Communitygithub.com

muyunxue/dance-mmd-subtitle-kit

Gradación de color con conciencia de sujeto para videos de baile MMD en este espacio de trabajo — realza al bailarín (fondo oscuro/frío/desaturado, sujeto iluminado/cálido/afilado/brillante) usando una elipse de luz suave o una máscara de personaje dura, con recetas de ffmpeg, conjuntos de parámetros medidos y modos de fallo conocidos.

¿Qué es dance-mmd-subtitle-kit?

Este skill proporciona un flujo de trabajo completo para la gradación de color de videos de baile MMD, centrado en aislar y realzar al bailarín mientras se oscurece el fondo. Ofrece dos enfoques principales: el método recomendado de 'elipse de luz suave' (ruta A), que aplica una máscara radial para iluminar al sujeto y oscurecer el fondo con transiciones suaves, y un método de 'enmascaramiento por diferencia de fotogramas' (ruta B), más complejo pero potencialmente de mayor calidad, que requiere una placa de fondo limpia. El skill incluye scripts de Python y ffmpeg para generar máscaras, aplicar gradaciones y verificar resultados, junto con conjuntos de parámetros prediseñados y documentación detallada de los modos de fallo, como la contaminación por sombras proyectadas y el bandeado de 8 bits. Está diseñado para ser utilizado en este espacio de trabajo específico, con rutas de archivo y configuraciones predefinidas para una resolución de 2560×1080.

Compatible con~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/muyunxue/dance-mmd-subtitle-kit/tree/HEAD/skills/subject-color-grade

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Documentación

Percepción del sujeto MMD para gradación de color (realzar el personaje)

0. Conclusión primero

  • Para que un video de escenario MMD "realce al personaje", hay dos caminos:
    1. Modelado de zona de luz (recomendado, limpio): Un gradiente radial/suave elíptico centrado en el personaje — dentro de la elipse, el personaje se ilumina/calienta/agudiza/brilla; fuera, el fondo se oscurece/enfría/desatura/desenfoca ligeramente; el borde de transición es muy amplio, casi no se ve el círculo.
    2. Separación con máscara dura (límite más alto pero sucio): Se toma una placa de fondo con diferencia de fotogramas para obtener una máscara del personaje, y luego se gradúa por separado el personaje y el fondo para recomponerlos. La dificultad es que la sombra proyectada (cast shadow) se mueve con el personaje y está conectada a él, por lo que la máscara arrastra grandes áreas de sombra → aparecen manchas brillantes; si se erosiona forzadamente, se dañan alas y plumas.
  • Solo para el producto final, elige la opción 1; cuando sea posible renderizar desde Blender/MMD una capa de personaje con canal alfa, elige la opción 2 (máxima calidad).

1. Materiales y herramientas

ElementoRuta
Video fuenteD:\mmd.mp4\0002-4956.mkv (completo 165.166s) / subtítulos\0001-4956 - copia.mkv (truncado a ~137s)
Scripts de gradaciónsubtítulos\build\grade_ffmpeg.py (zona de luz/luz suave), grade_final5s.py (parámetros del producto final 5s), color_grade.py (enmascaramiento por diferencia de fotogramas, versión antigua), gothic_art.py (gradación gótica para fotogramas estáticos)
Scripts de verificaciónavoid_layout.py (análisis de ocupación), avoid_side2.py (ocupación+bbox)
ffmpegC:\Users\35530\AppData\Local\Microsoft\WinGet\Packages\Gyan.FFmpeg_Microsoft.Winget.Source_8wekyb3d8bbwe\ffmpeg-9.0-full_build\bin\ffmpeg.exe
PythonC:\Users\35530\.dsh\dsh-runtimes\dsh-primary-runtime\dependencies\python\python.exe (PIL/numpy, sin cv2/aprendizaje profundo)

2. Ruta A: Modelado de zona de luz (enfoque predeterminado de este proyecto)

2.1 Generar máscara de luz suave (PNG único)

import numpy as np
from PIL import Image
W,H = 2560,1080
yy,xx = np.mgrid[0:H,0:W].astype(np.float32)
cx,cy = 0.515,0.565          # centro del personaje (en composición vertical 2560x1080 aproximadamente aquí; para otro video, verificar con un fotograma primero)
rx,ry = 0.245,0.47           # semiancho/semialto (proporción); demasiado pequeño se nota el círculo, demasiado grande no hay separación
q = ((xx-W*cx)/(W*rx))**2 + ((yy-H*cy)/(H*ry))**2
mask = np.clip(1.0-q,0,1)**0.55          # 0.5–0.7 es más suave
Image.fromarray((mask*255).astype(np.uint8)).save("_mask_final.png")

