Detección de contornos con OpenCV Python

Un contorno es un conjunto de puntos que conectados unos con otros de manera consecutiva forman una figura que rodea un objeto determinado, la detección de contornos en OpenCV se aplica sobre imágenes binarias, la figura obtenida puede ser analizada posteriormente para determinar cuál es el objeto que hemos detectado, para obtener los contornos utilizaremos la función findContours(), mientras que drawContours() nos ayudará a dibujarlos.

deteccion de contorno

Lo primero que requerimos es obtener una imagen binaria, para hacerlo nos apoyaremos en el proceso de umbralización que ya vimos en tutoriales previos, antes de aplicar dicho procedimiento suavizaremos la imagen con un filtro gaussiano para reducir el ruido en la imagen de salida.

src = cv2.imread('herramientas.jpg')

gray = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray, (7, 7), 3)

t, dst = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_TRIANGLE)

El resultado se muestra en la imagen inferior, a la izquierda la imagen obtenida con el tutorial antes mencionado, a la derecha el resultado obtenido al aplicarse el filtro gaussiano previo a la umbralización.

suavisado y umbralización opencv

El siguiente paso es obtener los contornos, y luego dibujarlos sobre la imagen original, si lo deseamos, para detectar los contornos usamos la función findContours() debemos indicarle la imagen binaria en donde se ubicarán los contornos, luego establecemos como se retornarán los contornos, de momento utilizaremos RETR_TREE que establece una jerarquía de contornos, y al final indicamos el método usado para simplificar el contorno, de momento CHAIN_APPROX_SIMPLE.

# obtener los contornos
_, contours, _ = cv2.findContours(dst, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

# dibujar los contornos
cv2.drawContours(src, contours, -1, (0, 0, 255), 2, cv2.LINE_AA)

Dibujamos los contornos obtenidos con la función drawContours(), el primer parámetro indica en donde dibujar, el segundo es el contornos a dibujar, el -1 establece que deseamos dibujar todos los contornos encontrados, los demás parámetros son comunes a la operaciones de dibujo, por ahora el resultado es el siguiente:

Detección y extracción de contornos con OpenCV

Seguro notaste que se dibujaron varios contornos que tal vez no nos interesen, dependiendo de lo que deseemos hacer, por ejemplo, tenemos un contorno que rodea toda la imagen, hay uno pequeño en la parte superior derecha e inclusive tenemos contornos dentro de los contorno de las herramientas.

Una manera sencilla, no la única, de filtrar aquellos contornos no deseados es calcular el área de los mismos y establecer un rango mínimo y máximo aceptable, para calcular el área de un contorno utilizaremos contourArea().

for c in contours:
    area = cv2.contourArea(c)
    if area > 1000 and area < 10000:
        cv2.drawContours(src, [c], 0, (0, 255, 0), 2, cv2.LINE_AA)

Calcular área de un contorno

Si lo que deseamos obtener es el rectángulo más pequeño posible que contenga el contorno indicado, podemos usar la función boundingRect() de esta manera:

for c in contours:
    area = cv2.contourArea(c)
    if area > 1000 and area < 10000:
        (x, y, w, h) = cv2.boundingRect(c)
        cv2.rectangle(src, (x, y), (x + w, y + h), (0, 255, 0), 1, cv2.LINE_AA)

Rectángulo de contorno OpenCV Python

El siguiente paso es analizar la figura que produce el contorno obtenido y tratar de identificarla, por ejemplo, si deseamos crear una aplicación de identifique herramientas de carpintería, como el ejemplo de la primera imagen, analizaríamos el contornos y trataríamos de identificar el martillo, un serrucho, etc., pero esto queda para la siguiente publicación.

Código OpenCV Python Completo

import numpy as np
import cv2

src = cv2.imread('herramientas.jpg')

gray = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray, (7, 7), 3)

t, dst = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_TRIANGLE)

_, contours, _ = cv2.findContours(dst, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

for c in contours:
    area = cv2.contourArea(c)
    if area > 1000 and area < 10000:
        cv2.drawContours(src, [c], 0, (0, 255, 0), 2, cv2.LINE_AA)

cv2.imshow('contornos', src)
cv2.imshow('umbral', dst)

cv2.waitKey(0)

Descarga las imágenes usadas en este tutorial: herramientas.jpg | martillo.jpg

Comentarios

Entradas populares de este blog

Conectar SQL Server con Java

Entrenar OpenCV en Detección de Objetos

Procesamiento de imágenes en OpenCV

Acceso a la webcam con OpenCV

Conociendo la clase cv::Mat de OpenCV