mcpField
V
video-color-grade

video-color-grade

github.com/whitetoweraiクリエイティブ・メディア1768 回インストール3 週間前に更新
リポジトリ

video-color-grade について

映像から複数のルックを作成・比較・選択し、LUTを生成して適用するカラーグレーディングスキルです。共通の補正と演出的な色付けを分け、肌色の確認を重視します。

主な機能

  1. 01映像を分析して基本補正を提案
  2. 02同じフレームに複数のルックを描画
  3. 03比較画像で肌色を確認
  4. 04ルックの選択と理由を記録
  5. 05ポータブルな`.cube` LUTを生成
  6. 06音声をコピーしてカラーを適用

活用シーン

  1. 01映像クリップの色調を比較
  2. 02肌色を確認しながらルックを選択
  3. 03LUTを出力してクリップ全体に適用

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/whitetowerai/cut-as-code --skill video-color-grade

インストール後、Claude Code で/video-color-gradeを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

looks.example.json
scripts/
apply_grade.py
assess.py
bake_lut.py
gradelib.py
make_clips.py
render_looks.py

詳細

ビデオのカラーグレーディング(評価 → 補正 → ルック作成 → 選択 → LUT 作成と適用)

コードでゼロからカラーグレーディングを作成し、実際の映像に複数の異なる名前付きルックを適用して生成します。明示的な人間の選択、または委任されたエージェントの判断によって1つを選び、持ち運び可能な .cube LUT に焼き込んで、クリップ全体に適用します。プリセットパックは使用しません。

基本的な考え方 — 補正してからスタイルを加える。 各ルックは 補正ベース + クリエイティブレイヤー です。

  • 補正ベースは映像を正直に見せます。フラットな LOG/HLG 映像の場合は log→Rec.709 変換、すでに Rec.709 の映像の場合は WB のニュートラル化+露出+控えめなコントラスト調整です。すべてのルックでこのベースを共有するため、「ニュートラル」は意味を保ち、ルックの違いは意図によって生まれます。
  • クリエイティブレイヤーは、その上に重ねるルックです(暖色/寒色/ティール&オレンジ/メリハリ/フェードなど)。

肌の色が品質の基準です。 人物が映っている場合、特に肌の色が濃い人では、teal_orange と cool_desat によって緑やグレーの色かぶりが生じがちです。すべてのルックでまず顔を確認してください。中間調の暖かみを保ち、色合いの調整はシャドウ/ハイライト/背景に加え、強い saturation より vibrance を優先します。ホワイトバランスを完全にニュートラルにすると肌の生気が失われるため、調整しすぎないでください。

要件:PATH 上に ffmpeg/ffprobe があること、Python に numpy と Pillow があること。

契約

  • 各ルックは ベース + クリエイティブレイヤー です。すべてのルックでベースを共有します。
  • すべてのルックを同じ代表フレームにフル解像度でレンダリングし、ラベルを付けます(公平で条件を統一した比較)。
  • クリップ全体への適用では -c:a copy を使います(音声は再エンコードされないため、A/V 同期は変わりません)。ソースの再生時間、fps、寸法を維持します。
  • 納品前にルックの選択を完了します。ユーザーが選択を求めた場合は human モードを使い、選択を委任された場合、または自律的な実行を求められた場合は、停止せずに agent モードを使います。どちらのモードでも、判断の根拠を永続的なプランに記録します。

プロジェクトプロトコルのワークフロー

永続的な判断を work/color-grade/grade-plan.json に保存します。

{
  "schema_version": 1,
  "target": "base-video",
  "base": "eq=contrast=1.05",
  "looks": [{"name": "clean", "chain": "null"}],
  "selected_look": "clean",
  "selection_mode": "agent",
  "selection_rationale": "Neutral correction preserves natural skin and source lighting.",
  "selected_lut": "../../final/selected-color-look.cube",
  "evidence_refs": ["media:source"]
}

コンテンツカードやキャプションの色を変更しないよう、デフォルトで base-video を使います。composite は、すでに合成されたピクセルを意図的にグレーディングする場合にのみ有効です。共有の work/understand/media.json と視覚的な根拠を読み込みます。review/02-color-grade/choose-color-look.jpg と review/02-color-grade/skin-tone-check.jpg を生成し、任意で短い selected-look-preview.mp4 も生成します。判断と根拠は review/02-color-grade/selected-look.md に記録します。

ユーザーが明示的に選択した場合は、selection_mode を human に設定します。ユーザーが判断を委任した場合、または中断のないワークフローを求めた場合は、agent に設定し、肌の色、ハイライトの保持、ニュートラルなバランスを優先して慎重に選択します。必ず空でない selection_rationale を記述します。agent モードでは処理を中断しないでください。