Referencia de productos: subtítulos\salida\pruebas_gradación\_mask_final.png, subtítulos\salida\muestra_subtítulos\_mask_final.png.

2.2 Composición con ffmpeg (personaje realzado + fondo oscurecido)

Idea: Versión del personaje graduada + versión del fondo graduada, combinadas con la máscara como canal alfa:

[0:v]split=2[sv][bv];
[sv]eq=brightness=0.050:contrast=1.06:saturation=1.15,
    colorbalance=rs=0.02:bs=-0.02:rm=0.05:bm=-0.06:rh=0.02:bh=-0.02,
    split=2[sm][sh];[sh]gblur=sigma=14[blur];
    [sm][blur]blend=all_mode=screen:all_opacity=0.34[sub];
    [sub]format=yuva420p[suba];
[1:v]format=gray[gm];[suba][gm]alphamerge[subj];
[bv]eq=brightness=-0.045:contrast=1.07:saturation=0.87,
    colorbalance=rm=-0.03:bm=0.05,gblur=sigma=0.6[bg];
[bg][subj]overlay=0:0,format=yuv420p[v]

Comando:

& $ff -v error -y -ss 36.5 -t 30 -i src.mkv -loop 1 -i _mask_final.png `
  -filter_complex "<graph de arriba>" -map "[v]" -t 30 `
  -c:v libx264 -preset medium -crf 16 -pix_fmt yuv420p OUT.mp4

Nota: Con -loop 1 -i mask.png, la máscara es un flujo estático; después de overlay, recuerda limitar la duración con -t. Significado de parámetros: bg brightness negativo = oscurecer, saturation<1 = desaturar, bm>0 = fondo azulado (frío), gblur = ligero desenfoque; subj incluye brightness/saturación/colores cálidos/blend screen para brillo.

2.3 Conjuntos de parámetros medidos (2560×1080, escenario MMD violeta)

Perfilbg brightnessbg satsubj gainsubj satbloomvignetteEfecto
A Natural−0.0350.82+0.0301.080.200.30Realza ligeramente al personaje, casi no cambia la atmósfera
B Mejorado−0.0750.70+0.0551.160.340.42Separación clara, el borde de la zona de luz apenas visible
Dirección final−0.0850.68+0.0501.150.300.38Luz suave muy amplia, recomendado como base para todo el video

Prueba parámetros en 5s, y una vez satisfecho, aplícalos directamente a 30s/todo el video (ffmpeg procesa todo de una vez, más rápido que fotograma por fotograma en Python).

3. Ruta B: Máscara dura (cuando se necesita una máscara más limpia)

3.1 Placa de fondo

  • Extrae fotogramas de muestra de 1/2s de todo el video, redimensiona a 1280×540, mediana píxel a píxel = placa de fondo bg_half.npy.
  • Comando/revisión: subtítulos\build\color_grade.py, función build_background().
  • Problema conocido: Cuando el personaje permanece en el centro durante mucho tiempo, la mediana se contamina con el personaje (ciertos píxeles en el cuerpo del personaje son a menudo del personaje) → la diferencia de fotogramas da valores pequeños en el torso → la máscara tiene agujeros. Usa fill_holes o bbox como respaldo.

3.2 Máscara por diferencia de fotogramas (resolución 1/4, más rápida)

m = |frame_q - bg_q|.max(axis=2) > 38
m = MaxFilter(5) (dilatar) → componente conectada más grande → opcional: rellenar agujeros/desenfocar
  • Se usa para análisis de ocupación/evitación (ver avoid-subtitles); para gradación, es necesario añadir una restricción de "similitud con el personaje", de lo contrario se mezclan sombras y manchas de luz.

3.3 Modos de fallo conocidos (medidos en este proyecto)

  • Contaminación por sombra: La sombra del personaje se mueve con él, la máscara se vuelve contigua → aparecen manchas brillantes/bloques de color alrededor del personaje tras la gradación. Solución: No usar diferencia de fotogramas como máscara precisa; o aceptar "iluminar también la sombra" (muy extraño), o volver al modelado de zona de luz.
  • Contaminación de fondo por mediana: Agujeros en la máscara donde el personaje está quieto → el torso no se gradúa, apareciendo manchas. Solución: Rellenar agujeros/usar bbox.
  • Bandeado de 8 bits: Al ajustar mucho el color, aparecen bandas en el cielo/gradientes → añadir 1–3 niveles de granulado (ffmpeg noise=alls=6:allf=t+u) o salida a 10 bits/HEVC.
  • Contraste de subtítulos: Al oscurecer el fondo, los textos blancos se ven más claros; si se oscurece demasiado, el personaje también se oscurece, por lo que hay que realzarlo o añadir bloom.

