PDI+VC · Ejercicio de Programación

EP06_08 — ⚫ Segmentación y Decodificación Real de QRCode con OpenCV

6.14.8 EP06_08 ⚫ Segmentación y Decodificación Real de QRCode con OpenCV

En los ejercicios anteriores, las magnitudes intermedias del pipeline de procesamiento de imágenes — como áreas, perímetros, varianzas y desplazamientos — se proporcionaron directamente o se calcularon a partir de matrices numéricas, sin necesidad de bibliotecas especializadas de Visión por Computador. En este ejercicio de cierre del capítulo, esta restricción se elimina de forma intencional: se utilizará la biblioteca OpenCV (cv2) para localizar y decodificar un QRCode real presente en una escena.

La propuesta reproduce un flujo simplificado de sistemas empleados en inspección visual, automatización industrial y lectura automática de documentos. Para mantener la entrada de datos accesible al contexto educativo, la carga de la imagen se integrará a la biblioteca didáctica morph, mediante la función mm.readImg.

La escena se proporciona en el formato PGM ASCII (P2) y contiene un único QRCode válido, además de diversos objetos distractores, como rectángulos, regiones de ruido texturizado y bloques aislados. La segmentación basada únicamente en propiedades geométricas — como área y forma aproximadamente cuadrada — es necesaria para reducir el espacio de búsqueda, pero no es suficiente para identificar el código correcto. La confirmación final se realizará exclusivamente mediante el intento de decodificación utilizando cv2.QRCodeDetector, procedimiento compatible con aplicaciones reales de reconocimiento automático.

6.14.8.1 📋 Directrices de Implementación

  1. Lectura de las dimensiones y parámetros

    Leer, en este orden, mediante la entrada estándar:

    • una línea que contenga el número de filas \(L\);
    • una línea que contenga el número de columnas \(C\);
    • una línea que contenga los cuatro parámetros del algoritmo separados por espacios:
      • umbral de binarización \(T\) (entero);
      • área mínima \(A_{\text{min}}\) (entero);
      • tolerancia de aspecto \(\text{tol}\) (real);
      • margen \(M\) (entero, en píxeles).
  2. Carga de la imagen

    Utilizar la función didáctica f = mm.readImg(L, C) para leer los \(L \times C\) valores de la imagen en tonos de gris, obteniendo un array de NumPy de tipo uint8.

  3. Binarización

    Aplicar umbralización binaria invertida utilizando el umbral \(T\). Todo píxel de la imagen original con intensidad estrictamente mayor que \(T\) debe convertirse a 255, mientras que los demás deben asumir el valor 0.

  4. Detección de contornos

    Extraer los componentes conectados externos utilizando cv2.findContours(...) con los parámetros:

    • cv2.RETR_EXTERNAL;
    • cv2.CHAIN_APPROX_SIMPLE.
  5. Filtrado geométrico

    Para cada contorno encontrado:

    • calcular el rectángulo delimitador (x, y, w, h) mediante cv2.boundingRect;

    • mantener únicamente los candidatos que satisfagan simultáneamente:

      Área mínima

      \[ w \times h > A_{\text{min}} \]

      Razón de aspecto

      \[ \left|\frac{w}{h}-1\right| \le \text{tol} \]

  6. Ordenación de los candidatos

    Ordenar los candidatos por el área del rectángulo delimitador

    \[ w \times h \]

    en orden descendente.

    En caso de empate, preservar el orden originalmente devuelto por cv2.findContours.

  7. Verificación por decodificación

    Para cada candidato, siguiendo el orden establecido:

    • expandir el rectángulo en \(M\) píxeles en las cuatro direcciones;
    • limitar los índices para permanecer dentro de la imagen;
    • extraer el recorte directamente de la imagen original f;
    • aplicar cv2.QRCodeDetector().detectAndDecode(...) sobre ese recorte.
  8. Criterio de detención

    Interrumpir inmediatamente el procesamiento cuando el primer candidato produzca una cadena decodificada no vacía.

  9. Caso no encontrado

    Si ningún candidato se decodifica con éxito, imprimir exactamente: QRCODE_NAO_ENCONTRADO

  10. Salida (caso encontrado)

    Imprimir dos líneas.

    Primera línea: linha coluna altura largura utilizando el rectángulo delimitador original, antes de la expansión por el margen \(M\).

    Segunda línea: texto_decodificado

