動画に映り込んだ通行人の顔や、車のナンバープレート、玄関の表札などは、その部分だけにモザイクやぼかしをかけて隠せます。FFmpeg では、隠したい部分を crop で切り出して加工し、overlay で元の位置に重ねます。


モザイク処理の適用前後の比較。左が元の映像、右は男性の顔の部分だけが粗いモザイクになった状態

左が元の映像、右が顔の部分だけをモザイクにした出力です。crop で切り出す → 縮小 → flags=neighbor で拡大 → overlay で重ねる、の 4 段階で作っています。

素材: Tears of Steel (CC) Blender Foundation | mango.blender.org、CC BY 3.0。映画の1フレームを切り出し、フィルターで加工しています。

モザイクとぼかしの違い — どちらを選ぶか

モザイクとぼかしは、別の処理です。違いは次の表のとおりです。

手法 仕組み プライバシー強度 処理時間 見た目
モザイク(ピクセル化) scale で縮小→拡大、または pixelize 中(ブロックが大きいほど強い) 0.40 秒(scale)、0.36 秒(pixelize) カクカクしたブロック
boxblur 矩形カーネルの平均化 中(強度次第) 2.21 秒(boxblur=10) 均一なソフトフォーカス
gblur ガウシアン分布のぼかし 中(強度次第) 0.62 秒(gblur=sigma=20) 自然で滑らか
avgblur 単純な平均化 中 0.57 秒(avgblur=sizeX=10) やや粗い

処理時間は、1080p・300フレームの非圧縮映像の全体に各フィルタをかけ、-f null に出力して計った時間です(Core i9-14900KF / FFmpeg 8.1、各5回の中央値。フィルタなしは 0.34 秒、モザイクのブロックは 10 ピクセル)。この記事のように小さな領域だけを加工するなら、どれを使っても処理時間はほとんど変わりません。

どちらを使うかの目安は次のとおりです。

  • 顔・ナンバープレート・住所など、絶対に知られたくない情報:不透明な色で塗りつぶす(drawbox の t=fill)
  • 背景の人影や小物など、目立たなくできればよい情報:モザイクやぼかし(boxblur / gblur)

モザイクやぼかしには、元の色の情報が残ります。モザイクにした文字を読み取った例もあるので、読まれて困るものは塗りつぶしてください。

静止した1領域にモザイクをかける(ピクセル化)

画面の決まった位置にある顔やナンバーを、四角いブロックにします。

scale でダウンスケール→アップスケールする方法

ffmpeg -i input.mp4 -filter_complex "[0:v]crop=80:60:100:80,scale=10:8,scale=80:60:flags=neighbor[fg];[0:v][fg]overlay=100:80[out]" -map "[out]" output.mp4

処理の流れは次のとおりです。

  1. crop=80:60:100:80 — 元の映像から、座標(100,80)を左上にして幅80・高さ60の部分を切り出す
  2. scale=10:8 — 切り出した部分を 10×8 まで縮小する(ここで細かい情報が消える)
  3. scale=80:60:flags=neighbor — 最近傍補間で元の大きさに戻す(ブロックの境目がくっきりする)
  4. overlay=100:80 — 元の映像の同じ位置に重ねる

ブロックを大きくしたいときは、scale=5:4 のように縮小後のサイズをさらに小さくします。ブロックが大きいほど、元の情報を推測しにくくなります。

pixelize フィルタを使う方法(FFmpeg 5.1+)

ffmpeg -i input.mp4 -filter_complex "[0:v]crop=80:60:100:80,pixelize=w=10:h=10[fg];[0:v][fg]overlay=100:80[out]" -map "[out]" output.mp4

pixelize はモザイク専用のフィルタです。w と h で、ブロックの幅と高さをピクセル数で指定します。

静止した1領域に gblur でぼかしをかける

gblur(ガウスぼかし)は、やわらかく自然な仕上がりになります。配信用の動画に向いています。

crop + overlay サンドイッチパターン

ffmpeg -i input.mp4 -filter_complex "[0:v]crop=80:60:100:80,gblur=sigma=20[fg];[0:v][fg]overlay=100:80[out]" -map "[out]" output.mp4

この形(サンドイッチパターン)を図にすると、次のとおりです。

        元映像 [0:v]
         │
         ├─────────────► そのまま下地に使う
         │
         └─► crop ─► gblur ─► [fg] ──┐
                                      ▼
                              overlay で同じ座標に重ねる
                                      │
                                      ▼
                                   [out] 出力

入力は1本のままで、[0:v] を2か所で使っています。split で分ける書き方もありますが、フィルタグラフの中で [0:v] を何度か参照するほうが簡単です。

boxblur を使う

ffmpeg -i input.mp4 -filter_complex "[0:v]crop=80:60:100:80,boxblur=10[fg];[0:v][fg]overlay=100:80[out]" -map "[out]" output.mp4

