La calidad perceptual y cómo elegirla sin ojo
Por qué calidad 80 no es una unidad, qué métricas correlacionan de verdad con el juicio humano, y el guion que busca la calidad mínima que alcanza tu objetivo en cada imagen.
El parámetro de calidad de un codificador no mide calidad: mide cuánto va a cuantizar, y cada codificador lo interpreta a su manera. Fijar un número global para todo el catálogo produce imágenes con artefactos visibles y otras con el triple de bytes de los necesarios, a la vez. La alternativa no es mirar cada imagen: es medirla con una métrica que correlacione con lo que ve una persona.
- Explicar por qué el mismo número de calidad da resultados distintos en cada codificador.
- Comparar las métricas de calidad por su correlación medida con el juicio humano.
- Interpretar la escala de SSIMULACRA 2 y elegir un objetivo por tipo de uso.
- Automatizar la búsqueda de la calidad mínima que alcanza ese objetivo.
Calidad 80 no es una unidad
El parámetro de calidad es un mando que controla la agresividad de la cuantización, y la relación entre ese mando y el resultado perceptual la define cada implementación. No hay ninguna norma que la fije.
El propio proyecto que mantiene la métrica de referencia publica las equivalencias, y son ilustrativas: una puntuación de 70, descrita como “calidad alta, artefactos perceptibles pero no molestos”, corresponde a la salida típica de un JPEG con crominancia reducida a calidad 70. Una puntuación de 90, “visualmente sin pérdida”, corresponde a un JPEG con crominancia completa a calidad 95. El mismo salto perceptual, de 70 a 90, se recorre en el mando de calidad de 70 a 95, y solo si además cambias el submuestreo de crominancia.
Cruza eso con tres codificadores distintos y con imágenes de contenido distinto y el resultado es el que se ve en cualquier catálogo real: la foto de producto sobre fondo blanco queda perfecta a calidad 50 y estás sirviéndola a 85, mientras que la fotografía con follaje y textura tiene bloques visibles a esa misma calidad 85.
El parámetro correcto no es global, es por imagen, y no se elige a ojo.
Por qué el ojo es mal instrumento
Cuatro razones, y todas empujan a comprimir menos de lo necesario.
Sabes dónde mirar. Has visto el original. Tu atención va directa a la zona que has tocado, que es precisamente donde el usuario nunca mira.
Comparas en paralelo. Poner las dos versiones una al lado de la otra es la prueba más dura que existe, y no es la que vive nadie. El usuario ve una imagen, sin referencia. La escala de la métrica distingue explícitamente esos escenarios: hay una puntuación para “indistinguible en comparación lado a lado” y otra, más alta, para “indistinguible en un test de parpadeo”.
Tu pantalla no es la suya. Un portátil calibrado a 400 nits en una habitación oscura muestra artefactos que un móvil al sol no puede mostrar.
Te adaptas. Después de veinte imágenes tu umbral se ha movido, y el criterio de la imagen veinte no es el de la primera.
Las métricas y su correlación medida
Aquí no hay que opinar: existen conjuntos de datos con decenas de miles de valoraciones humanas y cada métrica tiene su correlación medida contra ellos. Estos son los coeficientes de correlación de rango de Spearman sobre el conjunto de validación de CID22, que son 4.292 valoraciones subjetivas no usadas para ajustar ninguna métrica:
| Métrica | Correlación con el juicio humano | Dirección |
|---|---|---|
| SSIMULACRA 2.1 | 0,890 | Más alto es mejor |
| DSSIM | 0,872 | Más bajo es mejor |
| PSNR-HVS | 0,822 | Más alto es mejor |
| Butteraugli, norma 3 | 0,794 | Más bajo es mejor |
| VMAF | 0,788 | Más alto es mejor |
| SSIM | 0,787 | Más alto es mejor |
| MS-SSIM | 0,778 | Más alto es mejor |
| PSNR sobre luminancia | 0,658 | Más alto es mejor |
Las cifras están en valor absoluto; las métricas donde menos es mejor dan correlación negativa en la publicación original.
Qué es cada una, en una frase.
PSNR compara píxeles y nada más. Es la que sale por defecto en muchas herramientas y la que peor correlaciona: penaliza igual un error invisible en una zona texturada que un error obvio en un cielo liso.
SSIM y MS-SSIM comparan estructura local en varias escalas. Fueron un salto enorme sobre PSNR y no están diseñadas para artefactos de compresión concretos como el zumbido alrededor de los bordes.
Butteraugli estima la distancia psicovisual entre dos imágenes y está pensada para localizar el umbral de diferencia apenas perceptible. Es la que usan internamente varios codificadores como modo de ajuste.
DSSIM es una variante multiescala de SSIM, muy fácil de instalar y con una correlación notable.
SSIMULACRA 2 trabaja en un espacio de color perceptual, hace el escalado en luz lineal, y suma a la comparación estructural dos mapas de error asimétricos: uno que detecta que la imagen comprimida tiene bordes donde el original era liso, que es el zumbido y el bloqueo, y otro que detecta que es lisa donde el original tenía detalle, que es el emborronamiento. Calcula esos tres mapas en seis escalas y sobre tres componentes de color, y combina 108 valores en una puntuación. Es la que mejor correlaciona y la que conviene usar por defecto.
La escala, con su significado
El proyecto documenta la escala punto por punto, y merece la pena tenerla a mano porque convierte una puntuación en una decisión:
| Puntuación | Significado |
|---|---|
| 30 | Calidad baja. Artefactos obvios y molestos. |
| 50 | Calidad media. Artefactos ligeramente molestos. |
| 70 | Calidad alta. Artefactos perceptibles pero no molestos. Sin la referencia delante, un observador medio no los nota. |
| 80 | Calidad muy alta. Indistinguible en comparación lado a lado a escala 1:1. |
| 85 | Calidad excelente. Indistinguible en comparación superpuesta. |
| 90 | Visualmente sin pérdida. Indistinguible en un test de parpadeo. |
| 100 | Sin pérdida matemática. |
Los objetivos que funcionan en la práctica:
- 80 para la imagen del hero y para cualquier cosa grande que el usuario mire de frente.
- 70 para imágenes de contenido por debajo del pliegue y miniaturas grandes.
- 90 para imágenes que el usuario va a ampliar: fotografía de producto con zoom, obra gráfica, documentación técnica.
- Sin pérdida para capturas de interfaz con texto pequeño, donde cualquier artefacto se lee como un fallo de renderizado.
El guion que busca la calidad mínima
La idea es una búsqueda binaria sobre el mando de calidad: la puntuación crece de forma monótona con él, así que se puede encontrar el valor mínimo que alcanza tu objetivo en unas siete iteraciones.
#!/usr/bin/env bash
# Calidad AVIF minima que alcanza una puntuacion objetivo.
# Uso: ./calidad.sh original.png 80
set -euo pipefail
origen="$1"
objetivo="${2:-80}"
tmp=$(mktemp -d)
trap 'rm -rf "$tmp"' EXIT
bajo=20
alto=90
mejor=90
while [ "$bajo" -le "$alto" ]; do
medio=$(( (bajo + alto) / 2 ))
avifenc -q "$medio" -s 6 "$origen" "$tmp/p.avif" >/dev/null 2>&1
avifdec "$tmp/p.avif" "$tmp/p.png" >/dev/null 2>&1
nota=$(ssimulacra2 "$origen" "$tmp/p.png")
bytes=$(wc -c < "$tmp/p.avif")
printf 'q=%-3s nota=%-8s %s bytes\n' "$medio" "$nota" "$bytes"
if [ "$(echo "$nota >= $objetivo" | bc -l)" -eq 1 ]; then
mejor=$medio
alto=$(( medio - 1 ))
else
bajo=$(( medio + 1 ))
fi
done
echo "Calidad minima para alcanzar $objetivo: $mejor"
# Codificacion final con mas esfuerzo: mismo resultado, menos bytes.
avifenc -q "$mejor" -s 2 "$origen" "${origen%.*}.avif"
La última línea contiene una optimización que se suele pasar por alto. El parámetro de esfuerzo, que va de 0 a 10 con 6 por defecto y donde números más bajos significan más trabajo, no cambia la calidad perceptual del resultado: cambia cuánto busca el codificador antes de decidir. Usar esfuerzo bajo durante la búsqueda binaria, que hace siete codificaciones, y esfuerzo alto solo en la definitiva, da el mismo aspecto con menos bytes y sin multiplicar el tiempo total.
En una canalización de compilación en Node, el mismo criterio con la librería habitual de procesamiento de imágenes:
import sharp from 'sharp';
// La calidad viene de la busqueda previa, no de una constante global.
await sharp('hero.png')
.resize({ width: 1600 })
.avif({ quality: 58, effort: 8, chromaSubsampling: '4:4:4' })
.toFile('hero-1600.avif');
Reducir la resolución del color a la mitad ahorra bytes y es invisible en fotografía, que es para lo que se diseñó. Deja de ser invisible en cuanto hay bordes de color saturado: texto rojo sobre azul, gráficos de líneas finas, logotipos sobre fondo de color. Si tu imagen tiene ese contenido y la puntuación no sube por mucha calidad que le des, el problema no es la calidad, es el submuestreo. En AVIF se desactiva con crominancia completa; en JPEG, con la opción equivalente del codificador. En WebP con pérdida no se puede desactivar: siempre reduce la crominancia, y ese es un motivo concreto para preferir AVIF en imágenes con color saturado y bordes duros.
Ponerlo en la canalización
Tres reglas que convierten esto en algo mantenible.
Guarda la calidad calculada junto a la imagen, no la recalcules en cada compilación. La búsqueda binaria son siete codificaciones; en un catálogo grande eso es tiempo de CPU que solo hay que gastar una vez por imagen original.
Falla la compilación si una imagen no alcanza el objetivo ni siquiera a calidad máxima. Suele significar que el original ya venía comprimido con pérdida y estás recomprimiendo, que es la forma más eficaz de acumular artefactos. La solución es conseguir el original, no subir la calidad.
Mide también el resultado en bytes y ponle un techo. Una imagen que necesita calidad 90 para llegar a 80 de puntuación y acaba pesando 900 KB no es un problema de compresión: es un problema de contenido, y probablemente haya que reducir sus dimensiones antes de codificarla.
Todas estas métricas comparan dos imágenes píxel a píxel a la resolución en la que se las das, y esa resolución es la del archivo. Pero en un dispositivo con densidad de pantalla alta tú sirves una imagen de 1.600 píxeles de ancho para un hueco de 800 puntos de CSS, así que el navegador la reduce a la mitad antes de mostrarla, y ese reescalado destruye buena parte de los artefactos de compresión antes de que lleguen al ojo. Consecuencia directa: la puntuación que necesitas en una imagen que se va a mostrar al cincuenta por ciento de su tamaño es sensiblemente más baja que la que necesitas en una que se muestra a tamaño real, y aplicar el mismo objetivo a las dos significa gastar bytes en detalle que se descarta en el propio navegador. La forma rigurosa de tenerlo en cuenta es medir la puntuación sobre las dos imágenes reducidas al tamaño de presentación, original y comprimida, en lugar de sobre los archivos completos, que es exactamente lo que hace la métrica internamente en sus escalas menores pero ponderado con las mayores. En catálogos donde lo he visto aplicar, bajar el objetivo de 85 a 75 en las variantes de mayor densidad, que son las que solo se ven reducidas, recorta entre un tercio y la mitad de los bytes sin que nadie note nada, porque literalmente no hay nada que notar. Y explica una observación que desconcierta a quien empieza con esto: que una imagen con peor puntuación se vea mejor en el móvil que otra con mejor puntuación, porque lo que decide no es la puntuación del archivo sino la del resultado en pantalla.