顔交換で髪が変わらないのは性能ではなくマスクの範囲のせい — 複数のモデルがリレーするパイプライン
FaceFusionを分解してみたら — 髪は最初から対象外で、ちらつきは「別人」判定だった
FaceFusionで動画の顔を自分の顔に替えたら、髪は元の俳優の坊主頭のままだった。最初はモデルの性能のせいだと思った。もっといい交換モデルにすれば髪もついてくるだろう、と。
違った。パイプラインを分解すると、髪は最初から替える対象に入っていなかった。この記事を読めば、顔交換の結果の限界(髪、ちらつき、揺れ)を「どの段階がどこまでしか見ていないか」で説明できるようになる。
試すのは本人の顔か同意をもらった顔だけにし、公開するときはAIで変えた映像だと明記する。
ひとつのモデルではなくリレー
顔交換は、複数のモデルがバトンを渡していくパイプラインだ。ffmpegでフレームに分けたあと、今回(hyperswap_1a_256)実際に動いた順番はこうなる。
| 段階 | モデル | やること |
|---|---|---|
| 検出 | yoloface_8n |
顔の枠+目・鼻・口角の5点 |
| ランドマーク | 2dfan4 |
顔の点68個 |
| 位置合わせ | (モデルなし) | 点を基準に正面の規格サイズへ切り抜いて整える |
| 身元抽出 | arcface_w600k_r50 |
顔→512次元ベクトル。同じ人ならベクトルが近い |
| 交換 | hyperswap_1a_256 |
切り抜き+身元ベクトル→表情・角度はそのまま身元だけ替えた256pxの顔 |
| マスク | xseg_1、bisenet_resnet_34 |
手やマイクなどの遮蔽物、肌・目・唇などの部位分け |
| 補正 | gfpgan_1.4 |
ぼやけた顔の復元。blend 80 = 80%混ぜる |
最後に元の位置へ戻して合成し、元の音声を付けて再エンコードする。
限界1 — 髪はそもそも対象外
交換モデルが描くのは、位置合わせした顔の切り抜きの内側だけだ。マスクも box occlusion なので顔の領域だけを切り抜いて貼る。髪・耳・頭の形・首は、どの段階も触らない。
だからモデルをいいものに替えても髪は変わらない。範囲の外だからだ。髪まで変えたいなら系統そのものを替える必要がある。人物をまるごと描き直す動画生成の側だ(4系統マップ)。
限界2 — ちらつきは「別人」判定
最初の結果では、1.2〜1.6秒と2.4〜2.8秒の区間で元の顔が一瞬戻るちらつきがあった。
デフォルトの reference モードは、フレームごとに検出した顔のArcFaceベクトルを基準の顔と比べる。距離が reference_face_distance(今回の設定は0.3)を超えると別人とみなし、そのフレームは交換を飛ばす。顔の向きや照明が変わるとベクトルが揺れる。
one モードはこの比較をしない。画面で一番大きい顔ひとつを毎フレーム必ず替える。検出スコアの基準を0.5→0.35に下げたのはその手前の段階、つまり顔をそもそも見つけられないフレームを減らすためだ。
FaceFusionが実行ごとに残す記録(.jobs/completed/*.json)にオプションが全部残っていたので、比較は楽だった。
| 時刻 | ソース | selector mode | detector score | 結果 |
|---|---|---|---|---|
| 12:48 | テスト用の顔 | reference |
0.5 | ちらつき |
| 12:54 | テスト用の顔 | one |
0.35 | 解消 |
| 13:11 | 自分の写真 | one |
0.35 | 成功 |
reference モードのまま距離の基準を0.6に上げてちらつきが減るかは、まだ試していない。それを見れば原因が確定する。今言えるのは「one にしたら消えた」までだ。
限界3 — フレームを1枚ずつ別々に見る
前後のフレームを参照しない。細かい揺れが残る構造上の理由だ。横顔や速い動きでは、交換より手前の検出・ランドマークの段階が先に崩れる。
症状を段階に当てはめる
髪がそのまま → マスクの範囲。モデルのせいではない。数フレームだけ元の顔 → 選択モードと距離の基準。顔の縁が揺れる → フレームを別々に処理する構造。症状を段階に当てはめれば、どこを触ればいいかがすぐ分かる。交換モデルを取っ替え引っ替えして運に任せるよりずっと早い。
動画の顔処理をサービスや制作フローに組み込もうとして詰まっているなら、negabaroに相談してほしい(お問い合わせ)。
キーコンセプト
検出→ランドマーク→位置合わせ→身元→交換→マスク→補正の複数モデルのリレー
交換モデルは顔の切り抜きの内側だけを描く — 髪は範囲外
ちらついたら、まず --face-selector-mode one と低めのdetector scoreを試す
症状を段階に当てはめる — モデルの差し替えはその後