Communitygithub.com

视频色彩分级

用于需要对素材进行色彩校正、白平衡或曝光修复、Log转Rec.709转换、命名创意风格、肤色检查,或为"剪辑即交付"流程生成便携式.cube LUT的场景。

视频色彩分级 是什么?

该技能(Video Color Grade)是一个基于代码的自动化视频色彩分级工具,专为AI代理(如Claude Code、Cursor、Codex)设计。其核心理念是“先校正,再风格化”,通过将分级过程拆解为“校正基础”和“创意风格层”两个独立部分,确保所有创意风格都建立在对素材的正确还原之上。技能支持完整的端到端工作流:首先使用ffmpeg和Python脚本分析源视频,判断其为Log素材还是已校正的Rec.709素材,并获取白平衡、曝光等关键统计信息;然后基于分析结果生成多个不同的命名风格(如暖色调、冷色调、青橙风格等),所有风格共享同一个校正基础,并在同一张代表性帧上进行并排渲染对比;接着,通过人类手动选择或AI代理自主决策的方式选定最终风格;最后,将选定的完整风格(校正基础+创意层)烘焙成一个32³或33³的便携式.cube LUT文件,并应用到整个视频片段上。技能特别强调肤色是质量基准,尤其在对深色肤色人物进行处理时,会避免使用可能产生绿色/灰色偏色的青橙或冷色去饱和风格,并优先使用“自然饱和度”而非原始“饱和度”。它支持常见的视频处理平台,但要求系统已安装ffmpeg/ffprobe,以及Python的numpy和Pillow库。整个工作流的决策和配置文件(如grade-plan.json)会被持久化记录,支持可重现和可审计的交付。

兼容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/WhiteTowerAI/cut-as-code/tree/main/skills/video-color-grade

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

视频色彩分级(评估 → 校正 → 风格 → 选择 → LUT + 应用)

从头编写分级代码,在真实素材上生成多个不同的命名风格,通过明确的人类选择或委派的代理判断来选定一个风格,然后烘焙出一个便携式.cube LUT并将其应用到整个片段。无需预设包。

核心理念——先校正,后风格化。 每个风格都是 校正基础 + 创意层:

  • 校正基础 使素材变得“诚实”——对于平坦的LOG/HLG素材,它是log转Rec.709转换;对于已经是Rec.709的素材,它是白平衡中和 + 曝光 + 轻度对比。所有风格共享这个基础,因此“中性”始终有意义,而风格之间则通过“意图”来区分。
  • 创意层 是叠加在基础之上的风格(暖色/冷色/青橙/鲜艳/褪色……)。

肤色是质量基准。 对于人物——尤其是深色皮肤——teal_orange 和 cool_desat 通常会投射出绿色/灰色的偏色。首先在面孔上评判每个风格;保持中间调温暖,将色调推入阴影/高光/背景,优先使用 vibrance 而不是原始的 saturation。不要将白平衡一路推向中性,否则皮肤会失去活力。

要求:环境变量 PATH 中包含 ffmpeg/ffprobe,以及安装了 numpy + Pillow 的 Python。

契约

  • 每个风格 = base + creative layer;该基础由所有风格共享。
  • 所有风格渲染在同一帧代表性帧上(公平、可控制的比较),带有标签,全分辨率。
  • 完整应用使用 -c:a copy(音频从不重新编码 → A/V 同步一致)并保持源文件的时长、帧率、尺寸。
  • 在交付前完成风格选择。当用户要求选择时,使用 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": "中性校正保留了自然的肤色和原始光源。",
  "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": "<校正基础:log转Rec.709转换,或针对普通素材的白平衡+曝光+对比度>",
  "looks": [
    { "name": "clean_neutral", "label": "1 · 干净中性", "desc": "仅校正", "chain": "eq=contrast=1.02" },
    { "name": "teal_orange",   "label": "4 · 青橙风格", "desc": "电影感",      "chain": "colorbalance=...,eq=..." }
    // 一个风格的完整 ffmpeg 滤镜 = base + "," + chain。设置 "prepend_base": false 以单独使用 chain。
  ]
}

工作流

  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 中)。

    • 代表性帧是根据中位数亮度选取的,而不是根据面部。 在单次拍摄的 talking-head 上,这通常会落在好的面部帧上,但在以 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
    #   或使用交付的 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——不要为每个片段重新运行两阶段的选择过程。
  • 先校正,后风格化。 基础是对 Deak's S-Log3→Rec.709 步骤的泛化。对于普通素材,基础是白平衡+曝光+对比度;对于 log 素材,将转换放在那里。
  • 皮肤优先。 teal_orange/cool_desat 是在深色主体上常见的皮肤问题来源——保持中间调温暖,对阴影/高光/背景进行色调处理,使用 vibrance。不要完全中和 U/V 值。
  • 标签是通过 ffmpeg 叠加的 PIL PNG——永不使用 drawtext。 在 Windows 上,drawtext 的 fontfile 路径(驱动器冒号)不可靠。字体在 gradelib.py 顶部设置。
  • 驱动器冒号路径会破坏需要路径的 ffmpeg filtergraph 选项(如 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;几个 level 的 max|d| 仅仅是插值结果)。
  • 交付前始终进行选择。 人类选择和委派的代理选择都是有效的,但计划必须记录哪个发生了以及原因。

Individual skills in this repo

This repo contains 8 individual skills — each has its own dedicated page.

相关技能