選択した LUT を final/selected-color-look.cube に焼き込みます。この LUT を納品する場合は、グレードプランの selected_lut を設定し、共有レンダラーがそのファイルを正確に読み込むようにします。焼き込まれたフルルック LUT には補正ベースがすでに含まれています。レンダラーは base + lut3d ではなく、lut3d のみを適用する必要があります。

based_on に操作の正確な入力リビジョンを記録し、プランまたは選択した入力が変更されたときは整数の revision を増やします。レビュー用ファイルがすべて完成してから操作チェックを pass に設定し、プロトコルの全フィールドを含めます。

{
"target": {"sequence": "main", "scope": "base-video"},
"effects": {
  "changes_timeline": false,
  "changes_geometry": false,
  "changes_video_pixels": true,
  "changes_audio": false,
  "adds_track": null
},
"check": {
  "status": "pass",
  "report": "../review/02-color-grade/selected-look.md"
},
"render": {
  "kind": "video-filter",
  "target": "base-video",
  "plan": "color-grade/grade-plan.json"
}
}

共有レンダラーは selected_look が存在することを検証し、タイムライン変換の後、オーバーレイの前にカラーグレーディングを適用して、最終動画を一度だけエンコードします。

python skills/video-understand/scripts/build_render_plan.py .
python skills/video-understand/scripts/render_project.py work/render/render-plan.json

スタンドアロン互換入力

  • ソース動画。
  • base と名前付きの looks を含む looks.json。looks.example.json を基にして、assess.py の報告内容に応じて**base を調整**します。

既存のすべてのスクリプトは、引き続き従来の looks.json を受け付けます。gradelib.load_spec() は標準形式の grade-plan.json も受け付けるため、移行中もコンタクトシート、クリップ、LUT、スタンドアロン適用の各コマンドを引き続き使用できます。

looks.json のスキーマ

{
  "base": "<corrective base: log->Rec.709 conversion, OR WB+exposure+contrast for normal footage>",
  "looks": [
    { "name": "clean_neutral", "label": "1 · CLEAN NEUTRAL", "desc": "corrected only", "chain": "eq=contrast=1.02" },
    { "name": "teal_orange",   "label": "4 · TEAL & ORANGE", "desc": "cinematic",      "chain": "colorbalance=...,eq=..." }
    // a look's full ffmpeg filter = base + "," + chain. Set "prepend_base": false to use chain standalone.
  ]
}

ワークフロー

  1. 評価する — 評価を見ずに採点しないでください。

    python scripts/assess.py SOURCE.mp4 --out work/
    

    log と Rec.709 の判定、ホワイトバランスの色かぶり(signalstats の U/V と 128 の比較)、露出(Y)をレポートし、代表フレーム(work/assess/frame.png)を選び、基本的な調整を提案します。これに応じて looks.json の base を再調整してください(例:暖色の色かぶり → 青を少し加える、log → log から 709 への変換を base に追加する)。

    • 代表フレームは顔ではなく、輝度の中央値で選ばれます。 ワンショットのトークヘッド映像では通常、良好な顔のフレームが選ばれますが、Bロールが多い映像や複数ショットの映像では、顔のないフレームが選ばれることがあります。その場合、face_skin_check.png は役に立ちません(品質基準は肌です)。--frame-time SECONDS を指定して、顔が映っていることが分かっている場面を選んでください。
    • ホワイトバランス/露出の統計値は、映像の長さの 10% 地点にある約 10 秒間の signalstats ウィンドウ 1 つから取得します。照明が一定であれば問題ありません。照明が変化する映像では、--win-start SECONDS/--win-dur SECONDS で位置を変更したり、長さを延ばしたりしてください。
  2. 選択用にルックをレンダリングします。

    python scripts/render_looks.py work/assess/frame.png looks.json --out work/looks
    

    work/looks/looks_compare.png(元映像とすべてのルックをラベル付きでフル解像度表示)と、face_skin_check.png(肌部分を拡大したストリップ)を生成します。両方を確認してください。 肌が基準です。肌が灰色や緑色になるルックは再調整するか除外してから、再レンダリングしてください。被写体が中央から外れている場合は、--face-crop W:H:X:Y を追加してください。 これらの PNG は作業用の中間ファイルとして扱い、承認済みのレビュー用コピーを review/02-color-grade/choose-color-look.jpg と review/02-color-grade/skin-tone-check.jpg に保存してください。

  3. (任意) 上位 2~3 件のモーションプレビューを作成し、動きを確認できるようにします(音声は保持されます)。

    python scripts/make_clips.py SOURCE.mp4 looks.json --out work/clips \
      --pick clean_neutral,warm_filmic,teal_orange --with-original --ss 148 --t 8
    
  4. ルックを 1 つ選択します。 ユーザーが選択を求めた場合に限り、コンタクトシートを提示して回答を待ちます。それ以外の場合は、エージェントモードで選択し、判断待ちで中断せずに続行します。納品前に selected_look、selection_mode、selection_rationale を記入してください。

  5. 選択後 — LUT を作成し、クリップ全体に適用します。

    python scripts/bake_lut.py looks.json --name CHOSEN \
      --out final/selected-color-look.cube --verify-frame work/assess/frame.png
    python scripts/apply_grade.py SOURCE.mp4 --looks looks.json --name CHOSEN --out out/graded.mp4
    #   or apply the delivered LUT: --lut final/selected-color-look.cube
    

    apply_grade.py は再生時間と音声が保持されていることを検証し、ホワイトバランスの変化量(U/V が 128 に近づく方向)を表示して、目視確認用のフレームを出力します。

    • 適用時に動画は 1 回再エンコードされます(非可逆)。音声には -c:a copy が使われます。 品質と処理時間は --crf(デフォルトは 18)と --preset(デフォルトは slow)で設定します。小規模または短いクリップなら slow で問題ありませんが、1080p/4K の 1 時間の映像では時間が大幅にかかり、進捗も表示されません。納品用には --preset medium(簡易プレビューには veryfast)に変更し、最終版に限って slow を使ってください。
    • 納品する動画と納品する LUT を一致させてください。 チェーン(--name)と、焼き込まれた 33³ の .cube(--lut)は、急なカーブでは最大で約 5/255 異なることがあります(bake_lut.py がこの差を max|d| として報告します)。ほとんどの作業では見えない差ですが、.cube を納品し、それに動画を正確に一致させたい場合は、--name ではなく --lut final/selected-color-look.cube を指定して適用してください。

