| name | grade-consistency-pass |
| description | Apply uniform color grade across all clips in an ad run so the polished cut has consistent contrast, saturation, and gamma. Reads a reference clip (default first scene) and matches every other clip's mean LAB stats to it. |
grade-consistency-pass
Purpose
AI-generated scenes drift in color/contrast/saturation across cuts. This atom samples a reference clip, computes mean Y/U/V stats on every other clip, and applies an ffmpeg eq (+ optional curves) filter to each to bring its mean closer to the reference. The result is a graded set of clips with significantly reduced inter-clip variance.
Mirrors the manual color-grade logic in coca-cola/ad-runs/video-01-museum-painting/scripts/polish_v9.py but generalized and per-clip.
Inputs
--clips-dir <path> — directory containing scene-*.mp4 (required)
--output-dir <path> — destination (default: <clips-dir>/graded/)
--reference <name|path> — clip used as the grade reference. Default: lexicographically first clip in <clips-dir>. Can be a scene filename (scene-03.mp4) or an absolute path.
--match <y,u,v> — comma-separated channels to match (default y,u,v). Drop u,v to keep original tint per clip.
--max-delta <0–1> — clamp the contrast/saturation/gamma adjustments so a single bad reference can't blow out everything (default 0.30)
--archive <path> — if set, copy original clips here before overwriting (default: <clips-dir>/_archive/pre-grade-<ts>/)
Workflow
- List
scene-*.mp4 in <clips-dir>; resolve the reference clip.
- For each clip including reference, compute mean YAVG, UAVG, VAVG via
ffmpeg signalstats over a 1-fps frame sample.
- Derive an adjustment per clip:
- Contrast =
clamp(ref_yavg / clip_yavg, 1 - max_delta, 1 + max_delta) (applied as ffmpeg eq=contrast= around 1.0)
- Saturation =
clamp(ref_uvspread / clip_uvspread, ...), where uvspread = sqrt((uavg-128)^2 + (vavg-128)^2)
- Gamma = chosen so the corrected clip's mean Y matches reference Y, capped by
max-delta.
- Apply per-clip via
ffmpeg -i scene.mp4 -vf "eq=contrast=<C>:saturation=<S>:gamma=<G>" -c:a copy graded/scene.mp4.
- Archive originals before overwrite (if
--archive resolves to the same path as --output-dir).
- Re-measure each graded clip and report deltas.
Output
<output-dir>/scene-*.mp4 — graded clips
<output-dir>/manifest.json:
{
"reference": "scene-01.mp4",
"reference_stats": {"y": 128.4, "u": 127.1, "v": 130.5},
"clips": [
{"name": "scene-02.mp4", "before": {...}, "after": {...}, "params": {"contrast": 0.96, "saturation": 1.08, "gamma": 1.02}},
...
],
"variance_before": {"y": 14.2, "u": 6.0, "v": 8.1},
"variance_after": {"y": 3.1, "u": 2.4, "v": 3.0},
"status": "ok"
}
<output-dir>/verification.md — variance reduction table.
Quality checks
- Variance of
y across graded clips < variance before, by ≥ 50%.
- No single clip's contrast/saturation/gamma adjustment exceeds
max-delta.
- All originals archived before overwrite.
- Audio streams byte-identical to source.
Failure modes
- Reference clip is itself an outlier (e.g. very dark) — grading everything to it darkens the whole cut. Mitigation: use
--reference to point at a known-good scene, or compute reference as the median rather than first clip (future flag).
- Black frames in a clip skew mean Y — current impl samples at 1 fps, which still includes them. For clips with intentional fades, pass
--match u,v only.
- Audio re-encoded inadvertently — explicit
-c:a copy.
Example
scripts/grade.py \
--clips-dir coca-cola/ad-runs/video-01-museum-painting/clips/ \
--reference scene-03.mp4
Consumed by /polish (color-consistency branch).