¿Los códigos QR fotográficos realmente funcionan? Nuestros resultados de prueba de decodificación
Un código QR que es una fotografía suena como si debe escanear peor. Medimos el nuestro con un decodificador real — desenfocado, reducido, y leído de la manera en que un lector lee.
Novedades aquí: Resultados de prueba de decodificación de nuestra implementación de código QR fotográfico, medidos con jsQR contra un código de control simple: cero de 4.225 módulos mal leídos en cada apertura de lector de 0,10 a 0,45 módulos, tolerancia de escala de 3x idéntica, y una tolerancia de desenfoque de 4-5 píxeles contra los 6 del código simple — el costo específico y pequeño de convertir un código en una imagen.
Un código QR que es una fotografía parece que debe ser un compromiso: bonito, pero pierdes algunos escaneos. Esa intuición es correcta en la mayoría de las implementaciones e incorrecta sobre cómo debe funcionar, y “algunos escaneos” no es un número que nadie publique.
Aquí están los nuestros, de la suite de pruebas que tuvo que pasar antes de que enviáramos la característica en absoluto.
# Qué es un código QR de fotografía y qué no es
Dos cosas muy diferentes se llaman de la misma manera.
Arte QR con IA — el tipo basado en modelos de difusión — genera una imagen condicionada a un código QR y luego espera que el resultado siga decodificándose. A veces funciona. El modo de fallo es invisible hasta que alguien en un bar oscuro apunta un teléfono antiguo hacia él.
Un código de fotografía tramada es el otro enfoque y el que se mide aquí. La imagen se reduce a un bit — blanco o negro por subpíxel — mediante difusión de error, con una restricción crucial: en cada centro de módulo, la trama se fuerza al valor que el codificador exige, y el error que crea esta fuerza (aproximadamente el 95% del valor de un píxel, para un módulo blanco en una región oscura) se empuja hacia los subpíxeles vecinos que aún no han sido umbralados. La imagen está hecha del espacio entre los centros de módulos.
Esa distinción es todo el artículo. Significa que el código no gasta su corrección de errores en decoración: cada módulo sigue llevando el valor que el codificador exige, por lo que toda la redundancia permanece intacta para pliegues, deslumbramientos, un pulgar sobre una esquina — las cosas para las que realmente existe la corrección de errores.
# La prueba
Todo lo siguiente es reproducible desde nuestro repositorio, sin conexión:
- Codificador: nuestro propio
packages/qr, corrección de errores H, piso de densidadminVersion: 12→ versión de símbolo 12, 65 módulos de ancho, 10 píxeles por módulo, zona tranquila de 4 módulos. - Estilos: tramado (una fotografía verdaderamente tramada) y mosaico (solo se dibujan los módulos, dimensionados por la oscuridad local), contra un código sin tramado plano como control — mismo carga útil, misma versión, misma escala.
- Imágenes: imágenes de prueba procedimentales, incluido un gradiente diagonal (aparece cada tono) y gris medio plano, que es el peor caso porque cada punto forzado no está de acuerdo con sus alrededores.
- Decodificador: jsQR 1.4.0, un decodificador QR real, dado los píxeles reales.
- Degradaciones: reducción de escala de vecino más cercano, desenfoque de caja seguido de umbralización (una cámara desenfocada), y una lectura de abertura.
La suite en la que se construye es packages/qr/test/dither.test.js. Funcionó 39/39
pasando el 2026-08-31, y un código que no decodifica es una prueba fallida en lugar
de una advertencia — esa regla es por qué la característica existe en la forma que tiene. Las
tablas a continuación se imprimen mediante draft/mostlyqr/seo/benchmarks/photo.js, que ejecuta
los mismos estilos a través de las mismas degradaciones; nada aquí fue transcrito.
# Cero módulos malinterpretados, en cada abertura
La medición que más importa no es “¿se decodificó?” sino “¿el lector vio el valor correcto en cada celda?”, porque un código que se decodifica solo porque la corrección de errores lo rescató es un código que fallará cuando algo más salga mal.
Un lector conforme no muestrea un píxel por módulo. Promedia una pequeña abertura circular en cada centro de módulo y umbrala ese promedio. Así que hicimos lo mismo, en radios de abertura de 0.10, 0.25, 0.36 y 0.45 módulos (0.5 sería el módulo completo), y contamos cuántos de los 4,225 módulos se leerían mal:
| Estilo | Módulos malinterpretados, abertura 0.10 / 0.25 / 0.36 / 0.45 |
|---|---|
| código plano (control) | 0 / 0 / 0 / 0 |
| foto mosaico | 0 / 0 / 0 / 0 |
| foto tramada (gradiente) | 0 / 0 / 0 / 0 |
| foto tramada (gris medio plano, peor caso) | 0 / 0 / 0 / 0 |
Ni un módulo, en ningún estilo, en ninguna abertura, incluida la imagen del peor caso. El código de fotografía y el código plano presentan al lector los mismos valores. La corrección de errores no se toca y sigue siendo completamente disponible.
# Lo que cuesta: aproximadamente un paso de desenfoque
La corrección de errores sin tocar no significa idéntica. El tramado sí cambia lo que los píxeles se ven entre los centros, y una cámara muy desenfocada promedian esos píxeles. Así que empujamos cada estilo hasta que se rompió:
| Estilo | Máxima reducción de escala que aún se decodificaba | Máximo radio de desenfoque que aún se decodificaba |
|---|---|---|
| código plano (control) | 3× | 6 px |
| foto mosaico | 3× | 5 px |
| foto tramada (gris medio plano) | 3× | 6 px |
| foto tramada (gradiente) | 3× | 4 px |
La reducción de escala — el código renderizado más pequeño que el tamaño nativo — es idéntica en todos los estilos: cada uno sobrevivió 3× y cada uno falló por primera vez en 4×. (La reducción de escala de vecino más cercano no es monótona — algunos de ellos se decodificaron nuevamente en 5×, donde la red de muestreo sucedió aterrizando más amablemente — así que la cifra que reportamos es la primera falla, no el último éxito.)
El desenfoque es donde se ve el costo, y solo para el estilo tramado en la imagen más difícil: un tercio menos de margen que el control plano. El tramado de un campo gris medio plano coincidió exactamente con el código plano, así que este es un costo dependiente de la imagen en lugar de una propiedad de la técnica. En términos simples: un código de fotografía necesita que la cámara esté aproximadamente un paso más cerca del enfoque que un código plano. Ese es un costo real y es uno pequeño, y es la respuesta honesta a “¿se escanean?” — no “sí” y no “no” sino “sí, con aproximadamente un paso menos de tolerancia de enfoque”.
El estilo mosaico se sitúa entre los dos, lo que tiene sentido: solo dibuja los módulos, así que hay menos tinta entre los centros para que un desenfoque difumine.
# Por qué la densidad es el requisito real
La primera versión de esta característica era técnicamente correcta y se veía mal, por una razón que vale la pena saber si usas cualquier herramienta de QR de foto:
https://mqr.sh/AB12CD con corrección de errores H — que es lo que un código de fotografía fuerza
— se codifica en una cuadrícula de 29 módulos. Esos son 841 celdas para una fotografía completa, y
el resultado se lee como ruido en lugar de como una imagen: las personas concluyen que la técnica
está rota cuando el problema real es que no hay lugar para que la imagen viva.
Forzar un símbolo más denso lo soluciona:
| Versión mínima | Símbolo | Módulos de ancho | Celdas disponibles para la imagen |
|---|---|---|---|
| ninguna (lo que la carga útil necesita) | v3 | 29 | 841 |
| 8 | v8 | 49 | 2,401 |
| 12 (nuestro predeterminado) | v12 | 65 | 4,225 |
Cinco veces las celdas en la versión 12. Cada herramienta de imagen-QR seria fuerza esto hacia arriba por la misma razón, y el piso nunca debe reducir un símbolo por debajo de lo que la carga útil realmente necesita — los datos ganan sobre la densidad, siempre.
La consecuencia para la impresión es directa, y es la razón por la que este artículo se sitúa en el mismo grupo que cuántos módulos necesita tu carga útil: un código de 65 módulos necesita 73 anchos de módulo de papel incluida su zona tranquila. En un módulo de 0.5mm eso es 36.5mm — así que un código de fotografía es un póster, un menú, un panel de empaque o una pantalla. No es una tarjeta de visita.
# Lo que la prueba no cubre
Dicho claramente, porque un punto de referencia con límites no declarados es peor que ninguno:
- Un decodificador, píxeles sintéticos. jsQR es un decodificador real pero no es una pila de cámara de teléfono, y la entrada es salida renderizada limpia en lugar de una fotografía de algo impreso.
- Sin impresión, sin deslumbramientos, sin perspectiva, sin arrugas. Cada uno de esos cuesta margen, y cuestan a un código de fotografía y a un código plano de manera diferente.
- Sin color. Estos son códigos en blanco y negro de 1 bit.
- Nuestra propia implementación. Nada aquí dice nada sobre los códigos QR de fotografía o arte con IA de nadie más. Si sobrescriben módulos y se apoyan en la corrección de errores para reparar el daño, se comportarán de manera completamente diferente a esto, y la prueba justa es la de arriba ejecutada en su contra.
# Cuándo usar uno
- Sí: pósters, menús bajo vidrio, paneles de empaque, pantallas, gráficos de exhibición, cualquier cosa impresa grande.
- Probablemente: una portada de álbum, una cubierta de libro, una etiqueta de producto grande — pruébala.
- No: tarjetas de visita, volantes de papel que se pliegan, cualquier cosa bajo aproximadamente 35mm, cualquier cosa escaneada con poca luz a distancia.
Y si lo que quieres no es una fotografía completa sino tu logotipo en el medio de un código ordinario, eso es una técnica diferente con un presupuesto mucho más pequeño — también medimos cuán grande puede ser un logotipo y la respuesta es más pequeña de lo que internet piensa.
Los códigos de fotografía de MostlyQR son la implementación medida aquí. El mismo núcleo de tramado se ejecuta en la vista previa del navegador y en el PNG renderizado por el servidor, así que lo que ves en el constructor es lo que obtiene la impresora. La nota propia del constructor dice “mejor en pantallas e impresiones grandes — un código de fotografía es una lectura más difícil en papel pequeño o arrugado”, que después de estos números parece ser lo correcto que se debe decir.
Preguntas frecuentes
¿Los códigos QR fotográficos escanean de manera confiable?
En nuestras propias pruebas, sí — con un costo medible. Leyendo nuestros códigos fotográficos de la manera que lo hace un lector conforme, promediando una apertura circular en cada centro de módulo, ninguno de los 4.225 módulos fue mal leído en ninguna apertura que probamos. Toleraban la misma escala de 3x que un código simple. La única diferencia medida fue el desenfoque, y solo en la imagen más difícil: el control simple sobrevivió a un radio de desenfoque de 6 píxeles, el estilo mosaico 5, y el estilo semitonos 4 en un gradiente (6 en gris plano). Esto es aproximadamente un paso de enfoque de cámara, no una categoría diferente de confiabilidad.
¿Los códigos QR artísticos agotan la corrección de errores?
Muchas implementaciones lo hacen, por eso la técnica tiene mala reputación. La nuestra no. En lugar de sobrescribir módulos completos con datos de imagen y confiar en Reed-Solomon para reparar la diferencia, fuerza un punto en cada centro de módulo al valor que el codificador exige y difunde el error resultante en los subpíxeles circundantes. La imagen se paga del espacio entre centros de módulos, por lo que el presupuesto completo de corrección de errores sigue ahí para el mundo real — para arrugas, brillo y un pulgar sobre la esquina.
¿Puedo imprimir un código QR fotográfico en un volante?
Nosotros no lo haríamos. Nuestro propio constructor dice "mejor en pantallas e impresiones grandes", y lo decimos en serio: un código fotográfico necesita un símbolo denso (65 módulos de ancho en la prueba de abajo, contra 29 para el mismo enlace corto sin forzar), por lo que en el tamaño de un volante cada módulo se vuelve muy pequeño muy rápidamente. Carteles, menús bajo vidrio, paneles de empaque y pantallas son los lugares correctos. Un volante de papel que se dobla en un bolsillo no lo es.
¿Por qué mi código QR fotográfico se parece más a ruido que a una imagen?
Casi siempre porque el símbolo es demasiado grueso. Un enlace corto con corrección de errores H se codifica en una cuadrícula de 29 módulos — 841 celdas, demasiado pocas para llevar una imagen reconocible, por lo que la imagen no tiene dónde vivir. Forzar un símbolo más denso lo arregla: la versión 8 da 49 módulos y la versión 12 da 65 (4.225 celdas, cinco veces más), y nuestro constructor por defecto a la versión 12 para códigos fotográficos exactamente por esta razón. Los datos siempre ganan, por lo que una carga útil más larga aún obtiene un símbolo más grande.
- ¿Qué tan grande puede ser el logotipo en un código QR? Lo medimos"Corrección de errores del 30%" no es un presupuesto de logotipo. Hicimos agujeros cada vez más grandes en códigos en cada nivel de EC hasta que un decodificador real se rindió, y registramos dónde se rompió.
- ¿Qué tan pequeño puede imprimirse un código QR? Los tamaños, calculadosNo hay un único tamaño mínimo para un código QR. Ejecutamos cinco cargas útiles reales a través de nuestro propio codificador para los recuentos de módulos, luego los convertimos a milímetros.