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.pnge 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.pngdeve estar na mesma pasta do script. O programa deve lê-la diretamente do disco (ex: usandomm.read("sudoku.png")oucv2.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.warpPerspectiveesperam 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.
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
)
%%writefile EP02_11.py
# Código PythonOverwriting 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.