FFMpegで動画フレームを抽出したかったです。
▼ より具体的に書くならこういうこと
- 動画の一定時間の範内だったり、
- 動画のフレーム番号の範囲内だったり、
- その間のフレーム画像を全保存したい
そういった処理はFFmpegでやる方法について
ffmpegでは2つほどやり方があるので、
範囲内のフレーム抽出するコマンド例を紹介します。
方法1.時間範囲を指定してフレーム抽出
初めは時間指定でフレーム抽出する方法
ffmpegではミリ秒単位まで時間指定ができます。
抽象的なコマンド構文は以下の通りです。
▼ 時間指定フレームを抽出するコマンド構文
1 |
ffmpeg -ss [START_TIME] -to [END_TIME] -i input.mp4 %03d.png |
このコマンドでは [START_TIME] から [END_TIME] までの時間範囲で入力動画(input.mp4)を読み込みしてます。時間表現は 00:12:34.567 みたいにミリ秒単位で可能
そしてffmpegが各フレーム画像を 001.png , 002.png, 003.png みたいに連番で保存していってくれます。
以下はより具体的なコマンド例…
- コマンド例1
1ffmpeg -ss 15:10.625 -to 19:24.194 -i input.mp4 %03d.png
入力動画の 00:15:10.625 ~ 00.19:24.19 までの全てのフレームをカレントディレクトリに連番((001.png, 002.png, 003.png ...)でpng画像保存される - コマンド例2
1ffmpeg -ss 01:57:24.172 -to 02.01:83.842 -i input.mp4 path/to/%05d.png
入力動画の 01:57:24.172 ~ 02.01:83.842 までの全てのフレームをpath/toディレクトリ以下に連番(00001.png, 00002.png, 00003.png ...)で画像保存する
時間指定は人間的には分かりやすいです。
手入力でコマンド実行する時はこっちを使うかも
方法2.フレーム番号の範囲指定でフレーム抽出
お次はフレーム番号によるフレーム抽出です。
例えば 200フレーム目から500フレーム目までとか。
そういう時に使えるのが以下コマンドになります。
▼ フレーム番号指定で抽出するコマンド構文
1 |
ffmpeg -i input.mp4 -vf select='between(n\,[START_FRAME_IDX]\,[END_FRAME_IDX])' -vsync 0 %03d.png |
このコマンドでは [START_FRAME_IDX] から [END_FRAME_IDX] までのフレーム番号の範囲内で入力動画(input.mp4)のフレーム抽出してます。ただし番号が 0 から始まるインデックス
実行するとffmpegがそのフレーム番号内のフレームを連番で保存していきます。001.png, 002.png , 003.png みたいな感じで
これも以下に具体的なコマンド例を示します。
- コマンド例その1
1ffmpeg -i input.mp4 -vf select='between(n\,2735\,3218)' -vsync 0 %03d.png
入力動画の2735~3218フレーム目までが3桁0埋めの連番画像(001.png , 002.png , 003.png...)で保存される - コマンド例その2
1ffmpeg -i input.mp4 -vf select='between(n\,12345\,67890)' -vsync 0 path/to/frame_%05d.png
入力動画の12345~67890フレーム目までが5桁0埋めの接頭辞付き連番画像(frame_00001.png , frame_00002.png , frame_00003.png...)で保存される
これはffmpegをAPI経由で実行する時に便利です。
後者の方法はFFmpegをコード実行する時に便利!
後者のフレーム番号で抽出する方法について
ffmpegをコード的に実行する時に便利です。
例えばAndroidではffmpegライブラリがあります。
ffmepgコマンドを実行できるAPI
こういったライブラリではコード的にffmpegコマンドを実行するため、フレーム番号指定がとても便利なことがあります。逆に手入力でコマンド実行するなら、前者の 12:34:56.789 みたいな時間指定が直観的で分かりやすいですね。
使い分ければいいと思う
動画時間とフレーム番号の相互変換について
それから最後に豆知識
動画のフレームを抽出する時、
- 再生ミリ秒時間 ⇒ フレーム番号
- フレーム番号 ⇒ 再生ミリ秒時間
みたいに相互変換することも可能です。
それぞれ具体的に次の変換式です。
▼ 再生時間 ⇒ フレーム番号 に変換する式
1 |
FRAME_IDX = TIME_MILLIS / (1000 / FPS) |
※ ただし FPS = Frames Per Seconds
まず (1000 / FPS) によって1フレーム当たりの経過ミリ秒を計算し、それとミリ秒換算の再生時間(TIME_MILLIS)を割ってるだけです
▼ フレーム番号 ⇒ 再生時間 に変換する式
1 |
TIME_MILLIS = (1000 / FPS) * FRAME_IDX |
1つ前の式をいじくって変形しただけです。