MMD 主体認識カラーグレーディング(人物強調)
0. 結論
- MMD ステージ動画で「人物を強調」するには、2つの方法:
- ライトゾーンシェーピング(推奨、クリーン):人物を中心としたソフトな楕円/放射状グラデーション——楕円内の人物を明るく/暖かく/シャープ/輝かせ、楕円外の背景を暗く/冷たく/彩度低下/微かにぼかす;エッジのトランジションは非常に広く、ほとんど円が見えない。
- ハードキーイング分離(上限は高いが汚れやすい):フレーム差背景板から人物マスクを取得し、人物/背景を別々にグレーディングして合成。難点は人物の影(キャストシャドウ)が人物と一緒に動き、繋がってしまうこと → マスクに大きな影が含まれる → 明るい斑点が発生;強引に縮小すると羽や翼などが削られる。
- 最終成果物の場合は1を選択;Blender/MMD からアルファ付きのキャラクターレイヤーを再レンダリングできる場合は2を選択(最高品質)。
1. 素材とツール
| アイテム | パス |
|---|---|
| ソース動画 | D:\mmd.mp4\0002-4956.mkv(フル 165.166s)/ 字幕\0001-4956 - コピー.mkv(約137sにカット) |
| グレーディングスクリプト | 字幕\build\grade_ffmpeg.py(ライトゾーン/ソフトライト)、grade_final5s.py(5s 最終パラメータ)、color_grade.py(旧版フレーム差キーイング)、gothic_art.py(静的フレームゴシック調色) |
| 検証スクリプト | avoid_layout.py(占有率分析)、avoid_side2.py(占有率+bbox) |
| ffmpeg | C:\Users\35530\AppData\Local\Microsoft\WinGet\Packages\Gyan.FFmpeg_Microsoft.Winget.Source_8wekyb3d8bbwe\ffmpeg-9.0-full_build\bin\ffmpeg.exe |
| Python | C:\Users\35530\.dsh\dsh-runtimes\dsh-primary-runtime\dependencies\python\python.exe(PIL/numpy、cv2/深層学習なし) |
2. ルート A:ライトゾーンシェーピング(本プロジェクトのデフォルト)
2.1 ソフトマスクの生成(1回限りの PNG)
import numpy as np
from PIL import Image
W,H = 2560,1080
yy,xx = np.mgrid[0:H,0:W].astype(np.float32)
cx,cy = 0.515,0.565 # 人物中心(2560x1080 縦構図はおおよそこの位置;別の動画の場合はフレームを確認して調整)
rx,ry = 0.245,0.47 # 半幅/半高(比率);小さすぎると円が見え、大きすぎると分離効果が弱まる
q = ((xx-W*cx)/(W*rx))**2 + ((yy-H*cy)/(H*ry))**2
mask = np.clip(1.0-q,0,1)**0.55 # 0.5–0.7 がソフトめ
Image.fromarray((mask*255).astype(np.uint8)).save("_mask_final.png")
参考成品:字幕\出力\調色テスト\_mask_final.png、字幕\出力\字幕サンプル\_mask_final.png。
2.2 ffmpeg 合成(人物浮き上がらせ + 背景暗く)
考え方:人物用グレーディング版 + 背景用グレーディング版、マスクでアルファ合成:
[0:v]split=2[sv][bv];
[sv]eq=brightness=0.050:contrast=1.06:saturation=1.15,
colorbalance=rs=0.02:bs=-0.02:rm=0.05:bm=-0.06:rh=0.02:bh=-0.02,
split=2[sm][sh];[sh]gblur=sigma=14[blur];
[sm][blur]blend=all_mode=screen:all_opacity=0.34[sub];
[sub]format=yuva420p[suba];
[1:v]format=gray[gm];[suba][gm]alphamerge[subj];
[bv]eq=brightness=-0.045:contrast=1.07:saturation=0.87,
colorbalance=rm=-0.03:bm=0.05,gblur=sigma=0.6[bg];
[bg][subj]overlay=0:0,format=yuv420p[v]
コマンド:
& $ff -v error -y -ss 36.5 -t 30 -i src.mkv -loop 1 -i _mask_final.png `
-filter_complex "<上記 graph>" -map "[v]" -t 30 `
-c:v libx264 -preset medium -crf 16 -pix_fmt yuv420p OUT.mp4
注意:
-loop 1 -i mask.pngの場合マスクは静止ストリーム;overlay終了後は-tで長さを制限すること。 パラメータの意味:bg brightness 負=暗くする、saturation<1=彩度低下、bm>0=背景を青み(寒色)に、gblur=微かにぼかし;subj 側では brightness/彩度/暖色/blend screenで輝きを追加。
2.3 実測パラメータセット(2560×1080、紫ステージ MMD)
| 設定 | bg brightness | bg sat | subj gain | subj sat | bloom | vignette | 効果 |
|---|---|---|---|---|---|---|---|
| A 自然 | −0.035 | 0.82 | +0.030 | 1.08 | 0.20 | 0.30 | 軽く人物を引き立て、雰囲気はほとんど変えず |
| B 強化 | −0.075 | 0.70 | +0.055 | 1.16 | 0.34 | 0.42 | 明確な分離、ライトゾーンのエッジがわずかに見える |
| 最終方向 | −0.085 | 0.68 | +0.050 | 1.15 | 0.30 | 0.38 | ソフトライトが非常に広く、全編のベースとして推奨 |
5s でパラメータを試し、満足したらそのまま 30s/全編に適用(ffmpeg で一括処理の方がフレームごとの Python より速い)。
3. ルート B:ハードキーイング(よりクリーンなマスクが必要な場合)
3.1 背景板
- 全編から 1/2s ごとにフレームをサンプリング、1280×540 に縮小、ピクセルごとに中央値 = 背景板
bg_half.npy。 - コマンド/レビュー:
字幕\build\color_grade.pyのbuild_background()。 - 既知の問題:人物が中央に長時間立っている場合、中央値が人物に「汚染」される(人物の一部のピクセルが頻繁に出現する) → フレーム差が胴体部分で小さくなる → マスクに穴。
fill_holesまたは bbox で対策。
3.2 フレーム差マスク(1/4 解像度が最速)
m = |frame_q - bg_q|.max(axis=2) > 38
m = MaxFilter(5)(外側に拡大)→ largest connected component → 必要に応じて穴埋め/ブラー
- 占有率分析/回避(avoid-subtitles 参照)に使用;グレーディングに使用する場合は「人物類似度」制約を追加しないと、影/光斑が混入する。
3.3 既知の失敗パターン(本プロジェクトで実測)
- 影の汚染:人物の影が動きに合わせて移動し、マスクが繋がる → グレーディング後に人物周辺に明るい斑点/色ブロックが出現。解決策:フレーム差を正確なマットとして使用しない;影ごと明るくする(不自然)か、ライトゾーンシェーピングに戻る。
- 中央値背景の汚染:人物が立ち止まっている部分でマスクに穴 → 胴体がグレーディングされず、斑模様になる。解決策:穴埋め/bbox の使用。
- 8bit 色帯:大幅な色調整後、空やグラデーションに色帯が発生 → 1–3 の粒状ノイズ追加(ffmpeg
noise=alls=6:allf=t+u)または 10bit/HEVC 出力。 - 字幕のコントラスト:ベースを暗くすると白文字がより明確になる;暗くしすぎると人物も暗くなるため、人物をさらに明るくするか bloom を追加する必要がある。
4. ゴシック/ネオン等のスタイライズドグレーディング(静的フレーム用)
- ゴシック赤黒(ユーザーに却下済み、アーカイブのみ):
字幕\build\gothic_art.pyのgothic_grade():明るさ 0.42–0.52 に暗く、彩度 0.30–0.42 に低下、中間調を紫/赤に、強めのビネット、霞。 - テーマカラーバージョン(ユーザーが最終的に希望したもの):白/骨白を基調 + ラベンダー紫/マゼンタピンクの輝き、背景を濃い紫黒に;
gothic_art.py内の調色定数(BLOOD/LAV/PINK/VIOLET)参照。 - ネオンバージョン:
neon_wide.py(ASS で直接ネオン描画、グレーディング不要)。 - クイックカラー適用:
eq+colorbalance+vignetteの3点セットで紫ステージを任意の色調に変更可能:- 冷たい青:
colorbalance=bs=0.10:bm=0.12:bm...(青にシフト)、彩度低下; - 暖かく燃えるような:
colorbalance=rs=0.10:rm=0.08、eq=saturation=1.1。
- 冷たい青:
5. 検証チェックリスト
- 3–5 フレーム抽出:人物の明るさと背景の分離が自然か、ライトゾーンのエッジに明らかな円がないか
- 近接/クローズアップ:顔が露出オーバーになっていないか、肌の色が偏っていないか
- 暗部が死滅/色帯(8bit)になっていないか
- 字幕と一緒に確認:白文字が十分に明確か
- 出力
ffprobeの長さ/フレームレートが正しい;10bit 出力は-pix_fmt yuv420p10le -c:v libx265を使用
6. リソース
- 5s 最終パラメータと比較:
字幕\出力\調色テスト\(A自然/B強化/最終方向 + 比較動画) - 30s ベース:
字幕\出力\S4S6_30s\_base_30s.mp4(軽く暗くしたのみ、フルグレーディングなし) - 以前試したが却下された方向:ゴシック(
字幕\出力\字幕設計\G1…G3)、FLARE 演出、ネオン(字幕\出力\字幕サンプル)——パラメータ参照用にアーカイブ。