PDI+VC · Exercício de Programação

EP06_08 — ⚫ Segmentação e Decodificação Real de QRCode com OpenCV

6.14.8 EP06_08 ⚫ Segmentação e Decodificação Real de QRCode com OpenCV

Nos exercícios anteriores, as grandezas intermediárias do pipeline de processamento de imagens — como áreas, perímetros, variâncias e deslocamentos — foram fornecidas diretamente ou calculadas a partir de matrizes numéricas, sem a necessidade de bibliotecas especializadas de Visão Computacional. Neste exercício de encerramento do capítulo, essa restrição é removida de forma intencional: será utilizada a biblioteca OpenCV (cv2) para localizar e decodificar um QRCode real presente em uma cena.

A proposta reproduz um fluxo simplificado de sistemas empregados em inspeção visual, automação industrial e leitura automática de documentos. Para manter a entrada de dados acessível ao contexto educacional, o carregamento da imagem será integrado à biblioteca didática morph, por meio da função mm.readImg.

A cena é fornecida no formato PGM ASCII (P2) e contém um único QRCode válido, além de diversos objetos distratores, como retângulos, regiões de ruído texturizado e blocos isolados. A segmentação baseada apenas em propriedades geométricas — como área e formato aproximadamente quadrado — é necessária para reduzir o espaço de busca, mas não é suficiente para identificar o código correto. A confirmação final será realizada exclusivamente pela tentativa de decodificação utilizando cv2.QRCodeDetector, procedimento compatível com aplicações reais de reconhecimento automático.

6.14.8.1 📋 Diretrizes de Implementação

  1. Leitura das dimensões e parâmetros

    Ler, nesta ordem, por meio da entrada padrão:

    • uma linha contendo o número de linhas \(L\);
    • uma linha contendo o número de colunas \(C\);
    • uma linha contendo os quatro parâmetros do algoritmo separados por espaço:
      • limiar de binarização \(T\) (inteiro);
      • área mínima \(A_{\text{min}}\) (inteiro);
      • tolerância de aspecto \(\text{tol}\) (real);
      • margem \(M\) (inteiro, em pixels).
  2. Carregamento da imagem

    Utilizar a função didática f = mm.readImg(L, C) para ler os \(L \times C\) valores da imagem em tons de cinza, obtendo um array NumPy do tipo uint8.

  3. Binarização

    Aplicar limiarização binária invertida utilizando o limiar \(T\). Todo pixel da imagem original com intensidade estritamente maior que \(T\) deve ser convertido para 255, enquanto os demais devem assumir o valor 0.

  4. Detecção de contornos

    Extrair os componentes conectados externos utilizando cv2.findContours(...) com os parâmetros:

    • cv2.RETR_EXTERNAL;
    • cv2.CHAIN_APPROX_SIMPLE.
  5. Filtragem geométrica

    Para cada contorno encontrado:

    • calcular o retângulo delimitador (x, y, w, h) por meio de cv2.boundingRect;

    • manter apenas os candidatos que satisfaçam simultaneamente:

      Área mínima

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

      Razão de aspecto

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

  6. Ordenação dos candidatos

    Ordenar os candidatos pela área do retângulo delimitador

    \[ w \times h \]

    em ordem decrescente.

    Em caso de empate, preservar a ordem originalmente retornada por cv2.findContours.

  7. Verificação por decodificação

    Para cada candidato, seguindo a ordem estabelecida:

    • expandir o retângulo em \(M\) pixels nas quatro direções;
    • limitar os índices para permanecerem dentro da imagem;
    • extrair o recorte diretamente da imagem original f;
    • aplicar cv2.QRCodeDetector().detectAndDecode(...) sobre esse recorte.
  8. Critério de parada

    Interromper imediatamente o processamento quando o primeiro candidato produzir uma string decodificada não vazia.

  9. Caso não encontrado

    Se nenhum candidato for decodificado com sucesso, imprimir exatamente: QRCODE_NAO_ENCONTRADO

  10. Saída (caso encontrado)

    Imprimir duas linhas.

    Primeira linha: linha coluna altura largura utilizando o retângulo delimitador original, antes da expansão pela margem \(M\).

    Segunda linha: texto_decodificado

