Blog / Ingeniería

Los PNG transparentes rompen los ampliadores con IA: el halo oscuro

· estudio de un error, con el arreglo medido · sujeto: el pipeline ×4 de producción

Dale un PNG con transparencia (una foto recortada, una exportación de sticker) a casi cualquier ampliador con IA y aparece un defecto concreto: un halo oscuro que se cuela unos píxeles hacia dentro del sujeto desde cada borde transparente, con un tenue anillo claro de sobreimpulso detrás. Se esconde en las vistas previas oscuras y salta a la vista en las páginas blancas. Lo reprodujimos en nuestro propio pipeline, medimos su forma exacta (un surco de −94 de luma, tres píxeles de modelo de ancho), lo rastreamos hasta el viaje de ida y vuelta del alfa premultiplicado de la plataforma web, y medimos el arreglo que publicamos: un relleno por inundación O(n) que elimina el 98% del error antes de que el modelo llegue a ejecutarse.

−93.9error de luma, primer anillo de píxelesruta ingenua frente a referencia limpia
≈3 pxancho del surco a escala de modeloy después un anillo de sobreimpulso de +17
63×reducción del error con el arreglo−62.9 → 1.1 de media, banda de 0–3 px
O(n)coste del arreglouna pasada BFS, sin inferencia extra

Cada cifra de esta nota se midió con el código del pipeline de producción: los mismos modelos, las mismas matemáticas. Registros brutos por imagen: e3_alpha.json.

1 · De dónde sale el negro

El canvas 2D de la web almacena los píxeles premultiplicados: no (r, g, b, α), sino (rα, gα, bα, α). A la composición le encanta este formato (los operadores de Porter–Duff[1] se convierten en simples multiplicaciones y sumas), pero es lossy en exactamente un lugar. Leer los píxeles de vuelta significa dividir el color entre α:

r = ⌊ rα / α ⌉, no definido en α = 0(1)

En α = 0 eso es 0/0, y la respuesta de la plataforma[2] es que no queda nada que recuperar: el color se multiplicó por cero en el momento en que tocó el canvas. getImageData devuelve RGB (0, 0, 0) bajo cada píxel completamente transparente. El campo transparente de tu recorte se ha convertido silenciosamente en un lago de negro puro.

Un humano nunca ve el lago: el alfa lo oculta. Una red de superresolución no es un humano: consume tres canales de RGB y ningún alfa, así que ve una fotografía incrustada en negro absoluto, y cada píxel de salida cercano al borde se calcula a partir de un campo receptivo que se sumerge en el lago. El negro no se queda quieto; se difunde hacia dentro a través de la pila de convoluciones[3].

2 · Medir el halo

ingenua (RGB=0 del canvas)sangrado de alfa (el nuestro)
-100-75-50-2502513581216distancia L1 hacia dentro del sujeto (px, escala de modelo)Δ luma frente a la referenciaperfecto
Figura 1. El halo, perfilado. Ruta ingenua (violeta): un surco de −94 de luma en el primer anillo de píxeles dentro del sujeto, −90 a 2 px, −54 a 3 px, y luego un anillo de sobreimpulso de +17 a 5 px que decae a cero hacia los ~13 px; contaminación oscura a través de un campo receptivo finito, afilada por la GAN hasta convertirse en un borde. Ruta de producción (verde): nunca peor que 1.5 niveles de luma. Distancias a escala de modelo; ×4 para píxeles de salida.
Tres paneles: la entrada recortada mostrada sobre un tablero de ajedrez, la ampliación ingenua con un borde oscuro alrededor del óvalo y la ampliación limpia con sangrado de alfa
Figura 2. Entrada con transparencia (izquierda), ruta ingenua (centro), ruta de producción (derecha), compuestas sobre un fondo claro. El borde del panel central se lee como un sutil “borde sucio” a tamaño de miniatura, que es exactamente la razón por la que este error se publica tan a menudo: se esconde hasta que un usuario pone el sticker sobre un fondo claro.