6.14.8.2 📌 Restricciones Computacionales

  • Utilizar funciones de OpenCV para realizar la binarización, la detección de contornos, el cálculo del rectángulo delimitador y la decodificación del QRCode.
  • El filtrado geométrico debe ocurrir obligatoriamente antes de la etapa de decodificación.
  • Utilizar exclusivamente el umbral fijo \(T\) proporcionado en la entrada. No se permite utilizar métodos automáticos de umbralización, como Otsu o umbralización adaptativa.
  • Garantizar que los recortes enviados al decodificador permanezcan dentro de los límites de la imagen.

6.14.8.3 🧠 Fundamentación Teórica

Etapa Papel en el pipeline Consecuencia si se omite
Filtrado geométrico Reduce el espacio de búsqueda seleccionando solo regiones compatibles con la geometría esperada de un QRCode. El decodificador procesaría todos los contornos, incluyendo ruidos y objetos distractores.
Decodificación Confirma semánticamente si el candidato contiene un QRCode válido. Objetos geométricamente similares podrían clasificarse incorrectamente como QRCode.
Margen \(M\) Preserva la zona de silencio alrededor del código, facilitando su detección. La ausencia de este margen puede impedir la alineación y la lectura correcta del código.

Este ejercicio integra conceptos estudiados a lo largo del capítulo en un único pipeline de Visión por Computador. La segmentación reduce el conjunto de regiones candidatas mediante características geométricas, mientras que la etapa de decodificación valida el contenido de la región utilizando un algoritmo especializado de reconocimiento.

6.14.8.4 📦 Especificación de Entrada y Salida (VPL)

Estructura de Entrada

L
C
T A_min tol M
[matriz de la imagen]

Estructura de Salida (Éxito)

linha coluna altura largura
texto_decodificado

Estructura de Salida (Fallo)

QRCODE_NAO_ENCONTRADO

6.14.8.5 📌 Archivos de Referencia (.pgm)

Para fines de validación, depuración local y análisis de matrices reales de píxeles, los archivos de imagen generados en el estándar ASCII P2 se encuentran disponibles en el directorio del proyecto. Puede utilizarlos para probar con decodificadores de su teléfono móvil la adherencia de su código (guardar *.pgm localmente para visualizar):

  • 📥 Caso 1: Patrón Normal – Contiene un único código perfectamente centrado con distractores geométricos simples en la periferia.
  • 📥 Caso 2: Escenario Complejo – Presenta mayor densidad de ruido texturizado y múltiples distractores candidatos que ponen a prueba los límites del filtrado por aspecto.
  • 📥 Caso 3: Mensaje Expandido – Contiene un QRCode estructurado a partir de una cadena de caracteres de mayor longitud, generando una mayor densidad de módulos internos.
  • 📥 Caso 4: Geometría Compacta – Evalúa el comportamiento del pipeline bajo condiciones optimizadas de contraste y posicionamiento límite.
  • 📥 Caso 5: Escenario de Exclusión – Imagen compuesta puramente por elementos distractores de alta área, diseñada para validar el comportamiento de fallo controlado del programa.
📋 Simulador EP06_08: Segmentación y Decodificación de Código QR Filtro Geométrico → Parada Semántica

Ajusta interactivamente los parámetros de entrada del algoritmo (A_min y tol) para verificar qué componentes se filtran geométricamente y cómo el criterio de parada por análisis semántico interrumpe el escaneo de la cola.

250
0.22
Visualización de la Escena (Matriz f)
Componentes Conectados en la Cola
Figura 6.28: Simulador EP06_08: Segmentación Geométrica + Verificación por Decodificación de Código QR
%%writefile EP06_08.py
# Código Python
Overwriting EP06_08.py
TestSuite("EP06_08.py").run()
✔️ EP06_08.cases ya existe en casos/
📋 5 caso(s) cargado(s) de casos/EP06_08.cases

🔍 Probando Python: EP06_08.py
⚠️ EP06_08.py: archivo vacío (menos de 3 líneas). Pruebas omitidas.