Communitygithub.com

Video-Farbkorrektur

Verwendet, wenn Filmmaterial eine Farbkorrektur, Weißabgleich- oder Belichtungsreparatur, Log-zu-Rec.709-Konvertierung, benannte kreative Looks, Hautton-Überprüfung oder ein portables .cube-LUT für eine Cut-as-Code-Lieferung benötigt.

Was ist Video-Farbkorrektur?

Die Video-Farbkorrektur-Skill bewertet Filmmaterial mit ffmpeg/ffprobe und Python, erstellt automatisch mehrere benannte Looks (z. B. Clean Neutral, Teal & Orange, Warm Filmic) auf einem repräsentativen Frame, wobei jeder Look als Kombination aus einer gemeinsamen korrektiven Basis und einem kreativen Layer aufgebaut wird. Nach der Auswahl eines Looks – entweder explizit durch den Benutzer (human mode) oder automatisch durch den Agenten (agent mode) mit Schwerpunkt auf Hautton- und Belichtungsschonung – wird ein portables 33³ .cube-LUT gebacken und mittels ffmpeg auf das gesamte Video angewendet. Die Skill unterstützt sowohl Log/HLG-Footage (mit automatischer Log→709-Konvertierung) als auch bereits korrigiertes Material, bewahrt die Audio-Spur verlustfrei über `-c:a copy` und stellt sicher, dass Dauer, fps und Maße des Quellvideos erhalten bleiben. Besonderer Wert wird auf Hauttöne gelegt: Teal-Orange- und kühle Desättigungs-Looks werden auf dunkleren Hauttönen kritisch geprüft und bei Grün-/Graustich verworfen. Die Skill ist kompatibel mit Claude Code, Cursor, Codex und anderen KI-Agenten-Plattformen, die ffmpeg, Python, numpy und Pillow bereitstellen.

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

In Ihrer bevorzugten KI fragen

Öffnet einen neuen Chat, in dem dieser Agent-Skill bereits geladen ist.

Dokumentation

Video-Farbkorrektur (bewerten → korrigieren → Looks → auswählen → LUT + anwenden)

Schreibe die Korrektur von Grund auf als Code, generiere mehrere verschiedene benannte Looks auf dem echten Filmmaterial, wähle einen durch explizite menschliche Entscheidung oder delegierte Agentenentscheidung aus, erstelle dann ein portables .cube-LUT und wende es auf den gesamten Clip an. Keine Voreinstellungspakete.

Kernidee — korrigieren, dann stylen. Jeder Look ist korrektive Basis + kreative Schicht:

  • korrektive Basis macht das Filmmaterial ehrlich — für flaches LOG/HLG ist es die Log→Rec.709 Konvertierung; für bereits Rec.709-korrigiertes Material ist es der Weißabgleich neutralisieren + Belichtung + dezenter Kontrast. Jeder Look teilt sich diese Basis, sodass ein "neutraler" Look sinnvoll bleibt und sich die Looks durch die Absicht unterscheiden.
  • kreative Schicht ist der darauf aufgesetzte Look (warm / kühl / Teal-Orange / knallig / verblasst…).

Haut ist das Qualitätskriterium. Bei Personen — besonders bei dunklerer Haut — werfen teal_orange und cool_desat regelmäßig einen Grün-/Graustich. Beurteile jeden Look zuerst an den Gesichtern; halte die Mitteltöne warm, verschiebe den Farbstich in die Schatten/Lichter/Hintergrund, bevorzuge vibrance gegenüber roher saturation. Treibe den Weißabgleich nicht ganz auf neutral, sonst wird die Haut leblos.

Voraussetzungen: ffmpeg/ffprobe im PATH, Python mit numpy + Pillow.

