PDI+VC · Ejercicio de Programación

EP08_12 — 🔴 Segmentación de Instancias en Imagen Real: Objetos Geométricos

8.14.12 EP08_12 🔴 Segmentación de Instancias en Imagen Real: Objetos Geométricos

El ejemplo de segmentación clásica de este capítulo separó “instancias” de monedas por desconexión espacial en la máscara binaria resultante de la umbralización de Otsu. En este ejercicio vas a aplicar la misma idea — pero ahora sobre una imagen real con objetos geométricos variados — encadenando preprocesamiento, binarización, extracción de contornos (cv2.findContours) y validación del resultado contra un patrón de bounding boxes.

A diferencia del ejercicio anterior (etiquetado sobre máscara ya preparada), aquí partes de la imagen original: la calidad de tu segmentación depende directamente de las elecciones de preprocesamiento (filtrado, umbralización, operaciones morfológicas) realizadas antes de etiquetar los componentes.

8.14.12.1 📋 Directrices de Implementación

  1. Entrada: utilizar la imagen 00000.jpg.
  2. Preprocesamiento y segmentación: aplicar las etapas necesarias (filtrado, binarización y operaciones morfológicas) para separar automáticamente los objetos del fondo, sin recortes manuales.
  3. Etiquetado y medición: para cada objeto segmentado, determinar:
    • área;
    • centro de masa (centroide);
    • tipo, conforme al conjunto obj2.
  4. Anotación visual: escribir, en el interior de cada objeto, su área y la sigla del tipo (obj2).
  5. Validación (IoU): calcular el Intersection over Union (IoU) entre el bounding box detectado (cv2.boundingRect) y el bounding box de patrón del tipo correspondiente. Un objeto se considera correctamente segmentado solo si hay exactamente un bounding box del tipo correcto con IoU ≥ 0,5.
  6. Salida: imprimir, para cada objeto detectado, su identificador, tipo y si fue validado con éxito (acertou=1) o no. La impresión debe seguir el orden de las clases de obj2 (0=Tria … 8=Cruz); dentro de la misma clase, ordenar los objetos por la coordenada vertical del centroide (cy) creciente. Al final, imprimir la precisión general.

8.14.12.2 📌 Restricciones Computacionales

  • Sin recorte manual: toda la segmentación debe realizarse sobre la imagen completa.

  • Conjunto de clases fijo:

    obj  = ['Triangulo','Quadrado','Pendagono','Hexagono','Heptagono','Circulo',
            'Elipse','Estrela','Cruz']
    obj2 = ['Tria','Quad','Pent','Hexa','Hept','Circ','Elip','Estr','Cruz']
  • Dimensión de la imagen: 608×608 píxeles — usada para desnormalizar las coordenadas del archivo TXT.

  • Validación por centro de masa: un objeto solo se considera correctamente segmentado si su centroide está estrictamente dentro del boundbox del patrón correspondiente al mismo tipo de objeto.

8.14.12.3 🧠 Fundamentación Teórica

Elemento Papel en la segmentación de instancias
Preprocesamiento (filtrado, umbralización) Etapa que produce la máscara binaria a partir de la imagen de intensidad original
cv2.findContours Extrae los contornos de los componentes conectados en la máscara binaria
Momentos geométricos (cv2.moments) Permiten calcular el centro de masa (centroide) de cada contorno
approxPolyDP / vértices Ayuda en la clasificación del tipo de objeto (nº de lados aproximado)
Validación mediante boundbox Confirma si la instancia segmentada corresponde espacialmente a un objeto del patrón, midiendo la precisión del método

8.14.12.4 📌 Ejemplo de Salida Esperada

Objeto 1: tipo=Tria, validado=True
...
Precisión: 88.89%

Parámetros fijos para reproducibilidad: para que la salida coincida con el patrón de corrección automática, utiliza exactamente: filtro de área mínima de 300 píxeles; cv2.approxPolyDP con epsilon = 0.02 * perímetro; umbral de solidez 0.92 y conteo de vértices ≥ 9 (con ≥ 11 para diferenciar Cruz de Estrella) para formas cóncavas; relación de aspecto 1.15 para diferenciar Círculo de Elipse; umbral de IoU = 0.5 en la validación.

8.14.12.5 📌 Archivos de Referencia (.jpg y .txt)

Para depuración local, se proporcionan dos archivos de referencia (incluidos en esta entrega; al integrarlos al repositorio del capítulo, guárdalos en all/cap08/dados/EP08/):

  • 📥 Imagen (00000.jpg): imagen de objetos geométricos utilizada como entrada del ejercicio. El objetivo es segmentar automáticamente cada objeto, determinar su tipo y calcular sus medidas.
  • 📥 Patrón (00000.txt): archivo que contiene las bounding boxes normalizadas de los objetos presentes en la imagen. Cada línea posee el identificador de la clase y las coordenadas normalizadas de las esquinas superior izquierda e inferior derecha, utilizándose para validar automáticamente la segmentación.

La Figura 8.26 presenta la imagen de entrada y la misma imagen con las bounding boxes dibujadas a partir del archivo de patrón.

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 del 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: Precisión de Segmentación en Múltiples Objetos 🟢 acertó si IoU ≥ umbral Y tipo correcto

Cada forma tiene un boundbox de referencia (rectángulo discontinuo, justo alrededor de la forma) y un boundbox detectado (rectángulo sólido, desplazado/ruidoso). Ajuste el ruido, el sesgo y el umbral de IoU para ver cómo cambia la validación.

0
0
0.50
id tipo real tipo detectado IoU ≥ umbral acertó
Figura 8.27: Simulador EP08_12: Precisión de Segmentación en Múltiples Objetos (IoU)
%%writefile EP08_12.py
# Código Python
Overwriting EP08_12.py
TestSuite("EP08_12.py").run()
✔️ EP08_12.cases ya existe en casos/
📋 1 caso(s) cargado(s) de casos/EP08_12.cases

🔍 Probando Python: EP08_12.py
⚠️ EP08_12.py: archivo vacío (menos de 3 líneas). Pruebas omitidas.