Clase 15 — Tema 11: Contornos y Formas (findContours, drawContours, áreas)
Resumen Ejecutivo
Sesión de dos partes:
- Revisión de la actividad de líneas (Hough). Comentario de las imágenes entregadas por los alumnos: ajuste del umbral de votaciones en
HoughLines, importancia de ecualizar antes y de pasar un filtro de suavizado para evitar rectas falsas. Aclaración teórica sobre filtros en el dominio del espacio vs. dominio de la frecuencia (equivalentes matemáticamente; en el curso solo se trabaja en el espacio). - Tema 11 — Contornos y Formas. Pipeline de detección de contornos con OpenCV:
findContours(parámetrosmodeymethod),drawContours, la jerarquía de contornos (EXTERNAL,LIST,TREE) y el cálculo de áreas concontourArea, con filtrado de contornos por área.
La jerarquía completa se deja para la última clase (lunes 15/06). Esta sesión habilita el ejercicio 3 del laboratorio 2 (filtrado por área).
Conceptos Clave
findContours: busca objetos blancos sobre fondo negro en una imagen binaria (de bordes Canny o umbralizada). ⚠️ EXAMEN- Bordes vs. umbralización: sobre el mismo "9", Canny da 2 objetos blancos (contorno exterior + agujero) → 4 contornos; umbralización da 1 objeto blanco → 2 contornos. ⚠️ EXAMEN
method:CHAIN_APPROX_NONE(todos los puntos) vsCHAIN_APPROX_SIMPLE(solo extremos de tramos rectos). ⚠️mode:RETR_EXTERNAL(solo contornos externos),RETR_LIST(todos, sin jerarquía),RETR_TREE(todos + jerarquía). ⚠️ EXAMENdrawContours: dibuja contornos; índice-1= todos;thickness=-1= relleno sólido. ⚠️contourArea: devuelve el área en píxeles cuadrados que encierra el contorno (no la longitud del contorno). ⚠️ EXAMEN- Filtrado por área: descartar contornos por debajo de un % del área total de la imagen.
Desarrollo del Temario
1. Cierre de la actividad de líneas (Hough)
Puntos repetidos al comentar las entregas:
- Umbral de votaciones: subir el umbral = más exigente → desaparecen líneas; bajarlo → aparecen muchas (incluso falsas). El objetivo de la actividad es saber moverse con el parámetro, no encontrar exactamente todas las rectas.
- Ecualizar primero: sin ecualizar la imagen (trabajando solo con la escala de grises) se pierde información y no salen las líneas esperadas.
- Suavizado previo: un filtro de suavizado quita ruido que genera rectas falsas. Recomendable poner un flag que permita activar/desactivar el suavizado para hacer pruebas.
- Imágenes alargadas: si las verticales son más cortas, el umbral puede hacer aparecer horizontales sin sentido.
eliminar rectas similares: solo aplica a Hough normal (trata rectas en polares, ρ-θ). Para la versión probabilística (segmentos por puntos extremos) hay que adaptarla.
El ejercicio de OpenCV del examen es muy fácil; lo que se valora es saber manejar el pipeline, no la precisión exacta.
2. Dominio del espacio vs. dominio de la frecuencia
Dos formas de atacar los filtros (p.ej. suavizado):
| Dominio del espacio | Dominio de la frecuencia | |
|---|---|---|
| Cómo | Convolución con kernel (filtro de media, gaussiano) | Transformada de Fourier |
| En el curso | Sí (es lo que hemos usado) | No (matemáticas más duras) |
Se demuestra matemáticamente que un filtro de convolución que suaviza en el espacio es equivalente a un filtro frecuencial que suaviza. El desenfoque gaussiano existe en ambas versiones; son el mismo efecto en espacios distintos.
3. Pipeline general de detección de contornos
flowchart LR
img[Leer imagen] --> gray[Escala de grises]
gray --> blur[Suavizado opcional]
blur --> bin{Binarizar}
bin -->|Canny| edges[Bordes]
bin -->|threshold| thr[Umbralizado]
edges --> fc[findContours]
thr --> fc
fc --> draw[drawContours opcional]
fc --> area[contourArea / filtrado]
findContours siempre requiere una imagen binaria (dos colores: fondo negro + objetos/bordes blancos).
4. findContours: qué devuelve y parámetros
Devuelve:
1. contours — vector de contornos; cada contorno es un vector de puntos.
2. hierarchy — relación jerárquica entre contornos (se pide o no según mode).
Parámetro method (simplificación de puntos):
- CHAIN_APPROX_NONE → todos los puntos del contorno.
- CHAIN_APPROX_SIMPLE → solo los extremos de cada tramo recto (p.ej. un cuadrado → 4 vértices).
Parámetro mode (jerarquía):
- RETR_EXTERNAL → solo el contorno externo de cada objeto (ignora huecos internos).
- RETR_LIST → todos los contornos (externos e internos) sin relación entre ellos.
- RETR_TREE → todos los contornos + jerarquía (quién contiene a quién).
Ejemplo del "9": bordes vs umbralización
flowchart TB
subgraph Canny["Canny → 2 objetos blancos → 4 contornos"]
c1["interior del agujero"]
c2["exterior del agujero"]
c3["interior del borde del 9"]
c4["exterior del borde del 9"]
end
subgraph Thr["Umbralización → 1 objeto blanco → 2 contornos"]
t1["interior (agujero)"]
t2["exterior (borde)"]
end
Visualmente con Canny solo se "ven" dos líneas porque los pares de contornos están pegadísimos, pero al imprimir los puntos son contornos distintos. El orden en que findContours devuelve los contornos no está documentado.
5. drawContours: parámetros
| Parámetro | Significado |
|---|---|
| Imagen destino | Normalmente una copia de la original |
contours |
Lo que devuelve findContours, tal cual |
| Índice del contorno | Índice concreto, o -1 para dibujar todos |
| Color | Color del trazo (BGR) |
thickness |
Grosor; -1 = relleno sólido |
| Tipo de línea | Sólida, punteada… |
6. Cálculo y filtrado por área (contourArea)
contourArea(contorno) devuelve el área en píxeles cuadrados que encierra el contorno (no su perímetro/longitud). El segundo parámetro oriented no se usa en el curso.
Aplicación — filtrar por tamaño: quedarse solo con contornos cuya área supere un porcentaje del área total de la imagen (más robusto que usar valores absolutos). Útil para: descartar células pequeñas en microscopía, control de calidad en cadena de montaje, etc.
area_total = img.shape[0] * img.shape[1]
area_min = porcentaje/100 * area_total # umbral en píxeles
for i, c in enumerate(contornos):
if cv2.contourArea(c) > area_min:
cv2.drawContours(copia, contornos, i, color, 2)
Ejemplo de clase: área total 212.800 px², umbral 0,5 % = 1.064 px². Los agujeros del 9 (≈276, 290, 1.040 px²) no se dibujan; los contornos de ≥1.081 px² sí.
Qué entra del examen de este tema (palabras de la profesora): saber dar el paso desde Canny →
findContours, y calcular áreas concontourArea. "No tiene más dificultad." El ejercicio será muy parecido al laboratorio 3 (filtrado por área de una carta).Pregunta de un alumno: usar el autocomplete de VS Code en el examen no es problema (no es un IDE ni Copilot); Copilot sí estaría prohibido.
Preguntas de Autoevaluación
- ¿Por qué
findContoursnecesita una imagen binaria? ¿Qué representa un "contorno" en OpenCV? - Sobre la imagen de un "9", ¿cuántos contornos devuelve
findContourscon bordes Canny y cuántos con umbralización? Justifícalo. - Diferencia entre
CHAIN_APPROX_NONEyCHAIN_APPROX_SIMPLEcon el ejemplo de un cuadrado. - Explica
RETR_EXTERNAL,RETR_LISTyRETR_TREE. ¿Cuál usarías si solo te interesa el borde externo de cada objeto? - ¿Qué hace
drawContourscon índice-1? ¿Y conthickness=-1? - ¿Qué devuelve
contourArea: el perímetro o el área encerrada? ¿En qué unidades? - ¿Cómo filtrarías una imagen para quedarte solo con los objetos grandes? ¿Por qué se usa un porcentaje del área total en vez de un valor absoluto?
- ¿Por qué un filtro de suavizado en el dominio del espacio es equivalente a uno en el dominio de la frecuencia?
- En la actividad de Hough, ¿qué efecto tiene subir o bajar el umbral de votaciones? ¿Por qué hay que ecualizar antes?
- ¿Por qué la función
eliminar rectas similaressolo sirve para Hough normal y no para la versión probabilística?