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

EP08_12 — 🔴 Segmentação de Instâncias em Imagem Real: Objetos Geométricos

8.14.12 EP08_12 🔴 Segmentação de Instâncias em Imagem Real: Objetos Geométricos

O exemplo de segmentação clássica deste capítulo separou “instâncias” de moedas por desconexão espacial na máscara binária resultante da limiarização de Otsu. Neste exercício você vai aplicar a mesma ideia — mas agora sobre uma imagem real com objetos geométricos variados — encadeando pré-processamento, binarização, extração de contornos (cv2.findContours) e validação do resultado contra um gabarito de bounding boxes.

Diferente do exercício anterior (rotulação sobre máscara já pronta), aqui você parte da imagem original: a qualidade da sua segmentação depende diretamente das escolhas de pré-processamento (filtragem, limiarização, operações morfológicas) feitas antes de rotular os componentes.

8.14.12.1 📋 Diretrizes de Implementação

  1. Entrada: utilizar a imagem 00000.jpg.
  2. Pré-processamento e segmentação: aplicar as etapas necessárias (filtragem, binarização e operações morfológicas) para separar automaticamente os objetos do fundo, sem recortes manuais.
  3. Rotulação e medição: para cada objeto segmentado, determinar:
    • área;
    • centro de massa (centroide);
    • tipo, conforme o conjunto obj2.
  4. Anotação visual: escrever, no interior de cada objeto, sua área e a sigla do tipo (obj2).
  5. Validação (IoU): calcular o Intersection over Union (IoU) entre o bounding box detectado (cv2.boundingRect) e o bounding box de gabarito do tipo correspondente. Um objeto é considerado corretamente segmentado apenas se houver exatamente um bounding box do tipo correto com IoU ≥ 0,5.
  6. Saída: imprimir, para cada objeto detectado, seu identificador, tipo e se foi validado com sucesso (acertou=1) ou não. A impressão deve seguir a ordem das classes de obj2 (0=Tria … 8=Cruz); dentro da mesma classe, ordenar os objetos pela coordenada vertical do centroide (cy) crescente. Ao final, imprimir a acurácia geral.

8.14.12.2 📌 Restrições Computacionais

  • Sem recorte manual: toda a segmentação deve ser feita sobre a imagem completa.

  • Conjunto de classes fixo:

    obj  = ['Triangulo','Quadrado','Pendagono','Hexagono','Heptagono','Circulo',
            'Elipse','Estrela','Cruz']
    obj2 = ['Tria','Quad','Pent','Hexa','Hept','Circ','Elip','Estr','Cruz']
  • Dimensão da imagem: 608×608 pixels — usada para desnormalizar as coordenadas do arquivo TXT.

  • Validação por centro de massa: um objeto só é considerado corretamente segmentado se seu centroide estiver estritamente dentro do boundbox do gabarito correspondente ao mesmo tipo de objeto.

8.14.12.3 🧠 Fundamentação Teórica

Elemento Papel na segmentação de instâncias
Pré-processamento (filtragem, limiarização) Etapa que produz a máscara binária a partir da imagem de intensidade original
cv2.findContours Extrai os contornos dos componentes conectados na máscara binária
Momentos geométricos (cv2.moments) Permitem calcular o centro de massa (centroide) de cada contorno
approxPolyDP / vértices Auxilia na classificação do tipo de objeto (nº de lados aproximado)
Validação via boundbox Confirma se a instância segmentada corresponde espacialmente a um objeto do gabarito, medindo a acurácia do método

8.14.12.4 📌 Exemplo de Saída Esperada

Objeto 1: tipo=Tria, validado=True
...
Acurácia: 88.89%

Parâmetros fixos para reprodutibilidade: para que a saída bata com o gabarito de correção automática, utilize exatamente: filtro de área mínima de 300 pixels; cv2.approxPolyDP com epsilon = 0.02 * perímetro; limiar de solidez 0.92 e contagem de vértices ≥ 9 (com ≥ 11 para diferenciar Cruz de Estrela) para formas côncavas; razão de aspecto 1.15 para diferenciar Círculo de Elipse; limiar de IoU = 0.5 na validação.

8.14.12.5 📌 Arquivos de Referência (.jpg e .txt)

Para depuração local, são disponibilizados dois arquivos de referência (incluídos nesta entrega; ao integrá-los ao repositório do capítulo, salve-os em all/cap08/dados/EP08/):

  • 📥 Imagem (00000.jpg): imagem de objetos geométricos utilizada como entrada do exercício. O objetivo é segmentar automaticamente cada objeto, determinar seu tipo e calcular suas medidas.
  • 📥 Gabarito (00000.txt): arquivo contendo as bounding boxes normalizadas dos objetos presentes na imagem. Cada linha possui o identificador da classe e as coordenadas normalizadas dos cantos superior esquerdo e inferior direito, sendo utilizado para validar automaticamente a segmentação.

A Figura 8.26 apresenta a imagem de entrada e a mesma imagem com as bounding boxes desenhadas a partir do arquivo de gabarito.

import os
import urllib.request
from morph import mm

def garantir_e_baixar(nome):
    pasta = "dados/EP12"
    caminho = os.path.join(pasta, nome)

    os.makedirs(pasta, exist_ok=True)

    if not os.path.exists(caminho):
        url = (
            "https://raw.githubusercontent.com/"
            "fzampirolli/pdi-vc/master/all/cap08/dados/EP12/"
            + nome
        )
        print(f"Baixando {nome}...")
        urllib.request.urlretrieve(url, caminho)

    return caminho

img_arq = garantir_e_baixar("00000.jpg")
txt_arq = garantir_e_baixar("00000.txt")

img = mm.read(img_arq)
img_bb = mm.showBoundBox(img, txt_arq, fmt="yolo", show=False)

mm.show(
    [img, img_bb],
    titles=[
        "Imagem original",
        "Bounding boxes do gabarito"
    ],
    cols=2,
    figsize=(10,5)
)
Figura 8.26: Simulador EP08_12: Imagem utilizada no EP08_12. À esquerda, a imagem original. À direita, a imagem com as bounding boxes do arquivo de gabarito.
🧮 Simulador EP08_12: Acurácia de Segmentação em Múltiplos Objetos 🟢 acertou se IoU ≥ limiar E tipo correto

Cada forma tem um boundbox de gabarito (retângulo tracejado, justo em torno da forma) e um boundbox detectado (retângulo sólido, deslocado/ruidoso). Ajuste o ruído, o viés e o limiar de IoU para ver a validação mudar.

0
0
0.50
id tipo real tipo detectado IoU ≥ limiar acertou
Figura 8.27: Simulador EP08_12: Acurácia de Segmentação em Múltiplos Objetos (IoU)
%%writefile EP08_12.py
# Código Python
Writing EP08_12.py
TestSuite("EP08_12.py").run()
✔️ EP08_12.cases já existe em casos/
📋 1 caso(s) carregado(s) de casos/EP08_12.cases

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