ffmpeg のフィルタの中でおそらく最も使い方が難解なgeq(generic equation)
フィルタの使い方。YUV と RGB、A のそれぞれを設定により色を変えたり、回転・反転させたり、グラデーションや線、円や矩形も描ける。さらにマスクも作れるのでトランジションへの応用もできるが処理速度はかなり遅い。その書き方はすべて縦横の座標とその値を評価式で計算する。
目次
コマンド例
YUV、RGBどちらにも使える何も変化しないコマンド。ただし処理速度はかなり落ちる。
ffplay -i input -vf geq='p(X,Y):p(X,Y):p(X,Y)'
左右反転。hflip
フィルタと同じ。
ffplay -f lavfi -i testsrc2,geq='p(W-X,Y)'
2×2の分割表示。
ffplay -f lavfi -i testsrc2,geq='p(mod(2*X,W),mod(2*Y,H))'
上は負荷が大きいのでscale,split,vstack,split,hstack
フィルタを併用した方がよい。
ffplay -f lavfi -i testsrc2,scale=iw/2:-1:flags=neighbor,split,vstack,split,hstack
もしくはxstack
フィルタで一度に4マスを並べる。
ffplay -f lavfi -i "testsrc2,scale=iw/2:-1:flags=neighbor,split=4,xstack=4:0_0|w0_0|0_h0|w0_h0"
π/3に傾けて、100ピクセル幅のサイン波を表示する。
ffplay -f lavfi -i color,geq='128+100*sin(2*(PI/100)*(cos(PI/3)*(X-50*T)+sin(PI/3)*Y)):128:128'
エンボス効果。
ffplay -f lavfi -i testsrc2,geq='(p(X,Y)+(256-p(X-4,Y-4)))/2'
RGB映像を座標によってRGBの値を変える。
ffplay -f lavfi -i testsrc,geq=r='X/W*r(X,Y)':g='(1-X/W)*g(X,Y)':b='(H-Y)/H*b(X,Y)'
中央を明るく、四隅を次第に暗くするvignette
フィルタのような効果。
ffplay -f lavfi -i color,geq='255*gauss((X/W-0.5)*3)*gauss((Y/H-0.5)*3)/gauss(0)/gauss(0):128:128'
負荷を軽くするには
geq
フィルタは処理が重たいので映像に変化がないならtrim
フィルタで1フレームだけ取り出してloop
フィルタで繰り返した方がよい。
ffplay -f lavfi -i color,geq='st(0,between(X,W/3,2*W/3)*between(Y,H/3,2*H/3));ld(0)*255:128:128',trim=end_frame=1,loop=-1:1:0,setpts=N/FRAME_RATE/TB
trim フィルタの使い方
ループ回数を指定できる loop, aloop
公式ドキュメント:FFmpeg Filters Documentation : geq
オプション
数値を指定すれば全画面が指定した色になる。評価式を指定すれば座標毎に色を変えたり動かしたりできる。
- lum_expr, lum[string]
輝度(Y)の設定。YUV の値を変えるなら必須項目
既定値:未設定 - cb_expr, cb[string]
彩度(U)の設定
既定値:lumと同じ値 - cr_expr, cr[string]
彩度(V)の設定
既定値:lumと同じ値 - alpha_expr, a[string]
透過(A)の設定
既定値:元映像のまま - red_expr, r[string]
赤(R)の設定。RGB の値を変えるなら RGB のどれか1つが必須項目
既定値:元映像のまま - green_expr, g[string]
緑(G)の設定。RGB の値を変えるなら RGB のどれか1つが必須項目
既定値:元映像のまま - blue_expr, b[string]
青(B)の設定。RGB の値を変えるなら RGB のどれか1つが必須項目
既定値:元映像のまま
使える評価式
- N
0 から始まるフレーム番号 - X, Y
入力映像の横と縦の解像度で 0 からはじまりW, Hまでを返す - W, H
入力映像の横と縦の解像度。固定値 - SW, SH
ピクセルフォーマットに合わせた横と縦の解像度比。YUV 4:2:0 の輝度は 1, 1、彩度は 0.5, 0.5 になる - T
0 から始まるタイムスタンプ秒 - p(x, y)
入力映像の該当チャンネルの横と縦の値を指定し、その座標の値を返す - lum(x, y)
入力映像の輝度(Y)チャンネルの指定した横と縦の値を返す - cb(x, y)
入力映像の彩度(U)チャンネルの指定した横と縦の値を返す - cr(x, y)
入力映像の彩度(V)チャンネルの指定した横と縦の値を返す - r(x, y)
入力映像の赤チャンネルの指定した横と縦の値を返す - g(x, y)
入力映像の緑チャンネルの指定した横と縦の値を返す - b(x, y)
入力映像の青チャンネルの指定した横と縦の値を返す - alpha(x, y)
入力映像の透過チャンネルの指定した横と縦の値を返す
マスクにも使えるコマンドサンプル
0 と 255 だけにマスクするのなら YUV でも RGB でもよいが、グラデーションにする場合 YUV だと限定レンジを超えた値(Y だと15以下と236以上、UV だと 15以下と241以上)で RGB 変換するとその値がグラデーションにならないのに注意する。RGB に変換せずに グラデーションを使うには A(アルファチャンネル) をつかう。
矩形
横*縦で範囲を決めて最後に*255でYの値を指定している。矩形を狭くすれば縦や横のラインになる。
ffplay -f lavfi -i color,geq='(between(X,W/3,2*W/3)*between(Y,H/3,2*H/3))*255:128:128'
横のライン。
ffplay -f lavfi -i color,geq='(between(X,10,2*100)*between(Y,5,10))*255:128:128'
縦のライン。
ffplay -f lavfi -i color,geq='(between(X,5,10)*between(Y,10,2*100))*255:128:128'
加算すれば矩形を追加できる。
ffplay -f lavfi -i color,geq='(between(X,10,2*100)*between(Y,5,2*5)+between(X,200,2*150)*between(Y,50,55))*255:128:128'
矩形の4隅を丸める
矩形の丸めた4隅を透過させて背景をオーバーレイすることで丸めた4隅が残る。透過のピクセル値は0が完全に透過している。
ffmpeg -f lavfi -i color=darkblue:size=800x600 -f lavfi -i color=gray:size=600x450 -filter_complex "[1:v]format=yuva420p,geq=lum='p(X,Y)':a='if(gt(abs(W/2-X),W/2-20)*gt(abs(H/2-Y),H/2-20),if(lte(hypot(20-(W/2-abs(W/2-X)),20-(H/2-abs(H/2-Y))),20),255,0),255)'[rounded];[0:v][rounded]overlay=x=(W-w)/2:y=(H-h)/2" -frames:v 50 example.mp4
Give a video rounded transparent edges so that it can be overlayed on another video using FFMPEG – Stack Overflow
How to draw text on a rectangle with rounded corners using ffmpeg? – Stack Overflow
drawbox
drawbox
フィルタと同じことも出来る。矩形を書いてその中心を反対の色で埋める。
ffplay -f lavfi -i color,geq='(between(X,10,2*100)*between(Y,10,100))*255+(between(X,15,195)*between(Y,15,95)):128:128'
円
pow()の第一引数で横と縦の座標を決めlt()の第二引数で円の半径の2乗を指定する。80*80をpow(80,2)に変えてもよい。
ffplay -f lavfi -i color,geq='lte(pow(X-(W/2),2)+pow(Y-(H/2),2),80*80)*255':128:128
drawbox
フィルタと同様に中を抜いて線で円を描くことも出来る。
ffplay -f lavfi -i color,geq='st(0,pow(X-(W/2),2)+pow(Y-(H/2),2));lte(ld(0),80*80)*255+lte(ld(0),79*79)':128:128
破線
最初2つのbetween()で座標を指定し、3番目のbetween(mod())で何ピクセル毎に白黒を繰り返すか指定する。例では20ピクセル毎に1から10までは白、11から20までは黒になる。
横の破線。
ffplay -f lavfi -i color,geq='between(X,0,W)*between(Y,5,10)*between(mod(X,20),0,9)*255:128:128'
縦の破線。
ffplay -f lavfi -i color,geq='between(X,5,10)*between(Y,0,H)*between(mod(Y,20),0,9)*255:128:128'
グラデーション
右から左、上から下またはその逆や特定座標から左右上下にグラデーションする。
ffplay -f lavfi -i color,geq=r='ceil(255*X/W)':g='255-ceil(255*X/W)':b='255-ceil(255*Y/H)'
fillborders
フィルタでもグラデーションを作れる。
上下左右を特定色で埋める fillborders
RGBのスペクトラム。
ffmpeg -f lavfi -i color=black:s=1280x256,geq=r='clip(512-X,0,255)+clip(X-1024,0,255)':g='lt(X,512)*clip(X,0,255)+gte(X,512)*clip(1024-X,0,255)':b='lt(X,1024)*clip(X-512,0,255)+gte(X,1024)*clip(1536-X,0,255)',oscilloscope=tw=1:s=1 -vframes 1 rgb-spectrum.png
http://www.ffmpeg-archive.org/Problem-with-colorhold-filter-td4692661.html:FFmpeg-users – Problem with colorhold filterより。
左から右に黒から白。
ffplay -f lavfi -i color,geq='r=ceil(255*X/W):g=ceil(255*X/W):b=ceil(255*X/W)'
左から右に白から黒。
ffplay -f lavfi -i color,geq='r=255-ceil(255*X/W):g=255-ceil(255*X/W):b=255-ceil(255*X/W)'
上から下に黒から白。
ffplay -f lavfi -i color,geq='r=ceil(255*Y/H):g=ceil(255*Y/H):b=ceil(255*Y/H)'
上から下に白から黒。
ffplay -f lavfi -i color,geq='r=255-ceil(255*Y/H):g=255-ceil(255*Y/H):b=255-ceil(255*Y/H)'
200ピクセル右にずらし左右にグラデーション。
ffplay -f lavfi -i color,geq='r=clip(255-sqrt(pow(X-200,2)),0,255):g=clip(255-sqrt(pow(X-200,2)),0,255):b=clip(255-sqrt(pow(X-200,2)),0,255)'
100ピクセル下にずらし上下にグラデーション。
ffplay -f lavfi -i color,geq='r=clip(255-sqrt(pow(Y-100,2)),0,255):g=clip(255-sqrt(pow(Y-100,2)),0,255):b=clip(255-sqrt(pow(Y-100,2)),0,255)'
RGB に変換せず A を使ってもグラデーションになる
ffplay -f lavfi -i color,format=yuva420p,geq=128:a='clip(255-sqrt(pow(X,2)+pow(Y,2)),0,255)',alphaextract
輝度プレーンを左右0から255までのフルレンジにしたグラデーション。
ffplay -f lavfi -i color=s=1920x1080:r=24000/1001,geq=lum='lerp(1\,0\,ceil(255*X/W))*255':cb=128:cr=128,oscilloscope=s=1:tw=1,trim=end_frame=1,loop=-1:1:0,setpts=N/FRAME_RATE/TB
ffplay -f lavfi -i color=s=1920x1080:r=24000/1001,geq=lum='lerp(0\,1\,ceil(255*X/W))*255':cb=128:cr=128,oscilloscope=s=1:tw=1,trim=end_frame=1,loop=-1:1:0,setpts=N/FRAME_RATE/TB
円形グラデーション
中心が左上ffplay -f lavfi -i color,geq=r='clip(255-sqrt(pow(X,2)+pow(Y,2)),0,255)':g='clip(255-sqrt(pow(X,2)+pow(Y,2)),0,255)':b='clip(255-sqrt(pow(X,2)+pow(Y,2)),0,255)'
中心が左下。
ffplay -f lavfi -i color,geq='r=clip(255-sqrt(pow(X,2)+pow((Y-H),2)),0,255):g=clip(255-sqrt(pow(X,2)+pow((Y-H),2)),0,255):b=clip(255-sqrt(pow(X,2)+pow((Y-H),2)),0,255)'
中心が右上。
ffplay -f lavfi -i color,geq='r=clip(255-sqrt(pow((X-W),2)+pow(Y,2)),0,255):g=clip(255-sqrt(pow((X-W),2)+pow(Y,2)),0,255):b=clip(255-sqrt(pow((X-W),2)+pow(Y,2)),0,255)'
中心が右下。
ffplay -f lavfi -i color,geq='r=clip(255-sqrt(pow((X-W),2)+pow((Y-H),2)),0,255):g=clip(255-sqrt(pow((X-W),2)+pow((Y-H),2)),0,255):b=clip(255-sqrt(pow((X-W),2)+pow((Y-H),2)),0,255)'
sqrtの倍数を小さくするとグラデーションが広くなる
ffplay -f lavfi -i color,geq=r='clip(255-0.5*sqrt(pow(X,2)+pow(Y,2)),0,255)':g='clip(255-0.5*sqrt(pow(X,2)+pow(Y,2)),0,255)':b='clip(255-0.5*sqrt(pow(X,2)+pow(Y,2)),0,255)'
255/(W/2)*sqrtで左右の端が0になる。
ffplay -f lavfi -i color,geq='r=st(0,pow(X-(W/2),2)+pow(Y-(H/2),2));st(1,clip(255-255/(W/2)*sqrt(ld(0)),0,255));lte(ld(0),pow(W/2,2))*ld(1):g=st(0,pow(X-(W/2),2)+pow(Y-(H/2),2));st(1,clip(255-255/(W/2)*sqrt(ld(0)),0,255));lte(ld(0),pow(W/2,2))*ld(1):b=st(0,pow(X-(W/2),2)+pow(Y-(H/2),2));st(1,clip(255-255/(W/2)*sqrt(ld(0)),0,255));lte(ld(0),pow(W/2,2))*ld(1)'
255/hypot(W/2,H/2)で四隅が0になる。
ffplay -f lavfi -i color,geq='r=st(0,pow(X-(W/2),2)+pow(Y-(H/2),2));st(1,clip(255-255/hypot(W/2,H/2)*sqrt(ld(0)),0,255));lte(ld(0),pow(hypot(W/2,H/2),2))*ld(1):g=st(0,pow(X-(W/2),2)+pow(Y-(H/2),2));st(1,clip(255-255/hypot(W/2,H/2)*sqrt(ld(0)),0,255));lte(ld(0),pow(hypot(W/2,H/2),2))*ld(1):b=st(0,pow(X-(W/2),2)+pow(Y-(H/2),2));st(1,clip(255-255/hypot(W/2,H/2)*sqrt(ld(0)),0,255));lte(ld(0),pow(hypot(W/2,H/2),2))*ld(1)'
円の半径を決めてグラデーション。lte(ld(0),pow())で円の半径を決める。sqrtの倍数と併用する。
ffplay -f lavfi -i color,geq='r=st(0,pow(X-(W/2),2)+pow(Y-(H/2),2));st(1,clip(255-1*sqrt(ld(0)),0,255));lte(ld(0),pow(100,2))*ld(1):g=st(0,pow(X-(W/2),2)+pow(Y-(H/2),2));st(1,clip(255-1*sqrt(ld(0)),0,255));lte(ld(0),pow(100,2))*ld(1):b=st(0,pow(X-(W/2),2)+pow(Y-(H/2),2));st(1,clip(255-1*sqrt(ld(0)),0,255));lte(ld(0),pow(100,2))*ld(1)'
幅の広いグラデーション
st()が分割数の指定。
左から黒から白へ。
ffplay -f lavfi -i color,geq=r='st(0,14);(255/(ld(0)-1))*trunc(X/(W/ld(0))):g=st(0,14);(255/(ld(0)-1))*trunc(X/(W/ld(0))):b=st(0,14);(255/(ld(0)-1))*trunc(X/(W/ld(0)))'
左から白から黒へ。
ffplay -f lavfi -i color,geq=r='st(0,14);255-(255/(ld(0)-1))*trunc(X/(W/ld(0))):g=st(0,14);255-(255/(ld(0)-1))*trunc(X/(W/ld(0))):b=st(0,14);255-(255/(ld(0)-1))*trunc(X/(W/ld(0)))'
上から黒から白へ。
ffplay -f lavfi -i color,geq=r='st(0,14);(255/(ld(0)-1))*trunc(Y/(H/ld(0))):g=st(0,14);(255/(ld(0)-1))*trunc(Y/(H/ld(0))):b=st(0,14);(255/(ld(0)-1))*trunc(Y/(H/ld(0)))'
上から白から黒へ。
ffplay -f lavfi -i color,geq=r='st(0,14);255-(255/(ld(0)-1))*trunc(Y/(H/ld(0))):g=st(0,14);255-(255/(ld(0)-1))*trunc(Y/(H/ld(0))):b=st(0,14);255-(255/(ld(0)-1))*trunc(Y/(H/ld(0)))'
そのほか
twitter より
ffmpeg -f lavfi -i "nullsrc=32x24,geq=b='asin(sin( (N+(X+Y)*50)/20 ))/PI*255+127.5',scale=w=iw*20:h=ih*20:flags=neighbor" -pix_fmt yuv420p -vframes 126 output.mp4
ffmpegで簡単な映像制作 – Qiita(https://qiita.com/yukari120/items/f4c302f01f44a7aec1fe)より
ffplay -f lavfi -i color -vf "format=rgb24,scale=600:400,split[a][b];[a]geq=r='if( lt(mod(X+24+if(lt(mod(N/2,80),40),mod(N/2,80)),40),24) * lt(mod(Y+24+if(gt(mod(N/2,80),40),mod(N/2,80)),40),24),255)':g=0:b=0[c];[b]geq=200:30:230:'if( lt(mod(Y+N/2,40),16) * lt(mod(X+N/2,40),16),255)'[d];[c][d]overlay"