9.10.5 EP09_05 🟠 Avaliação de Segmentação: IoU e Dice Pixel a Pixel
O Bloco 2 da seção “Segmentação Semântica com Arquitetura U-Net” define, em poucas linhas, a função iou_mascaras, usada para medir a qualidade da linha de base morfológica clássica (suavização + Otsu + abertura) e, mais adiante, da própria U-Net treinada. Diferentemente do IoU do EP09_04 — calculado sobre caixas delimitadoras (regiões retangulares descritas por quatro números) —, o IoU de segmentação é calculado pixel a pixel: cada posição da imagem é comparada individualmente entre a máscara predita e a máscara de referência.
Você foi encarregado de generalizar essa avaliação, implementando não apenas o IoU pixel a pixel, mas também o coeficiente de Dice, outra métrica de sobreposição amplamente usada em segmentação médica (inclusive na função perda_dice, mencionada no mesmo bloco do capítulo como base da função de perda usada para treinar a U-Net).
9.10.5.1 📋 Diretrizes de Implementação
Entrada: Ler as dimensões \(H \times W\) das máscaras.
Máscara predita: Ler \(H\) linhas com \(W\) valores inteiros (0 ou 1) cada — por exemplo, a saída de uma U-Net após limiarização em \(0{,}5\) sobre a sigmoide, como no Bloco 4 do capítulo.
Máscara de referência: Ler mais \(H\) linhas com \(W\) valores inteiros (0 ou 1) cada — o ground truth.
Interseção e união: Considerando cada pixel como pertencente ao objeto quando seu valor é diferente de zero, \[ \text{interseção} = \sum_{i,j} \mathbb{1}[P_{ij}=1 \wedge R_{ij}=1], \qquad \text{união} = \sum_{i,j} \mathbb{1}[P_{ij}=1 \vee R_{ij}=1]. \]
IoU pixel a pixel: \[ \text{IoU} = \frac{\text{interseção}}{\text{união}}. \]
Coeficiente de Dice: \[ \text{Dice} = \frac{2 \cdot \text{interseção}}{|P| + |R|}, \] em que \(|P|\) e \(|R|\) são o número total de pixels de objeto em cada máscara.
Convenção para máscaras vazias: se ambas as máscaras não possuem nenhum pixel de objeto (união \(= 0\) e \(|P|+|R|=0\)), considere a correspondência trivialmente perfeita: \(\text{IoU} = \text{Dice} = 1{,}0\).
Saída: Duas linhas,
IoU: X.XXXXeDice: X.XXXX, cada valor com 4 casas decimais.
9.10.5.2 📌 Restrições Computacionais
- Qualquer valor não nulo conta como objeto: trate valores diferentes de \(0\) (não apenas \(1\)) como pertencentes à máscara, replicando a checagem
predita > 0usada emiou_mascarasno capítulo. - Mesmas dimensões: as duas máscaras sempre possuem exatamente \(H \times W\) elementos.
- Convenção de vazio: aplique a regra do item 7 apenas quando ambas as máscaras estiverem totalmente vazias; se apenas uma estiver vazia, a interseção é \(0\) e o IoU/Dice resultante também será \(0\).
9.10.5.3 🧠 Fundamentação Teórica
| Elemento | Papel na avaliação de segmentação |
|---|---|
| IoU pixel a pixel | Generaliza a métrica do EP09_04 para regiões de forma arbitrária — não apenas retângulos — comparando máscara predita e referência posição a posição |
| Coeficiente de Dice | Métrica relacionada ao IoU (sempre \(\text{Dice} \ge \text{IoU}\)), mais sensível a pequenas interseções e amplamente usada como função de perda em segmentação (função perda_dice do capítulo) |
| Convenção de máscaras vazias | Evita divisão por zero e reconhece que “nenhum objeto previsto, nenhum objeto real” é, por definição, um acerto |
| Comparação clássico vs. U-Net | O capítulo usa exatamente este tipo de métrica para justificar, numericamente, por que a U-Net supera a linha de base morfológica em cenários de baixo contraste |
9.10.5.4 🧩 Métodos do morph.py que podem ajudar
mm.readImg(h, w, dtype='uint8')— lê diretamente cada máscara binária \(h \times w\) da entrada padrão (os valores \(0/1\) cabem perfeitamente no tipo inteiro padrão).- A própria função
iou_mascaras, definida no Bloco 2 da seção de U-Net do capítulo (não faz parte domorph.py, mas do código do capítulo), é a inspiração direta deste exercício — vale reler aquelas poucas linhas antes de programar. - Para uma extensão opcional (não exigida por este EP),
mm.connectedComponentsoumm.label0(vistos no contexto de análise de componentes conexos) permitiriam rotular cada nódulo individualmente e calcular o IoU por componente, em vez de sobre a máscara inteira.
9.10.5.5 📦 Especificação de Entrada e Saída (VPL)
Entrada:
- Linha 1: Inteiros \(H\) e \(W\).
- Próximas \(H\) linhas: \(W\) valores inteiros (0 ou 1) — máscara predita.
- Próximas \(H\) linhas: \(W\) valores inteiros (0 ou 1) — máscara de referência.
Saída:
- Linha 1:
IoU: X.XXXX. - Linha 2:
Dice: X.XXXX.
Considere uma máscara predita com um quadrado \(2\times2\) de pixels ativos e uma referência deslocada em uma coluna, sobrepondo-se em apenas metade da área:
Predita Referência
0 0 0 0 0 0 0 0
0 1 1 0 0 0 1 1
0 1 1 0 0 0 1 1
0 0 0 0 0 0 0 0
Interseção \(=2\) pixels, união \(=6\) pixels (\(4+4-2\)), logo \(\text{IoU}=2/6\approx0{,}3333\) e \(\text{Dice}=2\cdot2/(4+4)=0{,}5000\) — repare que o Dice é sempre igual ou maior que o IoU para a mesma sobreposição.
9.10.5.6 📌 Exemplos
| Entrada | Saída | Observação |
|---|---|---|
| 4 4 0 0 0 0 0 1 1 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 1 0 0 0 0 |
IoU: 0.3333 Dice: 0.5000 |
Máscaras \(4\times4\) com sobreposição parcial de 2 pixels. |
%%writefile EP09_05.py
# Código PythonWriting EP09_05.py
TestSuite("EP09_05.py").run()✔️ EP09_05.cases já existe em casos/
📋 4 caso(s) carregado(s) de casos/EP09_05.cases
🔍 Testando Python: EP09_05.py
⚠️ EP09_05.py: Arquivo sem conteúdo (menos de 3 linhas). Testes ignorados.