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

EP02_11 — 🏆 Correção de Perspectiva (Homografia) em Imagem Real

2.12.11 EP02_11 🏆 Correção de Perspectiva (Homografia) em Imagem Real

Nesta atividade, o objetivo é aplicar a transformação de perspectiva (homografia) para “retificar” um objeto inclinado em uma fotografia real. Você lidará com a imagem de um jornal, onde a grade de um jogo de Sudoku está distorcida devido ao ângulo em que a foto foi capturada.

Seu programa deve ler os parâmetros de entrada do terminal, carregar a imagem, calcular a matriz de homografia \(3 \times 3\), aplicar a transformação geométrica e exibir um indicador global de validação.

  • Leia dois inteiros L e C, representando as dimensões de linhas e colunas (altura e largura) que a imagem retificada de saída deve ter.
  • Leia quatro pares de coordenadas \((x, y)\) via terminal, representando os quatro cantos do quadrilátero de origem (o Sudoku distorcido na imagem original).
  • Calcule automaticamente os quatro pares de coordenadas de destino utilizando as dimensões \(L\) e \(C\) fornecidas, mapeando os cantos para as extremidades da nova imagem: \((0,0)\), \((C-1, 0)\), \((0, L-1)\) e \((C-1, L-1)\).
  • Carregue a imagem local sudoku.png e converta-a para tons de cinza (grayscale).
  • Calcule a matriz de homografia e aplique a transformação espacial na imagem.
  • Saída: Calcule e imprima a soma de todos os pixels da imagem resultante.

📌 Importante:

  • Arquivo de entrada: A imagem sudoku.png deve estar na mesma pasta do script. O programa deve lê-la diretamente do disco (ex: usando mm.read("sudoku.png") ou cv2.imread).
  • Ordem dos Pontos: Garanta que a leitura dos 4 pontos de origem e a geração dos 4 pontos de destino sigam rigorosamente a mesma ordem dos cantos: Superior-Esquerdo (TL), Superior-Direito (TR), Inferior-Esquerdo (BL) e Inferior-Direito (BR).
  • Dimensões no OpenCV: Lembre-se que funções como cv2.warpPerspective esperam o tamanho da imagem de saída no formato (largura, altura), o que equivale a (C, L).
  • Interpolação: Para garantir a consistência matemática da soma dos pixels com o corretor automático, utilize a interpolação bilinear padrão (flags=cv2.INTER_LINEAR).
  • Créditos: A imagem utilizada é “Sudoku en periódico” de Héctor Rodríguez, sob licença CC BY 2.0.

2.12.11.1 🧠 Contexto do Problema

A homografia possui 8 graus de liberdade, exigindo no mínimo 4 correspondências de pontos para ser calculada. Ao contrário de transformações afins, ela mapeia qualquer quadrilátero em outro quadrilátero, permitindo que linhas que convergem para pontos de fuga voltem a ser paralelas:

Operação Característica Aplicação Típica
Homografia Projeção entre planos Retificação de documentos, escaneamento de placas e QR Codes.
Mapeamento Inverso Varredura do destino para a origem Evita “buracos” ou pixels vazios na imagem final retificada.
Warping Reamostragem espacial Correção de distorção de lentes e montagem de panoramas (stitching).

2.12.11.2 📌 Exemplos

Entrada Saída Observação
500
500
100 120
420 95
80 440
450 460
32982820 As duas primeiras entradas são as dimensões de saída (\(L\) e \(C\)). As 4 linhas seguintes são as coordenadas \((x, y)\) dos cantos do Sudoku na imagem original + PAD. A saída é a soma total dos pixels da imagem retificada.
200 200
100 120
420 95
80 440
450 460
5277150 Mesmos pontos de origem do exemplo anterior, mas gerando uma imagem de saída menor (\(200 \times 200\)). A soma dos pixels reduz proporcionalmente devido à escala.

2.12.11.3 Aquisição da imagem do sudoku e conversão para níveis de cinza

A Figura 2.22 mostra a leitura da imagem original seguida da conversão para tons de cinza e redimensionamento para uma matriz de \(500 \times 500\) pixels, preparando os dados para a etapa seguinte.

A correção de perspectiva, aplicada na Figura 2.23 via matriz de homografia, elimina as deformações causadas pelo ângulo da câmera e produz uma visão frontal e regular da grade do Sudoku.

Figura 2.22: Aquisição da imagem de um Sudoku à esquerda. À direita, conversão para tons de cinza e redimensionamento. Crédito: Héctor Rodríguez de Guardamar, Espanha (CC BY 2.0).
import cv2
import numpy as np

# --- 1. Carrega a imagem salva (sudoku.png) ---
img = mm.read("sudoku.png")                # BGR, 500×500

# --- 2. Padding para não cortar vértices ---
PAD = 60
img_pad = cv2.copyMakeBorder(
    img, PAD, PAD, PAD, PAD,
    cv2.BORDER_CONSTANT, value=[255, 255, 255]
)

# --- 3. Pontos de origem (cantos da grade na imagem expandida) ---
pts1 = np.float32([
    [100, 160],    # TL
    [390, 45],    # TR
    [200, 580],   # BL
    [570, 420],   # BR
])
#     W    H

# --- 4. Pontos de destino (vista frontal 500×500) ---
SIZE = 500
pts2 = np.float32([
    [0,    0],
    [SIZE, 0],
    [0,    SIZE],
    [SIZE, SIZE],
])

# --- 5. Homografia e retificação ---
img_rect = mm.perspective_transform(img_pad, pts1, pts2, size=(SIZE, SIZE))

# --- 6. Exibição ---
mm.show(
    [img_pad, img_rect],
    titles=["Original (com padding)", "Vista frontal retificada"],
    cols=2, figsize=(10, 6), axis=True
)
Figura 2.23: Correção de perspectiva: original e vista frontal retificada.
🎮 Simulador EP02_11: Perspectiva do Sudoku Homografia 3×3 · CC BY 2.0
📷 Original (Expandida) — Arraste os Cantos Foto: Héctor Rodríguez · CC BY 2.0
✅ Corrigida (400×400) — Visão Frontal
Carregando imagem do Sudoku...
Figura 2.24: Simulador EP02_11: Correção de Perspectiva do Sudoku (Homografia 3×3 com Reamostragem Bilinear)
%%writefile EP02_11.py
# Código Python
Overwriting EP02_11.py
TestSuite("EP02_11.py").run()
✔️ EP02_11.cases já existe em casos/
📋 4 caso(s) carregado(s) de casos/EP02_11.cases

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