Vertrag

  • Jeder Look = Basis + kreative Schicht; die Basis wird von allen Looks geteilt.
  • Alle Looks werden auf dem gleichen repräsentativen Frame (ein fairer, kontrollierter Vergleich) gerendert, beschriftet, in voller Auflösung.
  • Die vollständige Anwendung verwendet -c:a copy (Audio wird nie neu kodiert → A/V-Synchronisation identisch) und behält die Dauer, fps, Abmessungen der Quelle bei.
  • Vollständige Look-Auswahl vor der Lieferung. Verwende den human-Modus, wenn der Benutzer gebeten wurde, zu wählen; verwende den agent-Modus ohne Pause, wenn der Benutzer die Wahl delegiert oder einen autonomen Durchlauf angefordert hat. Bewahre in beiden Modi die Begründung im dauerhaften Plan.

Projektprotokoll-Workflow

Speichere die dauerhafte Entscheidung in 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": "Neutrale Korrektur bewahrt natürliche Haut und Quelllicht.",
  "selected_lut": "../../final/selected-color-look.cube",
  "evidence_refs": ["media:source"]
}

Verwende standardmäßig base-video, damit Inhaltskarten und Untertitel nicht neu eingefärbt werden. composite ist nur gültig, wenn bereits zusammengesetzte Pixel absichtlich korrigiert werden. Lese die gemeinsame work/understand/media.json und visuelle Beweise. Erstelle review/02-color-grade/choose-color-look.jpg und review/02-color-grade/skin-tone-check.jpg; erstelle optional die kurze selected-look-preview.mp4. Dokumentiere die Entscheidung und die Beweise in review/02-color-grade/selected-look.md.

Setze selection_mode auf human nach einer expliziten Benutzerwahl. Setze es auf agent, wenn der Benutzer die Entscheidung delegiert oder einen ununterbrochenen Workflow anfordert, und wähle konservativ mit Hautton, Lichtererhaltung und neutralem Gleichgewicht als Prioritäten. Schreibe immer eine nicht-leere selection_rationale; pausiere im Agenten-Modus nicht.

Erstelle das ausgewählte LUT unter final/selected-color-look.cube. Wenn dieses LUT ausgeliefert wird, setze selected_lut im Korrekturplan, damit der gemeinsame Renderer genau diese Datei verwendet. Ein gebackenes Vollformat-LUT enthält bereits die korrektive Basis; der Renderer muss nur lut3d anwenden, nicht Basis + lut3d.

Dokumentiere die genauen Revisionen der Eingabeoperation in based_on, erhöhe deren ganzzahlige revision, wenn sich der Plan oder die ausgewählte Eingabe ändert, setze die Operationsprüfung auf pass erst nach Abschluss der Review-Dateien und füge die vollständigen Protokollfelder hinzu:

{
"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"
}
}

Der gemeinsame Renderer validiert, dass selected_look existiert, wendet die Korrektur nach den Timeline-Transformationen und vor den Overlays an und kodiert das endgültige Video einmal:

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

Standalone-Kompatibilitätseingaben

  • Das Quellvideo.
  • Eine looks.json (base + benannte looks); beginne mit looks.example.json und stimme die base basierend auf dem ab, was assess.py meldet.

Alle vorhandenen Skripte akzeptieren weiterhin das alte looks.json. gradelib.load_spec() akzeptiert auch das kanonische grade-plan.json, sodass Kontaktbogen-, Clip-, LUT- und Standalone-Anwendungsbefehle während der Migration kompatibel bleiben.

looks.json-Schema

{
  "base": "<korrektive Basis: Log→Rec.709 Konvertierung ODER WB+Belichtung+Kontrast für normales Filmmaterial>",
  "looks": [
    { "name": "clean_neutral", "label": "1 · CLEAN NEUTRAL", "desc": "nur korrigiert", "chain": "eq=contrast=1.02" },
    { "name": "teal_orange",   "label": "4 · TEAL & ORANGE", "desc": "filmisch",      "chain": "colorbalance=...,eq=..." }
    // Ein vollständiger ffmpeg-Filter eines Looks = base + "," + chain. Setze "prepend_base": false, um chain standalone zu verwenden.
  ]
}

