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. 03导出 LUT 并为完整片段调色

安装

复制下面的命令,在终端中运行。

$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 + 应用)

从头编写调色代码,在真实素材上生成多个风格迥异的命名风格,通过明确的人工选择或委托 Agent 判断选出一种,然后烘焙成便于移植的 .cube LUT 并应用到整个片段。不要使用预设包。

核心理念——先校正,再定风格。 每种风格都由 校正基础 + 创意层 组成:

  • 校正基础让素材呈现真实效果——对于平淡的 LOG/HLG 素材,这是 log→Rec.709 转换;对于已经是 Rec.709 的素材,则是白平衡中和 + 曝光 + 轻微对比度。所有风格共用此基础,因此“中性”始终有明确含义,而各风格则因意图而异。
  • 创意层是在基础上叠加的风格(暖调 / 冷调 / 青橙 / 鲜明 / 褪色……)。

肤色是衡量质量的标准。 对于有人物的素材——尤其是深色肤色——teal_orange 和 cool_desat 往往会带来偏绿 / 偏灰的色偏。先观察每种风格下的人脸;保持中间调温暖,将色调偏移推向阴影 / 高光 / 背景,并优先使用 vibrance,而不是直接提高 saturation。不要把白平衡完全调到中性,否则肤色会失去生气。

要求:ffmpeg/ffprobe 已加入 PATH;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 已包含校正基础;渲染器必须只应用 lut3d,不能使用 base + 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

独立兼容输入

  • 源视频。
  • looks.json(包含 base + 命名的 looks);从 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/
    

    报告日志与 Rec.709 的差异、白平衡色偏(signalstats 的 U/V 与 128 的差异)、曝光(Y),选取一帧有代表性的画面(work/assess/frame.png),并建议基础调整。相应地重新调整 looks.json 中的 base(例如,偏暖时稍微增加蓝色;如果是日志素材,则将日志→709 转换放入 base)。

    • 代表帧按亮度中位数选取,而非按人脸选取。 对单镜头的访谈视频,通常会选到一帧不错的人脸画面;但对于大量 B-roll 或多镜头素材,可能会选到没有人脸的画面,此时 face_skin_check.png 就毫无用处(肤色才是质量标准)。使用 --frame-time SECONDS 强制指定已知有人脸的时刻。
    • 白平衡/曝光统计来自素材时长 10% 处的一个约 10 秒 signalstats 窗口——对于光线恒定的素材足够;若素材光线会变化,可使用 --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. 选择一种色调方案。 展示对比图表,并且仅在用户要求选择时等待其决定。 否则,在 Agent 模式下自行选择并继续,不要暂停等待决定。交付前写入 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 的变化),并输出一帧画面供快速检查。

    • 应用调色时会对视频重新编码一次(有损);音频使用 -c:a copy。 质量/耗时由 --crf(默认值为 18)和 --preset(默认值为 slow)决定。对于短小的片段,slow 没问题;但对于时长一小时的 1080p/4K 素材,它会大幅增加耗时,且不会给出提示——交付时应改用 --preset medium(快速预览则用 veryfast),仅在最终输出时使用 slow。
    • 确保交付视频与交付的 LUT 匹配: 在曲线陡峭时,处理链(--name)与烘焙的 33³ .cube(--lut)最多可能相差约 5/255(bake_lut.py 会报告此 max|d|)。大多数场景中难以察觉;但如果你要交付 .cube 文件,并希望渲染后的视频与其完全匹配,请使用 --lut final/selected-color-look.cube,而不要使用 --name。

设计说明 / 注意事项

  • 先对干净版本调色,再将叠加层合成到调色后的视频上。 如果必须对已经烧录字幕或卡片的视频调色,切勿信任 assess.py:它的白平衡/曝光统计和帧选择会受到图形元素影响(顶部/底部的深色遮罩会拉低 Y 值,明亮的字幕文字/青绿色点缀会影响 U/V 值,而选中的帧可能满是字幕)——这样你调整的是叠加层,而不是视频素材。请重复使用基于干净视频素材调好的 base,并预期调色会改变叠加层的色调,因此只使用微妙/修正性的风格(clean_neutral);teal_orange/vintage_faded 会明显改变文字/点缀的颜色。
  • 所有相关片段都使用同一种风格/LUT。 选定一种风格后,将同一套 looks.json / .cube 用于所有相关片段(例如,干净版本和带叠加层的版本)——切勿为每个片段重新运行两阶段选择流程。
  • 先校正,再定风格。 base 是对演示文稿中 S-Log3→Rec.709 转换步骤的通用化处理。对于普通视频素材,base 包含白平衡、曝光和对比度;对于 log 视频素材,则应在此处进行色彩空间转换。
  • 优先处理肤色。 teal_orange/cool_desat 通常会让肤色较深的主体肤色失真——保持中间调温暖,对阴影/高光/背景着色,并使用 vibrance。不要完全中和 U/V。
  • 标签使用 PIL PNG,并通过 ffmpeg 叠加——切勿使用 drawtext。 在 Windows 上,drawtext 的 fontfile 路径(含盘符冒号)不可靠。字体在 gradelib.py 顶部设置。
  • 带盘符冒号的路径会破坏 ffmpeg filtergraph 中接收路径的选项(如 lut3d、metadata=print:file=)。脚本运行 ffmpeg 时会将 cwd 设为文件所在文件夹,并通过基本文件名引用该文件。任何新增的接收路径的滤镜都应沿用此模式。
  • 输出会保存到你传入的 --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| 只是插值造成的)。
  • 交付前务必完成选择。 人工选择和委派 Agent 选择都有效,但计划必须记录选择方式及原因。

评论

支持 Markdown