🎞️

動画の類似フレームをすっ飛ばしながら画像を書き出そう

に公開

動画から画像を取り出したいこと、あると思います
でも愚直に取り出すと画像が30枚も60枚も出てくることになります そんなにいらない!
一定間隔で切り出す? 動きがないフレームがダブったりしてサイアク!

なので「視覚的によく似たフレームはスキップしながら画像を書き出すツール」ツールを作りました
ここに置いておきます

https://gist.github.com/pal4de/567944e979e7c4492262b9e2e1973e20

事前準備

あらかじめ以下をインストールしておいてください

pip3 install opencv-python scikit-image

使い方

今すぐに使えます

コマンド
curl -s https://gist.githubusercontent.com/pal4de/567944e979e7c4492262b9e2e1973e20/raw/96642042c1ff2e053c07713bbe0c2946f3f3a452/extract_unique_frames.py \
  | python3 - 
--help
usage: - [-h] [-t THRESHOLD] [-k] video_path output_dir

Extract unique frames from a video based on SSIM.

positional arguments:
  video_path            Path to the input video file or URL.
  output_dir            Directory to save the output frames.

options:
  -h, --help            show this help message and exit
  -t, --threshold THRESHOLD
                        SSIM threshold for similarity detection (default: 0.85).
                        Frames with SSIM >= threshold are considered similar.
  -k, --keep-similar    If set, similar frames are saved with '_similar' suffix
                        instead of being skipped.

実行すると、 video_path の動画のフレームが output_dir に吐き出されます

実行例

例として、ロケットを打ち上げてる動画 (Rocket Launch Free Public Domain Video(1080P HD)を借ります

動画の場所と出力先ディレクトリを指定して実行します
URLでの指定にも対応しています 気が利いてると思いませんか

--threshold で閾値を変更できます

閾値例 イメージ
0.00 ほぼ何も出力しない
0.75 少なめに出力
0.85 そこそこ出力 (デフォルト)
0.95 多めに出力
1.00 ほぼ全てのフレームを出力
実行例
$ curl -s https://gist.githubusercontent.com/pal4de/567944e979e7c4492262b9e2e1973e20/raw/96642042c1ff2e053c07713bbe0c2946f3f3a452/extract_unique_frames.py \
  | python3 - https://ia801408.us.archive.org/27/items/public-domain-archive/Rocket%20Launch%20_%20Free%20Public%20Domain%20Video%281080P_HD%29.mp4 rocket_frames
Loading video from URL: https://media.xiph.org/video/derf/y4m/bowing_cif.y4m
Processing frame 1...
  Saving the first frame.
  Saved frame 1 as frame_00001.png
Processing frame 2...
  SSIM with previous frame: 1.0000
  Skipping frame 2 due to similarity.
...
Processing frame 891...
  SSIM with previous frame: 0.9890
  Skipping frame 891 due to similarity.
Processing frame 892...
  SSIM with previous frame: 0.9838
  Skipping frame 892 due to similarity.

Processing finished.
Total frames processed: 892
Total frames saved: 14
Total similar frames skipped: 878

概ねシーンごとに画像が一枚切り出されています 画面の一部分だけがゆっくり変化すると類似フレームと判定されるみたいです
892フレームが14フレームに減ったのは、いいですね

類似度指標 SSIM について

正直マルチメディア分野にはあまり明るくないのでこの辺りのはChatGPTに選定を委ねました

SSIMは次の流れで評価する指標のようです

  1. 画像を小領域に分けて、輝度・コントラスト・構造の3点で 似てる度 を測る。
  2. 各領域のスコアを平均して全体のSSIMを出す。

SSIMにも得意不得意があるみたいです
下の表ももらったので、出力に納得がいかない場合はお手元のコーディングアシスタントAIにこれを使って再実装するように頼んでみてください

シチュエーション 推奨される指標
GAN生成画像などの主観評価と一致しない LPIPS, DISTS, FID
圧縮・ぼかしに強いが微細な違いを見逃したくない FSIM, FSIMc, VIF
処理が重すぎる(特にバッチ処理) MSE, PSNR(ざっくり比較用)
ズレ・回転・幾何変形がある CW-SSIM, LPIPS, 手動アライメント + SSIM
色情報(色ずれ)が気になる FSIMc, Lab空間 + SSIM, 色差(CIEDE2000)
評価時間を秒単位まで削減したい PSNR, 簡易勾配ベースの類似度
非自然画像・特殊用途(工業・UI等) タスクベースのメトリクス(例:OCR精度、線の検出率)

終わりに

全然本筋の話じゃないんですけどGistでスクリプト配って即時実行するの面白いです
これ流行んないかな

株式会社TechSword

Discussion