2入力した映像の YUVA や RGBA を比較して結果を表示するblend
の使い方。差分を調べて比較動画を作ったり、マスクした部分に別の映像を重ねたりいろいろな映像効果を作ることができる。
基本コマンド
比較動画として上に二つ並べて左下に差分(Y は 0 差分、UV は1入力)の動画を表示するコマンド例。
ffplay -f lavfi -i "movie=left.mp4,setpts=PTS-STARTPTS,split[a1][a2];movie=right.mp4,setpts=PTS-STARTPTS,split[b1][b2];[a1][b1]blend=c0_mode=difference,pad=2*iw:ih:0:0[blend];[a2][b2]hstack[tmp];[tmp][blend]vstack"
ffmpeg -i left.mp4 -i right.mp4 -filter_complex [0:v]setpts=PTS-STARTPTS,split[a1][a2];[1:v]setpts=PTS-STARTPTS,split[b1][b2];[a1][b1]blend=c0_mode=difference,pad=2*iw:ih:0:0[blend];[a2][b2]hstack[tmp];[tmp][blend]vstack -c:a copy output
比較動画として上に二つ並べて左下に差分(Y は 0 差分、UV は128)の動画を表示するコマンド例。
ffplay -f lavfi -i "movie=left.mp4,setpts=PTS-STARTPTS,split[a1][a2];movie=right.mp4,setpts=PTS-STARTPTS,split[b1][b2];[a1][b1]blend=c0_mode=difference,lutyuv=val:128:128,pad=2*iw:ih:0:0[blend];[a2][b2]hstack[tmp];[tmp][blend]vstack"
ffmpeg -i left.mp4 -i right.mp4 -filter_complex [0:v]setpts=PTS-STARTPTS,split[a1][a2];[1:v]setpts=PTS-STARTPTS,split[b1][b2];[a1][b1]blend=c0_mode=difference,lutyuv=val:128:128,pad=2*iw:ih:0:0[blend];[a2][b2]hstack[tmp];[tmp][blend]vstack -c:a copy output
さらに音声も再生するコマンド例(音声は left.mp4)。
ffplay -f lavfi -i "movie=left.mp4,setpts=PTS-STARTPTS,split[a1][a2];movie=right.mp4,setpts=PTS-STARTPTS,split[b1][b2];[a1][b1]blend=c0_mode=difference,lutyuv=val:128:128,pad=2*iw:ih:0:0[blend];[a2][b2]hstack[tmp];[tmp][blend]vstack[out0];amovie=left.mp4[out1]"
開始フレームが一致しない場合はsetpts
フィルタの前にtrim
フィルタを使う。以下は開始1フレームカットする例。
trim=start_frame=1
間違い探しを簡単に調べるコマンド(インターネット上の画像も入力できる)。
ffmpeg -i img1.jpg -i img2.jpg -filter_complex setsar=1/1[0a];[1]setsar=1/1,[0a]blend=c0_mode=grainextract,lutyuv=val:128:128 output.jpg
- モードの説明:ブレンドモード – Wikipedia
- 公式wiki(処理の画像あり):Blend – FFmpeg
- 公式ドキュメント:FFmpeg Filters Documentation : blend
オプション
オプションは1入力をトップレイヤーに2入力をボトムレイヤーとして2つの入力から1つの出力に変える。指定チャンネル以外は1入力を返す。framesyncの設定にも対応している。
外部記事での解説。
- https://www.slideshare.net/MiyakojiEnzen/ss-242677066:デジタル画像の色の方式と描画モード解説
- After Effects で描画モードとレイヤースタイルを使用する
- 加算とスクリーンを正しく使い分けて綺麗な光を描くヒント – コンポジゴク
YUV は(0,128,128)で黒、(128,128,128)で灰、(255,128,128)で白になり、(255,255,255)で明るい紫、(0,0,0)で濃い緑になる。RGB は GBR の順番でフィルタを扱う。
- c0_mode[int]:最初のチャンネル。一般的には G または Y
- c1_mode[int]:2番目のチャンネル。一般的には B または U
- c2_mode[int]:3番目のチャンネル。一般的には R または V
- c3_mode[int]:4番目のチャンネル。一般的には A
- all_mode[int]:全チャンネル
- normal。それぞれの詳細は下にまとめてある
- addition
- and
- average
- burn
- darken
- difference, difference128
- grainextract
- divide
- dodge
- exclusion
- hardlight
- lighten
- multiply
- negation
- or
- overlay
- phoenix
- pinlight
- reflect
- screen
- softlight
- subtract
- vividlight
- xor
- hardmix
- linearlight
- glow
- addition128, grainmerge
- multiply128
- heat
- freeze
- extremity
- softdifference
- geometric
- harmonic
- bleach
- stain
- interpolate
- hardoverlay
- モードの効果具合を調整できる。1 より小さくするとその割合だけモードの反映が小さくなる
- c0_opacity[double]
最初のチャンネル。一般的には G または Y
既定値:1
範囲:0 から 1 まで - c1_opacity[double]
2番目のチャンネル。一般的には B または U
既定値:1
範囲:0 から 1 まで - c2_opacity[double]
3番目のチャンネル。一般的には R または V
既定値:1
範囲:0 から 1 まで - c3_opacity[double]
4番目のチャンネル。一般的には A
既定値:1
範囲:0 から 1 まで - all_opacity[double]
全チャンネル
既定値:1
範囲:0 から 1 まで
- c0_opacity[double]
- expr で適応する時間を指定できる
- c0_expr[string]:最初のチャンネル。一般的には G または Y
- c1_expr[string]:2番目のチャンネル。一般的には B または U
- c2_expr[string]:3番目のチャンネル。一般的には R または V
- c3_expr[string]:4番目のチャンネル。一般的には A
- all_expr[string]:全チャンネル
- 指定できる計算書式
- N:現在のフレームナンバーを返す
- X, Y:入力した座標
- W, H:入力したチャンネルの座標
- SW, SH:入力したチャンネルの縦横の座標比率。yuv420p の luma だと 1、1。chroma だと 0.5、0.5
- T:タイムスタンプ秒を返す
- TOP, A:1入力の現在のチャンネルを返す
- BOTTOM, B:2入力の現在のチャンネルを返す
2入力の内で映像の時間が短い場合にそこで処理を止めるか
既定値:0
2入力の内で映像の時間が短い場合に最終フレームの表示を継続するか
既定値:1
exprの使用例(1秒から3秒にかけてクロスフェードをかける)。
ffmpeg -i video1.mp4 -i video2.mp4 -filter_complex "[0:v][1:v]blend=all_expr='A*(if(lte(T,1),1,if(gte(T,3),0,1-T/3)))+B*(if(lte(T,1),0,if(gte(T,3),1,T/3)))'" -t 6 fade.mp4
手軽に扱えるフェードフィルタがある:
映像のトランジションの設定ができる xfade
音声のフェードイン、フェードアウトの設定ができる afade
左上から右下へ斜めに分割して同時表示。
ffmpeg -i video1.mp4 -i video2.mp4 -filter_complex "[1:v][0:v]blend=all_expr='if(gt(X,Y*(W/H)),A,B)'" diagonal.mp4
shell – FFMPEG Crop with side by side merge – Stack Overflow
2秒かけて1番目から2番目のファイルに菱形が小さくなるトランジション。
ffmpeg -i video0000.mov -i video0001.mov -filter_complex "blend=all_expr='if(lte(abs(X-W/2)/W+(abs(Y-H/2)/H),(2-T)/3),A,B)'" -preset veryfast output.mp4
exprの使い方:ffmpeg で使える評価式
mode の詳細
multiply、screen、burn、dodgeは(a)、(x) がよく分からないので空欄になっている。8ビット映像を参照しているが高ビット深度も対応している。1入力を A、2入力を B とする。
オプション | int | 計算内容 | 説明 |
normal | 0 | A | Aの値 |
addition | 1 | FFMIN(255, A + B) | AとBの和と255を比べて小さい値 |
and | 2 | A & B | AとBの論理積 |
average | 3 | (A + B) / 2 | AとBの和を2で割る |
burn | 4 | BURN(A, B) | |
darken | 5 | FFMIN(A, B) | AとBを比べて小さい値 |
difference | 6 | FFABS(A – B) | AからBを引いた絶対値 |
difference128 | 7 | 128 + A – B | AからBを引いた値に128を足す |
grainextract | 7 | 128 + A – B | AからBを引いた値に128を足す |
divide | 8 | B == 0 ? 255 : 255 * A / B | Bが0だと255、そうでなければAをBで割って255を掛けた値 |
dodge | 9 | DODGE(A, B) | |
exclusion | 10 | A + B – (2 * A * B) / 255 | AとBの和から2倍のAとBの積に255を割った値を引く |
hardlight | 11 | B < 128 ? MULTIPLY(2, B, A) : SCREEN(2, B, A) | |
lighten | 12 | FFMAX(A, B) | AとBを比べて大きい値 |
multiply | 13 | MULTIPLY(1, A, B) | |
negation | 14 | 255 – FFABS(255 – A – B) | 255からAとBの和を引いた絶対値を255から引く |
or | 15 | A | B | AとBの論理和 |
overlay | 16 | A < 128 ? MULTIPLY(2, A, B) : SCREEN(2, A, B) | |
phoenix | 17 | FFMIN(A, B) – FFMAX(A, B) + 255 | AとBを比べて小さい値からAとBを比べて大きい値を引いて255を足す |
pinlight | 18 | B < 128 ? FFMIN(A, 2 * B) : FFMAX(A, 2 * (B – 128)) | Bが128よりも小さければAと2倍のBを比べて小さい値、そうでなければBから128を引いて2倍した値とAを比べて大きい値 |
reflect | 19 | B == 255 ? B : FFMIN(255, (A * A / (255 – B))) | Bが255ならばB、そうでなければAの2乗に255からBを引いた値を割った値と255を比べて小さい値 |
screen | 20 | SCREEN(1, A, B) | |
softlight | 21 | A > 127 ? B + (255 – B) * (A – 127.5) / 127.5 * (0.5 – fabs(B – 127.5) / 255): B – B * ((127.5 – A) / 127.5) * (0.5 – fabs(B – 127.5)/255) | |
subtract | 22 | FFMAX(0, A – B) | AからBを引いた値と0を比べて大きい値 |
vividlight | 23 | A < 128 ? BURN(2 * A, B) : DODGE(2 * (A – 128), B) | |
xor | 24 | A ^ B | AとBの排他的論理和 |
hardmix | 25 | A < (255 – B) ? 0: 255 | 255からBを引いた値がAと比べて大きければ0、そうでなければ255 |
linearlight | 26 | B < 128 ? B + 2 * A – 255 : B + 2 * (A – 128) | Bが128よりも小さければBと2倍のAの和から255を引いた値、そうでなければAから128を引いて2倍しBを足した値 |
glow | 27 | A == 255 ? A : FFMIN(255, (B * B / (255 – A))) | Aが255だとA、そうでなければBの2乗に255からAを引いた値で割った値と255を比べて小さい値 |
addition128 | 28 | A + B – 128 | AとBの和から255を引く |
grainmerge | 28 | A + B – 128 | AとBの和から255を引く |
multiply128 | 29 | A – 128 * B / 32. + 128 | |
heat | 30 | A == 0 ? 0 : 255 – FFMIN(((255 – B) * (255 – B)) / A, 255) | Aが0だと0、そうでなければ255からBを引いた値の2乗をAで割った値と255を比べて小さい値 |
freeze | 31 | B == 0 ? 0 : 255 – FFMIN(((255 – A) * (255 – A)) / B, 255) | Bが0だと0、そうでなければAを引いた値の2乗をBで割った値と255を比べて小さい値を255から引いた値 |
extremity | 32 | FFABS(255 – A – B) | 255からAとBの和を引いた絶対値 |