Communitygithub.com

video-color-grade

Use quando a filmagem precisa de correção de cor, balanço de branco ou reparo de exposição, conversão Log para Rec.709, looks criativos nomeados, revisão de tom de pele ou um LUT .cube portátil para entrega no estilo cut-as-code.

O que é video-color-grade?

Este skill automatiza o processo completo de correção e finalização de cor para vídeos, operando inteiramente por código. Ele começa com a avaliação técnica do material bruto — detectando se é flat/LOG, analisando o balanço de branco e a exposição — e, em seguida, gera vários "looks" criativos nomeados a partir de uma base corretiva compartilhada. O skill suporta modos humano (onde o usuário escolhe o look) e agente (onde o próprio assistente seleciona com base em critérios de prioridade como tom de pele, retenção de realces e balanço neutro). Após a seleção, ele gera um LUT .cube portátil e aplica o look ao vídeo completo, preservando duração, quadros por segundo, dimensões e áudio (com copy). A ferramenta usa ffmpeg/ffprobe, Python com numpy e Pillow, e produz artefatos de revisão como contact sheets e verificações de tom de pele. É ideal para fluxos de trabalho onde a correção de cor precisa ser precisa, reproduzível e integrada a pipelines de renderização sem intervenção manual repetitiva.

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

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

Video Color Grade (avaliar → corrigir → looks → escolher → LUT + aplicar)

Escreva a correção de cor do zero como código, gere vários looks nomeados distintos no material real, selecione um através de escolha humana explícita ou julgamento delegado do agente, e então grave um LUT .cube portátil e aplique-o ao clipe completo. Sem packs de presets.

Ideia central — corrigir, depois estilizar. Cada look é base corretiva + camada criativa:

  • base corretiva torna a filmagem honesta — para LOG/HLG plano é a conversão log→Rec.709; para filmagem já em Rec.709 é neutralização do WB + exposição + contraste suave. Cada look compartilha esta base, então "neutro" permanece significativo e os looks diferem por intenção.
  • camada criativa é o look empilhado por cima (quente / frio / teal-orange / vívido / desbotado…).

A pele é o padrão de qualidade. Em pessoas — especialmente pele mais escura — teal_orange e cool_desat rotineiramente jogam um tom verde/cinza. Julgue cada look nos rostos primeiro; mantenha o calor dos médios, empurre a tonalidade para as sombras/realces/fundo, prefira vibrancia em vez de saturação bruta. Não force o balanço de branco totalmente para neutro ou a pele fica sem vida.

Requisitos: ffmpeg/ffprobe no PATH, Python com numpy + Pillow.

Contrato

  • Cada look = base + camada criativa; a base é compartilhada por todos os looks.
  • Todos os looks renderizam no mesmo frame representativo (uma comparação justa e controlada), etiquetado, em resolução total.
  • A aplicação completa usa -c:a copy (áudio nunca re-codificado → sincronia A/V idêntica) e mantém a duração, fps, dimensões da fonte.
  • Seleção completa do look antes da entrega. Use o modo human quando o usuário pediu para escolher; use o modo agent sem pausar quando o usuário delegou a escolha ou solicitou uma execução autônoma. Em ambos os modos, preserve a justificativa no plano durável.

Fluxo de trabalho do protocolo do projeto

Armazene a decisão durável em 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": "Correção neutra preserva a pele natural e a iluminação original.",
  "selected_lut": "../../final/selected-color-look.cube",
  "evidence_refs": ["media:source"]
}

Use base-video por padrão para que cartões de conteúdo e legendas não sejam recoloridos. composite é válido apenas ao intencionalmente corrigir pixels já compostos. Leia o work/understand/media.json compartilhado e as evidências visuais. Gere review/02-color-grade/choose-color-look.jpg e review/02-color-grade/skin-tone-check.jpg; opcionalmente gere o curto selected-look-preview.mp4. Registre a decisão e evidências em review/02-color-grade/selected-look.md.

Defina selection_mode para human após uma escolha explícita do usuário. Defina para agent quando o usuário delegar a decisão ou solicitar um fluxo de trabalho ininterrupto, e escolha conservadoramente com tom de pele, retenção de realces e balanço neutro como prioridades. Sempre escreva um selection_rationale não vazio; não pause no modo agente.