Una medición genuinamente contraintuitiva: esperábamos que el modelo alucinara basura dentro de la región transparente, que “mejorara el vacío”. No lo hace. Negro plano dentro, negro plano fuera (energía de gradiente 0.1). El daño no es lo que el modelo inventa en el vacío; es lo que el vacío le hace al sujeto a través del borde. Eso importa porque significa que enmascarar la salida no puede salvarte: los píxeles dañados están dentro de la región visible, bajo α > 0.

3 · El arreglo: inundar el vacío con color plausible

Si el modelo debe ver RGB bajo α = 0, que sea un RGB que continúe al sujeto. Antes de la inferencia ejecutamos un sangrado de alfa: una inundación en anchura de múltiples fuentes desde cada píxel no transparente, en la que cada píxel transparente toma el color medio de sus 4-vecinos ya coloreados:

c(p) = media{ c(q) : q ∈ N₄(p), q coloreado }, p en orden BFS(2)

Sembrar la cola con el anillo del borde y procesar en orden FIFO garantiza que cada píxel extraído de la cola tiene al menos un vecino coloreado (quien lo encoló terminó antes), así que una sola pasada O(n) colorea todo el vacío: distancia ilimitada, huecos cerrados incluidos. Los bytes de alfa nunca se tocan; los píxeles semitransparentes conservan su propio color. El modelo ve entonces una continuación suave en lugar de un precipicio, y el alfa (ampliado por separado) se vuelve a aplicar a la salida. Efecto medido: el error de la banda de 0–3 px cae de -62.9 a 1.1 niveles de luma, una reducción de 63×, sin coste medible en tiempo de ejecución.

Detalle del borde de las reconstrucciones ingenua y con sangrado, más un mapa de calor de la diferencia amplificada que muestra el halo pegado al límite del alfa
Figura 3. Detalle del borde: la ruta ingenua (izquierda) junto a la ruta con sangrado (centro), y a la derecha la |diferencia| entre las dos reconstrucciones, amplificada ×8. El halo sigue el límite del alfa y nada más; lejos del borde las salidas son idénticas, que es el arreglo comportándose exactamente como se diseñó.

4 · Qué significa esto para tus imágenes

Si usas este sitio: nada; los PNG transparentes siguen la ruta medida más arriba tanto en el pipeline en la nube como en el motor de respaldo del navegador, ya que ambos comparten la misma biblioteca pura. Si construyes herramientas de imagen: trata a todo modelo solo RGB como alérgico a los ceros premultiplicados: sangra antes de la inferencia (la inundación de arriba son ~30 líneas sin dependencias), o compón sobre un color sólido y acepta el sesgo de ese fondo. Y si estás diagnosticando un misterioso borde oscuro en la salida del mejorador de alguien, ya conoces la huella: un surco de unos pocos píxeles de ancho, un anillo de sobreimpulso detrás y una correlación perfecta con el límite del alfa. Los tres números que recordar: −94, 3 px, 63×.

Referencias

  1. Porter, T., & Duff, T. (1984). Compositing Digital Images. SIGGRAPH '84, Computer Graphics 18(3), 253–259. (The premultiplied-alpha compositing algebra.) dl.acm.org
  2. WHATWG HTML Living Standard, the 2D canvas element: premultiplied backing stores and the lossy getImageData round-trip for non-opaque pixels. html.spec.whatwg.org
  3. Wang, X., Xie, L., Dong, C., & Shan, Y. (2021). Real-ESRGAN: Training Real-World Blind Super-Resolution with Pure Synthetic Data. ICCV Workshops. arXiv:2107.10833. arxiv.org
  4. Lange, D. (1936). “Migrant Mother” (Destitute pea pickers in California), Farm Security Administration. Public domain, via Wikimedia Commons. commons.wikimedia.org
  5. ONNX Runtime: the inference engine both our server (CPU) and in-browser (WebGPU/WASM) engines run on. onnxruntime.ai