【Python】moviepy(1.0.3)の動画のクロップサイズ指定の不具合(たぶん)
【状況】動画の(x1, y1)-(x2, y2)の領域を切り抜いて別動画にしてくれるはずが,サイズがわずかに小さく切り取られて動画にエンコードしても再生できない.
【対処】x2, y2に1ずつ加えて切り抜き関数を呼び出す(という嫌なやり方で対応できたけど・・・ライブラリ変えますw)
切り抜いた動画が再生できない!
縦横16の倍数にしてmp4エンコードしたはずなのに,できたファイルが再生できない.ファイルの「プロパティ」→「詳細」でフレームサイズを確認すると,なぜか縦横2ずつ小さい.別の個所の切り抜きでも同じなので,デバッガで止めてcropの戻り値を確認.
入力座標は,(0, 239)-(559, 558)で,幅と高さは,width=560, height=320(両方とも16の倍数)となりますが,切り抜き関数から得られたデータのフレームサイズを見ると,
size: (559, 319)
1ずつ小さい!せっかく16の倍数になるように計算したのに,16の倍数から必ず外れてしまいますね.
検証する
縦横ともに1ずつ足りないという規則性があったので,原因は推測できます.
座標値(x1, y1)(x2, y2)から幅width, 高さheightを計算するときに,以下のように表します.
width = x2 - x1 + 1
height = y2 - y1 + 1
具体的な値を入れると分かりやすいけど,(0, 0)-(9, 9)で幅と高さが10になるはずですが,座標値で引き算するだけでは1足りないんですよね.つまり,ライブラリの実装で+1が抜けているんでしょ,これ.
ちなみに,動画ファイルのプロパティを見ると,フレーム幅558, フレーム高318になっていてさらに意味不明な結果でした・・・.
【変更前】
clip = video.fx(crop, x1=x1, y1=y1, x2=x2, y2=y2)
【変更後】
clip = video.fx(crop, x1=x1, y1=y1, x2=x2+1, y2=y2+1)
再度実行して,デバッガでフレームサイズを確認.
size: (560, 320)
フレームサイズは意図通り.ファイルのプロパティを見たらフレーム幅560, フレーム高320,と正しく,動画の再生も問題なし.
画像の中心,幅と高さを指定する方法も怪しい
画像の中心,幅と高さを与える方法もあります.
切り抜き領域が(0, 239)-(559, 558)のとき,以下のように計算すると,
width = 560, height = 320, x_center = 279, y_center = 398
となります.
width = x2 - x1 + 1
height = y2 - y1 + 1
x_center = (x1 + x2) // 2
y_center = (y1 + y2) // 2
clip = video.fx(crop, x_center = x_center, y_center = y_center, width = width, height = height)
横方向について,0~279の280ピクセルあるので一見良さそうに見えますが,幅方向のフレームサイズが0となってしまい,動画が生成されません(エラー表示などがないので,気づきにくかった).
これは,ライブラリ関数内部において行われているであろう,フレーム内に領域が収まっているかどうかの左端の判定が,
x_center - width / 2 >= 0
のようになっていることが推測されます.
試しに1ピクセル分横にずらし,(1, 239)-(560, 558),同様に計算すると,
width = 560, height = 320, x_center = 280, y_center = 398
となります.このときは画像が生成されましたので,推測が当たっているようです.であれば,中心位置の調整によって対応が可能になります.
ここでは,中心の計算の際に1を加算します.
x_center = (x1 + x2 + 1) // 2
y_center = (y1 + y2 + 1) // 2
結果,x_center = 280となります.この値を与えて同じ処理をしたところ,幅方向のフレームサイズが560となり,意図通りの動画ができあがりました.1ピクセルずつ減らして確認したので,左端については十分な対応ができています.
右端について,少しずつ値を変えて実験したところ,フレームの幅frame_widthを用いると,以下のような判定をしていることが予想されます.
x_center + width / 2 <= frame_width
ただし,左端とは異なり,右端からはみ出た部分は自動的にカットしているようです.左端のようにファイルが出力されない,ということはありませんでした.すっきりしたけど,すっきりしないw
結局どちらを使うか
以前は使っていて問題点に気づかなかったのですが,たまたま特殊なケースで大当たりしたようです.とはいえ,回避するためにつじつま合わせするのは・・・.
と,ここまで書いていて気づいてしまった.トリミングしたいだけならffmpeg使えばいいんじゃ?(ffmpegはパスの設定なども必要で面倒なので,インストールだけで楽なmoviepy使ってたんだけどね)
この記事が気に入ったらサポートをしてみませんか?