設計上の注意点/落とし穴

  • クリーン版をグレーディングしてから、その映像にオーバーレイを合成します。 焼き込み済みのキャプション/カードがある動画をグレーディングする必要がある場合、assess.py の結果を信用しないでください。グラフィックによって、WB/露出の統計値とフレーム選択が偏ります(上下の暗いスクリーンがYを下げ、明るいキャプション文字やティールのアクセントがU/Vを偏らせ、キャプションの多いフレームが選ばれることがあります)。オーバーレイではなく映像を補正することになるためです。クリーンな映像で調整した base を再利用し、グレードによってオーバーレイにも色が付くことを想定してください。そのため、控えめな補正用ルック(clean_neutral)だけを使用します。teal_orange/vintage_faded を使うと、文字やアクセントの色が目に見えて変わります。
  • 関連するすべてのクリップに同じルック/LUTを適用します。 ルックを選んだら、関連するすべてのクリップ(例:クリーン版とオーバーレイ版)で同じ looks.json/.cube を再利用します。クリップごとに2段階の選定をやり直さないでください。
  • 補正してからスタイルを加えます。 base は、デッキのS-Log3→Rec.709変換を一般化したものです。通常の映像では base にWB+露出+コントラストを設定し、ログ映像では変換をそこに設定します。
  • まず肌を確認します。 暗めの被写体では、teal_orange/cool_desat が肌色を損ねやすい傾向があります。中間調は暖色に保ち、シャドウ/ハイライト/背景に色を加え、vibrance を使います。U/Vを完全にニュートラルにしないでください。
  • ラベルはPILのPNGをffmpegでオーバーレイします。drawtext は使いません。 Windowsでは、drawtext の fontfile パス(ドライブ名のコロン)が不安定です。フォントは gradelib.py の先頭で設定します。
  • ドライブ名にコロンを含むパスは、パスを取るffmpegのフィルターグラフオプション(lut3d、metadata=print:file=)で問題を起こします。スクリプトは cwd をファイルのフォルダーにしてffmpegを実行し、ベース名で参照します。パスを取るフィルターを追加する場合も、このパターンを維持してください。
  • 出力先は指定した --out ディレクトリです(永続化されます)。システムの一時ディレクトリではありません。
  • 顔/肌のストリップには、顔検出ではなく中央上寄りの固定クロップを使います。 被写体がほぼ中央にいない場合は、render_looks.py に --face-crop W:H:X:Y を渡してください。そうしないと、肌のストリップに誤った領域が表示されます。
  • apply_grade.py の検証用スポットフレームは、動画の長さの20%地点です。 ルックの選定に使用したフレームとは異なります。20%地点に顔がない場合は、別のフレームで肌を目視確認してください(または assess.py に --frame-time を渡し、顔が映ると分かっている場面のフレームを選びます)。
  • LUTのベイクは正確です。 ここで使うフィルターはすべてピクセル単位のポイント演算だからです。bake_lut.py は33³の恒等グリッドを実際の処理チェーンに通し、結果を自己検証します(mean|d| は1/255を大幅に下回るはずです。max|d| が数レベルになるのは補間によるものです)。
  • 納品前に必ず選定します。 人間による選定も、委任されたエージェントによる選定も有効ですが、どちらが行われたかとその理由を計画に記録する必要があります。

コメント