画像をドット絵風の低画質に変換するTwitter Bot「低画質」を作った – razokulover publogで話題になったのを ffmpeg のフィルタでドット絵風の低画質に変換する。

ffmpeg での出力例
けものフレンズプロジェクト|公式サイトよりサーバルちゃんを引用。リニューアルによりキャラクター紹介ページ消失。

けもフレ図鑑のサーバルちゃん、左がオリジナル、右が pixeliz0r 0.8倍の16色

アルゴリズムについては上のブログにあるように、

  1. 画像を1×1ピクセルより大きいサイズで分割する
  2. 分割した各領域の色の平均値を算出する
  3. 算出した色をkmeans法でクラスタリングし、色数を減らす
  4. 各分割した領域をクラスタリングされた色で塗りつぶす

これを ffmpeg のフィルタで行う、

  • scale, zscaleフィルタで解像度を8の倍数にしてモザイク化できない映像の解像度を丸める
  • frei0rフィルタのpixeliz0rで分割して平均化しモザイクのようにする
  • palettegenフィルタで減色する色を決める
  • paletteuseフィルタでpalettegenで決めた色に減色する
  • アルファチャンネルがあればlut2フィルタでアルファチャンネルをコピーする

ここで問題になるのが外部ライブラリに依存するfrei0rフィルタで、Windows環境ならfrei0rフィルタが使えるffmpegとfrei0rのライブラリを各自で作らなければならない。frei0rライブラリが使えないときはm-ab-s/media-autobuild_suiteを使い自分で用意するか、scaleフィルタなどでneighborフラグを立てて解像度を戻すとそれらしくなる。

使うフィルタの解説

コマンド例

使う色を決めるパレットを作るコマンドと、そのパレットを使って減色する2つのコマンドに分けられる。最初のコマンドは基本的には後述する色数の指定だけ変える。

画像の場合のコマンド例

ffmpeg -i input -vf scale="trunc(iw/8)*8:trunc(ih/8)*8:flags=neighbor,frei0r=pixeliz0r",palettegen=24:stats_mode=0 palettegen.png
ffmpeg -i input -i palettegen.png -filter_complex scale="trunc(iw/8)*8:trunc(ih/8)*8:flags=neighbor,frei0r=pixeliz0r",paletteuse=0 paletteuse.png

1行コマンド
ffmpeg -i input -lavfi scale="trunc(iw/8)*8:trunc(ih/8)*8:flags=neighbor,frei0r=pixeliz0r",split[a],palettegen=24:stats_mode=0[pal],[a][pal]paletteuse=0 output.gif

アルファチャンネルのある画像の場合のコマンド例

ffmpeg -i input -vf scale="trunc(iw/8)*8:trunc(ih/8)*8:flags=neighbor,frei0r=pixeliz0r",palettegen=24:stats_mode=0 palettegen.png
ffmpeg -i input -i palettegen.png -filter_complex scale="trunc(iw/8)*8:trunc(ih/8)*8:flags=neighbor,frei0r=pixeliz0r",split[a],paletteuse=0,[a]lut2=y:y:y:x paletteuse.png

1行コマンド
ffmpeg -i input -lavfi scale="trunc(iw/8)*8:trunc(ih/8)*8:flags=neighbor,frei0r=pixeliz0r",split=3[a][b],palettegen=24:stats_mode=0[pal],[a][pal]paletteuse=0,[b]lut2=y:y:y:x output.png

動画の場合のコマンド例

ffmpeg -i input -lavfi scale="trunc(iw/8)*8:trunc(ih/8)*8:flags=neighbor,frei0r=pixeliz0r",split[a],palettegen=24:stats_mode=single[pal],[a][pal]paletteuse=new=1 -an out.gif

動画のすべてのフレームをドット絵風にしない場合はあらかじめ時間指定してカットするか、-ss 入力時間 -i 入力ファイル -vf(filter_complex) フィルタ -t 出力時間を併用する。ここでは開始5秒から5秒間出力する。
ffmpeg -ss 5 -i input -lavfi scale="trunc(iw/8)*8:trunc(ih/8)*8:flags=neighbor,frei0r=pixeliz0r",split[a],palettegen=24:stats_mode=single[pal],[a][pal]paletteuse=new=1 -t 5 -an out.gif

詳細な設定方法

リサイズ

本映像に8の倍数に丸めるのなら上のコマンドのままでよいが、任意の横、または縦の解像度にしたい場合は設定を変える。ただし設定値の片方はあらかじめ8の倍数にすること。

横幅を 1280 にして縦幅を元映像のアスペクト比をなるべく維持しつつ8の倍数に。
"scale=1280:trunc((ih*ow/iw)/8)*8:flags=neighbor"

縦幅を 960 にして横幅を元映像のアスペクト比をなるべく維持しつつ8の倍数に。
"scale=trunc((iw*oh/ih)/8)*8:960:flags=neighbor"

ドットの荒さを変える

シンプルなアイコンならpixeliz0rの既定値、または少し上げてもよい。逆に複雑な場合は少し下げるとよい。既定値から上げるとモザイクが大きく、下げると小さくなる。
既定値(どちらも同じ):frei0r=pixeliz0r、”frei0r=pixeliz0r:0.0194444|0.0243056″

既定値からの倍率の目安

10 0.194444 0.243056
9 0.1749996 0.2187504
8 0.1555552 0.1944448
7 0.1361108 0.1701392
6 0.1166664 0.1458336
5 0.097222 0.121528
4 0.0777776 0.0972224
3 0.0583332 0.0729168
2 0.0388888 0.0486112
1 0.0194444 0.0243056
0.9 0.01749996 0.02187504
0.8 0.01555552 0.01944448
0.7 0.01361108 0.01701392
0.6 0.01166664 0.01458336
0.5 0.0097222 0.0121528

色の数を変える

palettegenフィルタの最初の引数、コマンド例では 24 の値を変える。

出力形式を変える

出力フォーマットは GIF、アニメGIF、PNG、アニメPNG、WEBM(VP9)、MP4(AVC)のどれでも使える。

GIF、アニメGIF

ffmpeg -i input -i palettegen.mkv -filter_complex scale="trunc(iw/8)*8:trunc(ih/8)*8:flags=neighbor,frei0r=pixeliz0r",paletteuse=0 -an paletteuse.gif

アニメPNG

ffmpeg -i input -i palettegen.mkv -filter_complex scale="trunc(iw/8)*8:trunc(ih/8)*8:flags=neighbor,frei0r=pixeliz0r",paletteuse=0 -an -f apng paletteuse.png

WEBM(VP9)

VP9(libvpx-vp9)のエンコード設定について
ffmpeg -i input -i palettegen.mkv -filter_complex scale="trunc(iw/8)*8:trunc(ih/8)*8:flags=neighbor,frei0r=pixeliz0r",paletteuse=0 -acodec opus -vcodec libvpx-vp9 -crf 30 -b:v 0 -qmin 20 -qmax 40 -pix_fmt yuv420p paletteuse.webm

MP4(AVC)

ffmpeg -i input -i palettegen.mkv -filter_complex scale="trunc(iw/8)*8:trunc(ih/8)*8:flags=neighbor,frei0r=pixeliz0r",paletteuse=0 -acodec copy -vcodec libx264 -pix_fmt yuv420p paletteuse.mp4

コメントを残す

メールアドレスが公開されることはありません。

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)