Workflow

  1. Bewerten — niemals blind korrigieren.

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

    Berichtet Log-vs-Rec.709, Weißabgleich-Abweichung (signalstats U/V vs 128), Belichtung (Y), wählt einen repräsentativen Frame (work/assess/frame.png) und schlägt Basis-Anpassungen vor. Stimme die looks.json base entsprechend nach (z. B. warmer Farbstich → etwas Blau hinzufügen; Log → die Log→709-Konvertierung in base setzen).

    • Der repräsentative Frame wird nach medianer Luminanz gewählt, nicht nach Gesichtern. Bei einem Einzel-Talking-Head landet das normalerweise auf einem guten Gesichts-Frame, aber bei B-Roll-lastigem/Mehrfach-Einstellungen-Material kann es einen gesichtslosen Frame auswählen – und dann ist face_skin_check.png nutzlos (Haut ist das Qualitätskriterium). Erzwinge einen bekannten Gesichtsmoment mit --frame-time SEKUNDEN.
    • Die WB-/Belichtungsstatistiken stammen aus einem ~10s signalstats-Fenster bei 10% der Dauer – gut für konstantes Licht; bei Filmmaterial mit wechselndem Licht verschiebe/verlängere es mit --win-start SEKUNDEN / --win-dur SEKUNDEN.
  2. Rendere die Looks zur Auswahl.

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

    Erzeugt work/looks/looks_compare.png (Original + jeder Look, beschriftet, volle Auflösung) und face_skin_check.png (gezoomter Hautstreifen). SCHAUE BEIDE AN. Haut ist das Kriterium – stimme nach oder verwirf jeden Look, der Haut grau/grün macht, und rendere dann erneut. Motiv nicht zentriert? Füge --face-crop B:H:X:Y hinzu. Behandle diese PNGs als Arbeits-Zwischenergebnisse; veröffentliche die genehmigten Review-Kopien als review/02-color-grade/choose-color-look.jpg und review/02-color-grade/skin-tone-check.jpg.

  3. (optional) Bewegungsvorschauen der Top 2–3, damit sie in Bewegung gesehen werden (Audio bleibt):

    python scripts/make_clips.py QUELLE.mp4 looks.json --out work/clips \
      --pick clean_neutral,warm_filmic,teal_orange --with-original --ss 148 --t 8
    
  4. Wähle einen Look aus. Präsentiere den Kontaktbogen und warte nur, wenn der Benutzer gebeten wurde zu wählen. Ansonsten wähle im Agenten-Modus aus und fahre ohne Entscheidungspause fort. Schreibe selected_look, selection_mode und selection_rationale vor der Lieferung.

  5. Nach der Auswahl – backe das LUT und wende es auf den gesamten Clip an.

    python scripts/bake_lut.py looks.json --name AUSGEWAEHLT \
      --out final/selected-color-look.cube --verify-frame work/assess/frame.png
    python scripts/apply_grade.py QUELLE.mp4 --looks looks.json --name AUSGEWAEHLT --out out/bewertet.mp4
    #   oder wende das gelieferte LUT an: --lut final/selected-color-look.cube
    

    apply_grade.py überprüft, ob Dauer/Audio erhalten bleiben, druckt die WB-Verschiebung (U/V in Richtung 128) und legt einen Spot-Frame zur Sichtprüfung ab.

    • Die Anwendung kodiert das Video einmal (verlustbehaftet) neu; Audio ist -c:a copy. Qualität/Zeit werden durch --crf (Standard 18) und --preset (Standard slow) eingestellt. slow ist für kleine/kurze Clips in Ordnung, aber bei 1080p/4K stundenlangem Material ist es ein großer, stiller Zeitaufwand – wechsle zu --preset medium für die Lieferung (oder veryfast für eine schnelle Vorschau), slow nur für die endgültige Fassung.
    • Stimme das gelieferte Video mit dem gelieferten LUT ab: Die Kette (--name) und das gebackene 33³ .cube (--lut) können sich bei steilen Kurven um bis zu ~5/255 unterscheiden (bake_lut.py meldet dieses max|d|). Für die meisten Arbeiten unsichtbar, aber wenn du das .cube auslieferst und möchtest, dass das gerenderte Video genau damit übereinstimmt, wende mit --lut final/selected-color-look.cube an, nicht mit --name.

