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

EP07_05 — 🔴 Histograma de Orientações de uma Célula HOG

7.18.5 EP07_05 🔴 Histograma de Orientações de uma Célula HOG

A função hog do scikit-image, empregada no projeto de classificação de dígitos, divide a imagem em pequenas células e, para cada uma, constrói um histograma das orientações do gradiente ponderado pela magnitude — exatamente a etapa central descrita na seção sobre o descritor HOG do capítulo.

Você foi encarregado de implementar esse cálculo para uma única célula, a partir dos valores de magnitude e orientação do gradiente já calculados para cada pixel da célula (dispensando o cálculo das derivadas parciais).

7.18.5.1 📋 Diretrizes de Implementação

  1. Dimensões: Ler os inteiros \(n\) (a célula tem \(n \times n\) pixels) e \(B\) (número de compartimentos do histograma).
  2. Magnitudes: Ler \(n\) linhas com \(n\) valores reais cada, representando \(|\nabla f(x,y)|\) para cada pixel da célula.
  3. Orientações: Ler mais \(n\) linhas com \(n\) valores reais cada, representando \(\theta(x,y)\) em graus, já convertido para o intervalo não sinalizado \([0^\circ, 180^\circ)\), como convencionalmente utilizado pelo HOG.
  4. Compartimentos: Os \(B\) compartimentos cobrem \([0^\circ, 180^\circ)\) em faixas iguais de largura \(180/B\) graus. Um pixel com orientação \(\theta\) pertence ao compartimento \(\lfloor \theta / (180/B) \rfloor\); se esse índice for igual a \(B\) (possível apenas quando \(\theta\) é exatamente \(180^\circ\), o que não deve ocorrer pela diretriz do item 3), utilize o compartimento \(B-1\).
  5. Histograma bruto: Para cada pixel, acumule sua magnitude (não sua contagem) no compartimento correspondente: \[ H[b] = \sum_{(x,y)\, :\, \text{bin}(\theta(x,y)) = b} |\nabla f(x,y)|. \]
  6. Normalização L2: Após construir \(H\), normalize-o para obter \(\hat H\): \[ \hat H[b] = \frac{H[b]}{\sqrt{\sum_{j=0}^{B-1} H[j]^2 + \epsilon}}, \qquad \epsilon = 10^{-6}. \]
  7. Saída: Imprimir o histograma bruto \(H\) (arredondado a 2 casas decimais) em uma linha, seguido do histograma normalizado \(\hat H\) (arredondado a 4 casas decimais) em outra linha, ambos com os \(B\) valores separados por espaço, na ordem dos compartimentos.

7.18.5.2 📌 Restrições Computacionais

  • Binning não sinalizado: o intervalo de orientações é \([0,180)\), não \([0,360)\) — gradientes em direções opostas (diferença de \(180^\circ\)) contribuem para o mesmo compartimento, convenção padrão do HOG para detecção de objetos.
  • Acumulação por magnitude, não por contagem: o histograma pondera cada pixel por sua magnitude de gradiente, não simplesmente conta quantos pixels caem em cada compartimento.
  • Constante de estabilização: o \(\epsilon = 10^{-6}\) no denominador da normalização evita divisão por zero quando a célula é completamente homogênea (todas as magnitudes nulas).

7.18.5.3 📐 De onde vêm as matrizes de entrada

Antes deste EP, cada pixel \((x,y)\) da imagem passa por:

\[ G_x = f(x+1,y)-f(x-1,y), \qquad G_y = f(x,y+1)-f(x,y-1) \]

\[ |\nabla f| = \sqrt{G_x^2+G_y^2}, \qquad \theta_{\text{sinal}} = \operatorname{atan2}(G_y,G_x) \]

Como o HOG ignora a polaridade do contraste, o ângulo é dobrado para o intervalo não sinalizado:

\[ \theta = \theta_{\text{sinal}} \bmod 180° \]

Repetindo isso para todos os pixels de uma célula \(n\times n\), obtêm-se as duas matrizes de entrada deste exercício: magnitudes \(|\nabla f|\) e orientações \(\theta \in [0°,180°)\).

7.18.5.4 🧠 Fundamentação Teórica

Etapa Papel
Magnitude do gradiente Pondera a contribuição de cada pixel — bordas fortes pesam mais que ruído fraco
Orientação não sinalizada Torna o descritor invariante à polaridade do contraste (claro→escuro vs. escuro→claro)
Histograma por célula Resume a distribuição local de bordas em um vetor compacto
Normalização L2 Reduz a sensibilidade do descritor a variações globais de iluminação e contraste

A concatenação dos histogramas normalizados de todas as células da imagem — não implementada neste exercício — forma o vetor de características HOG completo, utilizado como entrada do classificador k-NN no projeto do capítulo.

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

Entrada:

  • Linha 1: Inteiros \(n\) e \(B\).
  • Próximas \(n\) linhas: \(n\) magnitudes reais cada.
  • Próximas \(n\) linhas: \(n\) orientações reais (graus, \([0,180)\)) cada.

Saída:

  • Linha 1: os \(B\) valores do histograma bruto, arredondados a 2 casas decimais.
  • Linha 2: os \(B\) valores do histograma normalizado, arredondados a 4 casas decimais.

7.18.5.6 📌 Exemplos

Entrada Saída Observação
2 2
1.0 2.0
3.0 4.0
10 100
170 20
5.00 5.00
0.7071 0.7071
Bin de largura 90°: \([0,90)\) e \([90,180)\); magnitudes 1 e 4 caem no bin 0, 2 e 3 no bin 1.
2 4
0.0 0.0
0.0 0.0
0 0
0 0
0.00 0.00 0.00 0.00
0.0000 0.0000 0.0000 0.0000
Célula homogênea: \(\epsilon\) evita divisão por zero.
🎮 Simulador EP07_05: Histograma de Orientações de uma Célula 🔴 célula 3×3 fixa

Ajuste B e acompanhe como a matriz de orientações (independente da de magnitudes) é mapeada para os compartimentos via bin = floor(θ / (180/B)), e como as magnitudes são somadas em cada bin.

2
📄 Entrada (exatamente como o programa lê via stdin)

🔢 Matriz de magnitudes |∇f|
📐 Matriz de orientações θ (graus) — colorida pelo bin
📏 Onde cada θ cai na régua [0°, 180°) — bin = floor(θ / largura)
📊 Faixas de cada compartimento (largura = 180° / B)
🧩 Cada pixel: magnitude + orientação → bin
🧮 Cálculo passo a passo (floor da divisão + soma das magnitudes por bin)
Figura 7.25: Simulador EP07_05: Histograma HOG de uma Celula (mapeamento de ângulos para bins)
%%writefile EP07_05.py
# Código Python
Writing EP07_05.py
TestSuite("EP07_05.py").run()
✔️ EP07_05.cases já existe em casos/
📋 5 caso(s) carregado(s) de casos/EP07_05.cases

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