6.14.8.2 📌 Restrições Computacionais

  • Utilizar funções do OpenCV para realizar a binarização, a detecção de contornos, o cálculo do retângulo delimitador e a decodificação do QRCode.
  • A filtragem geométrica deve ocorrer obrigatoriamente antes da etapa de decodificação.
  • Utilizar exclusivamente o limiar fixo \(T\) fornecido na entrada. Não é permitido utilizar métodos automáticos de limiarização, como Otsu ou limiarização adaptativa.
  • Garantir que os recortes enviados ao decodificador permaneçam dentro dos limites da imagem.

6.14.8.3 🧠 Fundamentação Teórica

Etapa Papel no pipeline Consequência se omitida
Filtragem geométrica Reduz o espaço de busca selecionando apenas regiões compatíveis com a geometria esperada de um QRCode. O decodificador processaria todos os contornos, incluindo ruídos e objetos distratores.
Decodificação Confirma semanticamente se o candidato contém um QRCode válido. Objetos geometricamente semelhantes poderiam ser classificados incorretamente como QRCode.
Margem \(M\) Preserva a quiet zone ao redor do código, facilitando sua detecção. A ausência dessa margem pode impedir o alinhamento e a leitura correta do código.

Este exercício integra conceitos estudados ao longo do capítulo em um único pipeline de Visão Computacional. A segmentação reduz o conjunto de regiões candidatas por meio de características geométricas, enquanto a etapa de decodificação valida o conteúdo da região utilizando um algoritmo especializado de reconhecimento.

6.14.8.4 📦 Especificação de Entrada e Saída (VPL)

Estrutura de Entrada

L
C
T A_min tol M
[matriz da imagem]

Estrutura de Saída (Sucesso)

linha coluna altura largura
texto_decodificado

Estrutura de Saída (Falha)

QRCODE_NAO_ENCONTRADO

6.14.8.5 📌 Arquivos de Referência (.pgm)

Para fins de validação, depuração local e análise de matrizes reais de pixels, os arquivos de imagem gerados no padrão ASCII P2 encontram-se disponíveis no diretório do projeto. Você pode utilizá-los para testar em decodificados do seu celular a aderência do seu código (salvar *.pgm localmente para visualizar):

  • 📥 Caso 1: Padrão Normal – Contém um único código perfeitamente centralizado com distratores geométricos simples na periferia.
  • 📥 Caso 2: Cenário Complexo – Apresenta maior densidade de ruído texturizado e múltiplos distratores candidatos que testam os limites da filtragem por aspecto.
  • 📥 Caso 3: Mensagem Expandida – Contém um QRCode estruturado a partir de uma cadeia de caracteres de maior comprimento, gerando maior densidade de módulos internos.
  • 📥 Caso 4: Geometria Compacta – Avalia o comportamento do pipeline sob condições otimizadas de contraste e posicionamento limítrofe.
  • 📥 Caso 5: Cenário de Exclusão – Imagem composta puramente por elementos distratores de alta área, projetada para validar o comportamento de falha controlada do programa.
📋 Simulador EP06_08: Segmentação e Decodificação de QRCode Filtro Geométrico → Parada Semântica

Ajuste interativamente os parâmetros de entrada do algoritmo (A_min e tol) para verificar quais componentes são filtrados geometricamente e como o critério de parada por análise semântica interrompe a varredura da fila.

250
0.22
Visualização da Cena (Matriz f)
Componentes Conectados na Fila
Figura 6.28: Simulador EP06_08: Segmentação Geométrica + Verificação por Decodificação de QRCode
%%writefile EP06_08.py
# Código Python
Writing EP06_08.py
TestSuite("EP06_08.py").run()
✔️ EP06_08.cases já existe em casos/
📋 5 caso(s) carregado(s) de casos/EP06_08.cases

🔍 Testando Python: EP06_08.py
⚠️ EP06_08.py: Arquivo sem conteúdo (menos de 3 linhas). Testes ignorados.