Konstruktionshinweise / Fallstricke

  • Korrigiere den CLEAN-Schnitt, setze dann Composite-Overlays auf das bewertete Filmmaterial. Wenn du ein Video korrigieren musst, das bereits eingebrannte Untertitel/Karten hat, vertraue NICHT auf assess.py: seine WB-/ Belichtungsstatistiken und die Rahmenauswahl werden durch die Grafiken verfälscht (dunkle obere/untere Bildschirmleisten ziehen Y nach unten, heller Untertiteltext / Tealfarbtöne verfälschen U/V, und die Rahmenauswahl kann auf einen untertitellastigen Rahmen fallen) – du würdest die Overlays korrigieren, nicht das Filmmaterial. Verwende eine base, die auf dem sauberen Filmmaterial abgestimmt ist, und erwarte, dass die Korrektur die Overlays einfärbt, also verwende nur einen subtilen/korrigierenden Look (clean_neutral); teal_orange/vintage_faded werden den Text/die Farbakzente sichtbar umfärben.
  • Ein Look/LUT deckt alle verwandten Clips ab. Sobald du einen Look ausgewählt hast, verwende dasselbe looks.json / .cube für jeden verwandten Clip (z. B. sauberer Schnitt + die überlagerte Version) – führe NICHT die zweiphasige Auswahl pro Clip erneut durch.
  • Korrigieren, dann stylen. Die Basis ist die Verallgemeinerung des S-Log3→Rec.709-Schritts des Decks. Für normales Filmmaterial ist die Basis WB+Belichtung+Kontrast; für Log-Filmmaterial setze die Konvertierung dort hinein.
  • Haut zuerst. teal_orange/cool_desat sind die üblichen Hauttöne-Störenfriede bei dunkleren Motiven – halte die Mitteltöne warm, färbe Schatten/Lichter/Hintergrund, verwende vibrance. Neutralisiere U/V nicht vollständig.
  • Beschriftungen sind PIL-PNGs, die von ffmpeg überlagert werden – niemals drawtext. Unter Windows ist der drawtext-fontfile-Pfad (Laufwerk-Doppelpunkt) unzuverlässig. Schriftarten werden am Anfang von gradelib.py gesetzt.
  • Laufwerk-Doppelpunkt-Pfade brechen ffmpeg-Filtergraph-Optionen, die einen Pfad akzeptieren (lut3d, metadata=print:file=). Die Skripte führen ffmpeg mit cwd = dem Ordner der Datei aus und referenzieren sie mit dem Basisnamen. Behalte dieses Muster für jeden neuen pfadnehmenden Filter bei.
  • Ausgaben landen in den von dir übergebenen --out-Verzeichnissen (dauerhaft), nicht in einem System-Temp-Verzeichnis.
  • Der Gesichts-/Hautstreifen verwendet einen festen, zentrierten oberen Mittelausschnitt, keine Gesichtserkennung. Wenn sich das Motiv nicht ungefähr in der Mitte befindet, übergib --face-crop B:H:X:Y an render_looks.py, sonst zeigt der Hautstreifen die falsche Region.
  • Der Verifikations-Spot-Frame von apply_grade.py liegt bei 20% der Dauer – ein anderer Frame als der, auf dem die Looks ausgewählt wurden. Wenn dieser 20%-Punkt gesichtslos ist, prüfe die Haut stattdessen an einem anderen Frame (oder übergib --frame-time an assess.py, damit der ausgewählte Frame ein bekannter Gesichtsmoment ist).
  • Das LUT-Backen ist exakt, weil jeder Filter hier ein pixelweiser Punktoperator ist: bake_lut.py schiebt ein 33³-Identitätsgitter durch die echte Kette und prüft sich selbst dagegen (mean|d| sollte deutlich unter 1/255 liegen; ein paar Ebenen max|d| ist nur Interpolation).
  • Auswahl vor Lieferung, immer. Die menschliche Wahl und die delegierte Agentenwahl sind beide gültig, aber der Plan muss festhalten, welche stattfand und warum.

Individual skills in this repo

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

Verwandte Skills