gblur の代わりに boxblur も使えます。ぼかしの強さの違いは、boxblurフィルタの記事を参照してください。

複数の領域を同時に隠す

何人もの顔や何台もの車を一度に隠すには、overlay をつなげていきます。

ffmpeg -i input.mp4 -filter_complex "[0:v]crop=60:50:40:40,boxblur=10[a];[0:v][a]overlay=40:40[v1];[0:v]crop=60:50:200:140,boxblur=10[b];[v1][b]overlay=200:140[out]" -map "[out]" output.mp4

処理の流れは次のとおりです。

  1. 領域A(左上)を crop → ぼかし → overlay で重ね、途中の結果を [v1] とする
  2. 領域B(右下)を crop → ぼかし → [v1] の上にさらに overlay で重ねる
  3. 最後の出力が [out]

領域は3個、4個と増やせます。[v1]→[v2]→[v3]→...→[out] のように、途中のラベルを増やしていきます。

時間で領域が動く場合の対処

人や車が画面の中で動くと、位置を固定した領域では追いかけられません。t(再生時刻、秒)を使った式で、位置を時間とともに動かします。

一定速度で水平移動する場合

ffmpeg -i input.mp4 -filter_complex "[0:v]crop=60:50:40+t*5:40,boxblur=10[fg];[0:v][fg]overlay=40+t*5:40[out]" -map "[out]" output.mp4

40+t*5 は「最初の X 座標が 40 で、毎秒 5 ピクセルずつ右へ動く」という意味です。crop と overlay には、必ず同じ式を書いてください。

キーフレーム的に位置を切り替える

5 秒の時点で位置が大きく変わる場合は、次のように書きます。

ffmpeg -i input.mp4 -filter_complex "[0:v]crop=60:50:if(lt(t\,5)\,40\,150):40,boxblur=10[fg];[0:v][fg]overlay=if(lt(t\,5)\,40\,150):40[out]" -map "[out]" output.mp4

if(lt(t,5),40,150) は「t が 5 未満なら 40、それ以外なら 150」という意味です。3つ以上の区間に分けるときは、if(lt(t,2),A,if(lt(t,5),B,C)) のように入れ子にします。フィルタの中では、, を \, と書いてエスケープしてください。

顔を自動で追跡してぼかすには

一般的な FFmpeg には、顔を見つける機能がありません。動く顔を自動で追いかけるには、次の手順が必要です。

  1. OpenCV・dlib・MediaPipe で顔を検出する — Python で各フレームの顔を囲む枠(バウンディングボックス)を求め、(time, x, y, w, h) を CSV に書き出す
  2. 検出結果を t を使った式に変える — 短い区間ごとに if(between(t,a,b),x1,...) を作る
  3. FFmpeg でぼかす — 上の「キーフレーム的に位置を切り替える」と同じ書き方にする

自動化するスクリプトの簡単な例です(擬似コード)。

# OpenCV で顔検出 → FFmpeg コマンド生成
import cv2
cap = cv2.VideoCapture("input.mp4")
detector = cv2.CascadeClassifier(cv2.data.haarcascades + "haarcascade_frontalface_default.xml")
boxes = []  # (time, x, y, w, h)
fps = cap.get(cv2.CAP_PROP_FPS)
i = 0
while True:
    ok, frame = cap.read()
    if not ok: break
    faces = detector.detectMultiScale(frame, 1.3, 5)
    if len(faces):
        x, y, w, h = faces[0]
        boxes.append((i/fps, x, y, w, h))
    i += 1
# boxes から FFmpeg の if() 式を生成して -filter_complex に渡す

仕事で使う品質が必要なら、見落としの少ないモデル(YOLOv8、MediaPipe Face Detection)を使ってください。

特定の時間範囲だけぼかす

「2秒目から5秒目だけぼかす」のように、決まった時間だけかけるときは enable を使います。

ffmpeg -i input.mp4 -filter_complex "[0:v]crop=60:50:40:40,boxblur=10[fg];[0:v][fg]overlay=x=40:y=40:enable='between(t,2,5)'[out]" -map "[out]" output.mp4
  • between(t,2,5) — 2秒〜5秒の間だけ overlay を有効にする
  • それ以外の時間は、元の映像がそのまま出る

区間を増やすときは、enable='between(t,2,5)+between(t,10,12)' のように +(または)でつなげます。

出力品質を保つコツ

ぼかした部分は色がなめらかに変わるので、エンコードの設定によってはバンディング(なめらかな部分に出る色の段差)が出ることがあります。

CRF を低めに設定する

ffmpeg -i input.mp4 -filter_complex "[0:v]crop=80:60:100:80,boxblur=10[fg];[0:v][fg]overlay=100:80[out]" -map "[out]" -c:v libx264 -crf 18 -pix_fmt yuv420p output.mp4

