关于 video-color-grade
用于视频调色的技能,可从素材创建多种命名风格,进行比较和选择,再烘焙并应用 LUT。它将通用校正与创意风格分开,并重点检查肤色。
主要功能
- 01分析素材并建议基础校正
- 02在同一帧渲染并标注多种风格
- 03通过对比图检查肤色
- 04记录风格选择及理由
- 05烘焙便携式 `.cube` LUT
- 06应用调色并复制音频
适用场景
- 01比较视频片段的不同色彩处理
- 02结合肤色检查选择风格
- 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.jsonscripts/apply_grade.pyassess.pybake_lut.pygradelib.pymake_clips.pyrender_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.
]
}
工作流
-
评估——切勿盲目评分。
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调整窗口的起点/时长。
- 代表帧按亮度中位数选取,而非按人脸选取。 对单镜头的访谈视频,通常会选到一帧不错的人脸画面;但对于大量 B-roll 或多镜头素材,可能会选到没有人脸的画面,此时
-
渲染各个色调方案,供选择。
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。 -
(可选) 预览排名前 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 -
选择一种色调方案。 展示对比图表,并且仅在用户要求选择时等待其决定。 否则,在 Agent 模式下自行选择并继续,不要暂停等待决定。交付前写入
selected_look、selection_mode和selection_rationale。 -
选定后——烘焙 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.cubeapply_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 选择都有效,但计划必须记录选择方式及原因。