背景差分を使ったキャラクターモーション切り抜き
Abstract
- ImageMagickとffmpegでのアニメーション切り抜きスクリプトの作成
- 使用条件が厳しいので使いみち少ないかも。
- 条件:切り抜き元動画の背景が静止画、かつ、その背景画像が入手できること(完全一致するもの)
Introduction
最近、動画編集をやってて2Dゲーム映像からキャラクターのモーション抜き出して使いたいなぁとか思ったので、
切り抜き方法を検討してみる。
現実の問題や3Dゲームと違って、2Dの奴なら照明による輝度変化とか画角の違いとかを気にしなくいいし、
完全一致する背景画像も入手しやすいので簡単にできるのではという算段。
今回は既存ソフト+ShellScriptで作成。
Method
概要
切り抜きたいアニメーション動画と背景画像から、フレーム毎に背景差分でマスク画像を生成・適用していくことで、最終的にブルーバックやグリーンバックの動画を作成する。途中でぼかし処理入れてるのは生成したマスクのエッジが綺麗に抽出できないときにそれっぽく見えるようにごまかすためです。
※BB動画じゃなくて、RGBAの動画にしてもいいけどかなり重くなるのでBBとかで良いかなと。
Fig.1 背景差分によるアニメーション切り抜きのブロック図
使用ソフト
- msys2
- windows環境でshellスクリプト実行用。ffmpegもImageMagickもpacmanで簡単に入れられるので。
- linux環境でやってもいいけど。
- ffmpeg
- 動画の分割・合成用
- ImageMagick
- compareコマンドでの背景差分に使っており今回の肝
- マスク処理とか各種の画像処理用
- (GNU Parallel)
- 直接関係ない。ImageMagickの画像処理を並列処理で高速化するために使用
- ImageMagickだけで何百枚も処理すると非常に遅いので。
- AG-デスクトップレコーダー
- 領域指定が便利なのでこれ使ってます
- 非圧縮で画面キャプチャできれば何でも良いですが
手順
Fig.1の処理の簡単な説明。詳細なコマンドとかは作ったスクリプトを置いておくのでそちらを参照。
- 切り抜きたいアニメーションのシーンを、キャプチャソフトの非圧縮フォーマットで録画する(自分はUtVideoのRGBA)※1※2
- 1と同様の手順で背景のみ表示しているシーンの動画を録画する
- ffmpegを使ってキャプチャしたアニメーション動画をPNGフォーマットのフレームに分割する
- 3と同様にffmpegで背景のみシーンの動画から背景画像を切り出す※3 [TIPS]参照
- 3.のオリジナルフレームと背景画像を比較し、完全一致ピクセルを透明に、それ以外のピクセルを白にする(差分画像を作成)
- 5.の差分画像にぼかし処理を入れてマスク画像を生成
- マスク画像のアルファ成分を、オリジナルフレームに移す(マスクする)
- 7の画像をBlueとかGreenの単色画像(クロマキー)の上に乗っける
- ffmpegで画像を連結してBB、GB動画を完成
※1 圧縮フォーマット(h264とか)で撮ると、動きのあるキャラクター周辺背景とか特にが毎フレーム微妙に画質が変わってしまい、マスク画像をうまく抽出できないため。
※2 なぜかRGBフォーマットだとうまく行かなかったので。
[TIPS] 画面キャプチャについて
シャニマスの解像度の場合は1136x640の特殊な解像度なので、ブラウザのDeveloperModeで表示解像度を1136x640に変えて録画しました。注意として、Windowsのディスプレイ設定でスケールを100%以外にしているとDeveloperModeの表示解像度を1136x640にしても実際に表示する解像度が変わっちゃうので注意。無駄にそこで詰まってしまった。
[TIPS] 背景画像について
シャニマスとかならブラウザのDeveloperModeでResource見れば背景画像のjpegとか簡単に取得できますが、それ使ってもうまく差分が取れなかったです。Canvasとして表示した段階か録画する段階で微妙に画質変化するのかも。なので、対象のアニメーション動画からフレーム切り出すのと同じ手順で背景画像を生成しています。
Result
実行環境
- CPU
- Ryzen 5 1600
- GPU
- GTX1080
- Memory
- 32GB
出力結果
今回は入力動画にアイドルマスターシャイニーカラーズのモーションを使用
- 1つ目はホーム画面の立ち絵のキャラモーション。
- 2つ目はアイドルロードのSDキャラモーション
※容量削減のために下の参考動画はもh264 yuv420pで圧縮しています
| 入力動画 | 背景画像 | 出力動画 |
|---|---|---|
|
| 入力動画 | 背景画像 | 出力動画 |
|---|---|---|
|
Discussion
今回はImageMagickのcompareコマンドによる差分でマスク画像を生成しているため、動画側で少しでも背景画像と異なるピクセルがあれば反応してしまう。そのため、2つ目の動画ではキャラクター以外のエフェクトなども切り抜いてしまい、綺麗に切り抜けていなかった。一方、1つ目の立ち絵モーションのようにエフェクトが一切無い動画であれば綺麗に切り抜くことが可能なであるため、そちら専用に使うのが良さそう。
シャニマスで言えばSDキャラには常にエフェクトがかかっている箇所が多く綺麗な抽出は難しいため、SDキャラのアニメーション映像が欲しい場合は、手間はかかるがSDキャラ画像からパーツを切り出して、AnimeEffectやMOHOなどでボーン入れて動かすべきか。。。
Appendix
シェルスクリプト配布
ffmpeg, ImageMagick, GNU parallel、shellscript使える環境なら何でも使えると思います。 Linuxならapt-getなりpacman使うなりで上記コマンドインストール、Windowsならmsys2使うなりして環境作っておけば大丈夫かと。
※本スクリプト使用に起因するいかなる事態の責任も負いかねます
※あと、自分用に作ったのでちゃんとしたエラー処理とかは書いてません
■使用例
sh make-chromakey-movie.sh source.avi background.png out.avi
- 引数の意味
- source.avi
- アニメーションを切り抜き元のソース動画名
- background.png
- 背景画像名
- out.avi
- 出力動画名
- source.avi
- その他のパラメータ
- ffmpegの出力パラメータ設定はスクリプト内で適宜変更
- 今回はBB動画にしていますが、スクリプト内で色指定(RGB HEX)を変えれば好きな色に変えられます
ソース動画と背景画像ファイルをスクリプトと同じディレクトリに入れて実行すれば処理が開始します 長い動画に対して実行するとめっちゃ時間かかっちゃうんで事前に切り抜きたい部分だけffmpegとかで抽出してから実行した方が良いです。(自分はだいたい10秒ぐらいの動画で使ってます)