Grave o LUT escolhido para final/selected-color-look.cube. Quando esse LUT for enviado, defina selected_lut no plano de correção para que o renderizador compartilhado consuma esse arquivo exato. Um LUT gravado de look completo já contém a base corretiva; o renderizador deve aplicar apenas lut3d, não base + lut3d.

Registre as revisões de entrada exatas da operação em based_on, incremente seu revision inteiro quando o plano ou a entrada selecionada mudar, defina a verificação da operação para pass apenas após os arquivos de revisão estarem completos, e contribua com os campos completos do protocolo:

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

O renderizador compartilhado valida que selected_look existe, aplica a correção após transformações da linha do tempo e antes de sobreposições, e codifica o vídeo final uma vez:

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

Entradas de compatibilidade autônoma

  • O vídeo de origem.
  • Um looks.json (base + looks nomeados); comece de looks.example.json e reajuste o base a partir do que assess.py relata.

Todos os scripts existentes continuam a aceitar looks.json legado. gradelib.load_spec() também aceita o canônico grade-plan.json, então comandos de folha de contato, clipe, LUT e aplicação autônoma permanecem compatíveis durante a migração.

Esquema looks.json

{
  "base": "<base corretiva: conversão log->Rec.709, OU WB+exposição+contraste para filmagem normal>",
  "looks": [
    { "name": "clean_neutral", "label": "1 · LIMPO NEUTRO", "desc": "apenas corrigido", "chain": "eq=contrast=1.02" },
    { "name": "teal_orange",   "label": "4 · TEAL & LARANJA", "desc": "cinematográfico",      "chain": "colorbalance=...,eq=..." }
    // o filtro ffmpeg completo de um look = base + "," + chain. Defina "prepend_base": false para usar chain sozinho.
  ]
}

Fluxo de trabalho

  1. Avaliar — nunca corrigir no escuro.

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

    Relata log-vs-Rec.709, desvio de balanço de branco (signalstats U/V vs 128), exposição (Y), escolhe um frame representativo (work/assess/frame.png), e sugere ajustes na base. Reajuste o base do looks.json de acordo (ex. desvio quente → adicione um pouco de azul; log → coloque a conversão log→709 no base).

    • O frame rep é escolhido pela mediana da luminância, não por rostos. Em uma fala única de cabeça falante isso geralmente cai em um bom frame de rosto, mas em filmagem com muitos B-roll / multi-tomadas pode escolher um frame sem rosto — e então face_skin_check.png é inútil (a pele é o padrão de qualidade). Force um momento de rosto conhecido com --frame-time SEGUNDOS.
    • As estatísticas de WB/exposição vêm de uma janela signalstats de ~10s a 10% da duração — bom para luz constante; para filmagem cuja luz muda, mova/aumente com --win-start SEGUNDOS / --win-dur SEGUNDOS.
  2. Renderizar os looks para escolha.

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

    Produz work/looks/looks_compare.png (original + cada look, etiquetado, resolução total) e face_skin_check.png (faixa de pele ampliada). OLHE para ambos. A pele é o padrão — reajuste ou descarte qualquer look que cinza/verdeie a pele, então re-renderize. Assunto descentralizado? adicione --face-crop L:A:X:Y. Trate esses PNGs como intermediários de trabalho; publique as cópias de revisão aprovadas como review/02-color-grade/choose-color-look.jpg e review/02-color-grade/skin-tone-check.jpg.

  3. (opcional) Pré-visualizações em movimento das 2–3 principais para que sejam vistas em movimento (áudio mantido):

    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. Selecionar um look. Apresente a folha de contato e espere apenas quando o usuário pediu para escolher. Caso contrário, selecione no modo agente e continue sem uma pausa de decisão. Escreva selected_look, selection_mode e selection_rationale antes da entrega.

  5. Após a escolha — gravar o LUT e aplicar ao clipe completo.

    python scripts/bake_lut.py looks.json --name ESCOLHIDO \
      --out final/selected-color-look.cube --verify-frame work/assess/frame.png
    python scripts/apply_grade.py SOURCE.mp4 --looks looks.json --name ESCOLHIDO --out out/graded.mp4
    #   ou aplique o LUT entregue: --lut final/selected-color-look.cube
    

    apply_grade.py verifica que duração/áudio são mantidos, imprime a mudança de WB (U/V em direção a 128), e solta um frame de verificação para inspeção.

    • A aplicação recodifica o vídeo uma vez (com perdas); o áudio é -c:a copy. Qualidade/tempo são definidos por --crf (padrão 18) e --preset (padrão slow). slow é bom para clipes pequenos/ curtos, mas em filmagem longa de 1080p/4K é um grande custo de tempo silencioso — reduza para --preset medium para entrega (ou veryfast para uma pré-visualização rápida), slow apenas para final.
    • Corresponda o vídeo entregue ao LUT entregue: a cadeia (--name) e o .cube de 33³ gravado (--lut) podem diferir em até ~5/255 em curvas íngremes (bake_lut.py relata este max|d|). Invisível para a maioria dos trabalhos, mas se você está enviando o .cube e quer que o vídeo renderizado corresponda exatamente a ele, aplique com --lut final/selected-color-look.cube, não --name.