4. Gradaciones estilizadas (gótica/neón, para fotogramas estáticos)

  • Gótico rojo-negro (ya descartado por el usuario, solo para archivo): subtítulos\build\gothic_art.py, función gothic_grade(): oscurecer 0.42–0.52, desaturar 0.30–0.42, tonos medios violeta/rojo, viñeta fuerte, niebla.
  • Paleta de colores temática (la que el usuario finalmente quiere): blanco/hueso como principal + lavanda/violeta/rosa fucsia brillo, fondo oscuro a violeta-negro; ver constantes en gothic_art.py (BLOOD/LAV/PINK/VIOLET).
  • Versión neón: neon_wide.py (dibuja neón directamente con ASS, sin necesidad de gradación).
  • Aplicación rápida de color: Con la tríada eq + colorbalance + vignette se puede convertir el escenario violeta a cualquier tono:
    • Azul frío: colorbalance=bs=0.10:bm=0.12 (desplazar a azul), desaturar;
    • Fuego cálido: colorbalance=rs=0.10:rm=0.08, eq=saturation=1.1.

5. Lista de verificación

  • Tomar 3–5 fotogramas: ¿Es natural la separación entre brillo del personaje y fondo? ¿Hay un círculo evidente en el borde de la zona de luz?
  • Primeros planos/primerísimos planos: ¿La cara está sobreexpuesta? ¿El tono de piel está alterado?
  • ¿Hay negros muertos/bandeado en las sombras (8 bits)?
  • Vista con subtítulos: ¿El texto blanco es lo suficientemente claro?
  • Verificar con ffprobe que duración/fotogramas por segundo sean correctos; para salida a 10 bits usar -pix_fmt yuv420p10le -c:v libx265

6. Recursos

  • Parámetros y comparación del producto final de 5s: subtítulos\salida\pruebas_gradación\ (A Natural/B Mejorado/Dirección final + videos de comparación)
  • Base de 30s: subtítulos\salida\S4S6_30s\_base_30s.mp4 (solo ligeramente oscurecido, sin gradación completa)
  • Direcciones probadas anteriormente pero descartadas: Gótico (subtítulos\salida\diseño_subtítulos\G1…G3), FLARE, Neón (subtítulos\salida\muestra_subtítulos) — se archivan como referencia de parámetros.

Individual skills in this repo

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

muyunxue/dance-mmd-subtitle-kit

Hard rules, templates, ffmpeg commands and failure diagnosis for authoring ASS/SSA subtitles and burning them with libass on this machine. Load this before writing any ASS file, when a burn "succeeds" but no text appears, when text is misplaced/too big, when \p1 drawings are offset, or when you need the transparent-overlay export recipe. Contains the exact pitfalls hit in this project (timestamp format, style colour trailing ampersand, fontsdir, drawing anchor, chained \t, Permanent Marker sizing).

muyunxue/dance-mmd-subtitle-kit

Character-avoiding subtitle layout for the MMD dance videos — measure the dancer's per-frame bounding box, compute a per-cue union, place text in safe side/top columns, and verify zero overlap on every frame. Load this when asked 字幕不要挡住人物/完全不挡/避让, or when text overlaps wings/body and you need a verified-free layout with measured overlap counts.

muyunxue/dance-mmd-subtitle-kit

End-to-end recipe for making subtitles for the MMD dance videos in this workspace (字幕/ project) — probe the source, pick a segment, map LRC cues, choose a style, build ASS, burn, verify, and deliver. Load this when starting or resuming any subtitle task (静态稿/5s小样/30s小样/全片/透明叠加层), when a render "succeeded" but the video has no text, or when you need this project's paths, font list, cue sheet and acceptance criteria.

muyunxue/dance-mmd-subtitle-kit

Design and deliver subtitle style mockups and animated comparison samples for the MMD/K-pop dance videos — S1–S6 style catalogue (Y2K chrome, minimal kinetic, glitch, mix&match editorial, graphic emphasis, hand-marker), PIL/numpy effect recipes, font list, contact-sheet/comparison video conventions, and the parallel-subagent workflow used for S4 vs S6. Load this when asked 出几个静态帧方案/参考女团PV字幕/做个小样/对比几个风格, or when choosing a visual direction before building a full-length subtitle track.

Skills relacionados