-crf 18 は、見た目ではほぼ劣化がわからない品質です(デフォルトは 23)。ぼかした部分をきれいに保つには、18〜20 にしておくと安心です。

-pix_fmt yuv420p を付ける

出力の指定に、次のオプションを必ず付けます。

-pix_fmt yuv420p

これで、多くの環境で再生できます。10bit の素材を -pix_fmt yuv420p10le のまま書き出すと、H.264 では High 10 というプロファイルになり、再生できない機器があります。

トラブルシューティング

-map の指定漏れでエラーになる

原因は、-map "[out]" の指定がないか、-map に書いたラベル名がフィルタグラフの中の名前と違うことです。

# 間違い
ffmpeg -i input.mp4 -filter_complex "[0:v]crop=80:60:100:80,boxblur=10[fg];[0:v][fg]overlay=100:80[result]" output.mp4

最後のラベル [result] を -map で指定していないので、Filter 'overlay:default' has output 0 (result) unconnected というエラーで止まり、動画は書き出されません。-map "[result]" のように、最後のラベルを -map で指定してください。-map のラベルのつづりが違うときは、Output with label 'out' does not exist で始まるエラーになります。

crop の領域が画面からはみ出す

crop=W:H:X:Y の W や H が入力の幅・高さより大きいと、“Invalid too big or non positive size” というエラーになります。X+W が入力の幅を超えるとき(Y+H と高さも同じ)はエラーにならず、crop は切り出す位置を画面の内側へずらします。overlay は元の位置に重ねるので、別の場所をぼかした画像がずれて貼られます。ffprobe -i input.mp4 で解像度を確かめてから、座標を決めてください。

処理が極端に遅い

  • 画面全体を boxblur でぼかすと、1つのスレッドで処理するので時間がかかります。gblur に替えると速くなります(sigma を大きくしても、処理時間はほとんど変わりません)。
  • 4K の動画では、crop する範囲も 4K の大きさに合わせて決めます(顔なら 200〜400 px くらい)。

色がわずかに変わる

8bit の yuv420p の素材なら、ぼかした部分以外の画素はフィルタで変わりません。10bit や 4:2:2 の素材では、overlay が標準で 8bit の yuv420p に変換します。元の形式のまま重ねるには、overlay=100:80:format=auto のように format=auto を付けます。

比較早見表 — どのフィルタを選ぶ?

フィルタ 強度の指定 処理時間 復元耐性 推奨用途
scale,scale (モザイク) 縮小サイズ 0.40 秒 中(ブロックが大きいほど強い) 顔・人影
pixelize w, h 0.36 秒 中(ブロックが大きいほど強い) 顔・人影
boxblur luma_radius:luma_power 2.21 秒 中 背景・小物
gblur sigma 0.62 秒 中 配信品質・自然な仕上がり
avgblur カーネルサイズ 0.57 秒 中 軽量バッチ

処理時間は、最初の表と同じ条件(1080p・300フレームの全体にかけた時間)です。

よくある質問

Q1. ぼかしが弱い/強くしたい

boxblur なら、boxblur=15:3 のように半径と繰り返し回数を上げます(80x60 の領域なら、半径は 15 までです)。gblur なら、gblur=sigma=30 のように sigma を大きくします。モザイクなら、縮小後のサイズを 5×4 のようにごく小さくすると、より強く隠せます。

Q2. モザイクで個人情報は完全に隠せる?

完全には隠せません。モザイクのブロックには元の色の情報が残り、モザイクにした文字を読み取った例もあります。ぼかしも同じです。住所や電話番号などの文字や、絶対に見分けられたくない顔は、drawbox=x=100:y=80:w=80:h=60:color=black:t=fill のように不透明な色で塗りつぶしてください。

Q3. 領域が動く対象(人物・車)を追跡したい

一般的な FFmpeg には、人や車を見つけて追いかける機能がありません。OpenCV・MediaPipe・YOLO で各フレームの座標を求め、上の「キーフレーム的に位置を切り替える」の式に入れる方法がよく使われます。Python で座標を求め、FFmpeg でぼかしをかける、という流れです。

Q4. unconnected のエラーで止まる

ほとんどは -map "[out]" の指定漏れです。-filter_complex の最後にラベル([out] など)を付けたら、同じラベルを -map で指定します。最後にラベルを付けなければ、-map なしでもその出力が使われます。

Q5. 1フレームだけぼかしたい

enable='between(n,30,30)' のように、n(フレーム番号)で指定します。秒で指定するなら enable='between(t,1.0,1.02)' です(30fps なら 1.0 秒のフレームだけが入ります)。

Q6. 処理した動画から元の領域を復元できる?

モザイクやぼかしをかけた動画を、元どおりに戻すことはできません。ただし、元の文字や顔を推測されることはあります。間違えて全体にぼかしをかけてしまった場合も、unsharp で少しくっきりさせることはできますが、元どおりにはなりません。元の動画は必ず残しておいてください。

関連記事