Notas de design / pegadinhas

  • Corrija o CORTE LIMPO, então composite sobreposições em cima da filmagem corrigida. Se você deve corrigir um vídeo que já tem legendas/cartões queimados, NÃO confie em assess.py: suas estatísticas de WB/ exposição e escolha de frame são desviadas pelos gráficos (escuridão superior/inferior arrasta Y para baixo, texto de legenda brilhante / tons teal desviam U/V, e a escolha de frame pode cair em um frame com muitas legendas) — você estaria corrigindo as sobreposições, não a filmagem. Reutilize um base ajustado na filmagem limpa, e espere que a correção tingirá as sobreposições, então use apenas um look sutil/corretivo (clean_neutral); teal_orange/vintage_faded recolorirá visivelmente o texto/acentos.
  • Um look/LUT cobre todos os clipes relacionados. Depois de escolher um look, reutilize o mesmo looks.json / .cube em cada clipe relacionado (ex. corte limpo + a versão sobreposta) — NÃO execute novamente a escolha de duas fases por clipe.
  • Corrigir, depois estilizar. A base é a generalização da etapa S-Log3→Rec.709 do deck. Para filmagem normal, a base é WB+exposição+contraste; para filmagem log, coloque a conversão lá.
  • Pele primeiro. teal_orange/cool_desat são os usuais ofensores de pele em sujeitos mais escuros — mantenha os médios quentes, tinga sombras/realces/fundo, use vibrancia. Não neutralize U/V completamente.
  • Etiquetas são PNGs PIL sobrepostos por ffmpeg — nunca drawtext. No Windows o caminho fontfile do drawtext (dois-pontos da unidade) é não confiável. As fontes são definidas no topo de gradelib.py.
  • Caminhos com dois-pontos de unidade quebram opções do filtergraph do ffmpeg que aceitam um caminho (lut3d, metadata=print:file=). Os scripts executam ffmpeg com cwd = a pasta do arquivo e referenciam pelo nome base. Mantenha este padrão para qualquer novo filtro que aceite caminho.
  • Os resultados caem nos diretórios --out que você passa (duráveis), não em um diretório temporário do sistema.
  • A faixa de rosto/pele usa um corte fixo centralizado no terço superior, não detecção de rosto. Se o sujeito não estiver aproximadamente centralizado, passe --face-crop L:A:X:Y para render_looks.py ou a faixa de pele mostrará a região errada.
  • O frame de verificação de apply_grade.py está a 20% da duração — um frame diferente daquele em que os looks foram escolhidos. Se esse ponto de 20% estiver sem rosto, inspecione a pele em outro frame (ou passe --frame-time para assess.py para que o frame escolhido seja um momento de rosto conhecido).
  • A gravação do LUT é exata, porque cada filtro aqui é uma operação ponto a ponto por pixel: bake_lut.py empurra uma grade de identidade 33³ através da cadeia real e auto-verifica contra ela (mean|d| deve estar bem abaixo de 1/255; um max|d| de alguns níveis é apenas interpolação).
  • Seleção antes da entrega, sempre. A escolha humana e a escolha delegada do agente são ambas válidas, mas o plano deve registrar qual ocorreu e por quê.

Individual skills in this repo

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

Habilidades Relacionadas