La Visión Artificial, una aplicación clave del aprendizaje profundo, permite a los ordenadores obtener información a partir de datos visuales, como imágenes y archivos de vídeo. En esta era de la revolución de la IA, herramientas como OpenCV facilitan a desarrolladores y no matemáticos la creación de aplicaciones de visión artificial sin necesidad de codificarlas desde cero. OpenCV es una potente librería que simplifica el desarrollo de sistemas que pueden contar objetos, como tornillos, tuercas o monedas, gracias a técnicas como la detección de bordes y el análisis de contornos.
Preprocesamiento de Imágenes para el Análisis de Contornos
Las imágenes digitales no son perfectas; cualquier señal digital o analógica está expuesta a diferentes fuentes de ruido. Para un análisis efectivo en visión artificial, el preprocesamiento es una fase crucial que nos permitirá aislar los objetos dentro de una imagen. Cada una de estas fases dará como resultado una imagen que será la entrada de la siguiente.
Conversión a Escala de Grises y Suavizado Gaussiano
Una vez que se ha cargado la imagen, lo primero que se debe hacer es convertirla a escala de grises con OpenCV. Esto es vital, ya que para aplicar detectores de bordes como Canny, la imagen debe estar en escala de grises. El suavizado Gaussiano es una operación fundamental para eliminar el ruido y suavizar la imagen, es decir, eliminar los detalles, lo que puede verse como un desenfoque en una cámara fotográfica. Este filtrado es un promediado ponderado que sigue la Campana de Gauss para una aproximación natural de cómo ve el ojo humano. Para poder aplicarlo en una imagen, debemos hacerlo en dos dimensiones.
- El segundo parámetro es el kernel o máscara de convolución. Recuerda que debe ser impar.
- El último parámetro es sigma (σ) y representa la desviación estándar en el eje X, es decir, la anchura de la campana Gaussiana. Por defecto, se suele dejar a 0.
Detección de Bordes y Binarización
La detección de bordes es una técnica muy utilizada que nos permite aislar los objetos y separarlos del fondo. Los bordes son cambios de intensidad pronunciados en la imagen. El detector de bordes Canny es una herramienta popular para identificarlos. Este proceso involucra varios pasos, donde se aplican umbrales mínimos y máximos para determinar si un píxel forma parte de un borde o no. Un valor de 50 para el mínimo y 150 para el máximo puede ser un buen comienzo.
Posteriormente, la imagen de entrada para emplear cv2.findContours debe ser binaria, lo que significa que únicamente puede presentar blanco y negro. Como norma general, la imagen binarizada debe tener el fondo negro y los objetos a ser buscados deben ser blancos. Para obtener una imagen binarizada, se puede usar la detección de bordes con cv2.Canny o la umbralización simple con cv2.threshold.
Lea también: IVA 21% Excel
Detección de Contornos con cv2.findContours
Los contornos son una herramienta esencial para el análisis de formas, y la detección y reconocimiento de objetos. La documentación de OpenCV los describe como: «Los contornos se pueden explicar simplemente como una curva que une todos los puntos continuos (a lo largo del límite), que tienen el mismo color o intensidad».
Para encontrar y dibujar contornos de un objeto o región de interés, OpenCV emplea la función cv2.findContours. Este método nos devuelve una lista de contornos, así como la jerarquía de contornos. La jerarquía de contornos demuestra la relación que tienen los contornos, por ejemplo, si tenemos un contorno y dentro de este se encuentra otro, y dentro de este otro más.
Parámetros de cv2.findContours
La función cv2.findContours requiere varios parámetros:
- imagenbinarizada: Es la imagen donde hemos detectado los bordes o umbralizado. Este método modifica esta imagen, por lo que es conveniente que sea una copia.
- modo_contorno: Es un parámetro interno del algoritmo que indica el tipo de contorno que queremos. Puede tomar diferentes valores, los cuales exploraremos a continuación.
- metodo_aproximacion: Este parámetro indica cómo queremos aproximar el contorno. Básicamente, le decimos si queremos almacenar todos los puntos del contorno.
Modos de Recuperación de Contornos (modo_contorno)
Vamos a visualizar los contornos obtenidos y analizaremos brevemente cada uno de los modos de recuperación del contorno. Estos modos afectarán directamente al argumento de salida 'hierarchy'.
| Modo de Recuperación | Descripción |
|---|---|
| cv2.RETR_EXTERNAL | Recupera únicamente los contornos externos, ignorando los contornos internos. |
| cv2.RETR_LIST | Recupera todos los contornos sin establecer ninguna relación jerárquica. |
| cv2.RETR_CCOMP | Organiza los contornos en una jerarquía de dos niveles. Es decir, si tenemos un contorno externo, tendrá jerarquía 1, y uno interno, jerarquía 2. |
| cv2.RETR_TREE | Recupera todos los contornos y reconstruye una jerarquía completa de todos los contornos anidados. |
Métodos de Aproximación del Contorno (metodo_aproximacion)
En cuanto a los métodos de aproximación del contorno, veremos cv2.CHAIN_APPROX_NONE y cv2.CHAIN_APPROX_SIMPLE. En ambos casos se procederá a almacenar los puntos x e y, correspondientes a cada contorno encontrado; la diferencia está en la cantidad de puntos que se almacenan. Por ejemplo, al usar cv2.CHAIN_APPROX_NONE se pueden almacenar 1092 puntos para un contorno, mientras que al usar cv2.CHAIN_APPROX_SIMPLE, se almacenan 4 puntos para ese mismo contorno, simplificando el contorno a sus vértices esenciales.
Lea también: Guía IVA reducido
Esto es especialmente útil cuando se analizan muchos objetos en imágenes grandes, ya que permite optimizar el tiempo de procesado y la memoria.
Dibujando Contornos con cv2.drawContours
Por último, nos queda dibujar los contornos que hemos encontrado en la imagen. La función cv2.drawContours permite pintar estos contornos sobre la imagen original. Un bucle for se puede usar para dibujar los contornos conforme se presiona una tecla, facilitando la visualización individual o secuencial de los contornos detectados.
Detección de Figuras Geométricas Simples
Para la detección de figuras geométricas simples, como triángulos, cuadrados, rectángulos o círculos, podemos combinar la detección de contornos con otras funciones de OpenCV.
Aproximación Poligonal con cv2.approxPolyDP
La función cv2.approxPolyDP aproxima curvas o una curva poligonal con una precisión especificada. Por ejemplo, un círculo, al aplicarle esta función, se representaría como un polígono con muchísimos lados y vértices. Los parámetros clave para esta función son:
- Epsilon: Es el parámetro que especifica la precisión de aproximación. Para obtener este parámetro, se utiliza la función cv2.arcLength, que calcula el perímetro del contorno. Se suele determinar mediante prueba y error, por ejemplo, un porcentaje del 1% del perímetro.
- Closed: Es true cuando la curva aproximada es cerrada, es decir, que tanto el primer como el último vértice están conectados.
La longitud de la variable resultante de cv2.approxPolyDP nos permite clasificar las figuras. Si obtenemos 3, estaríamos en presencia de un triángulo; si obtenemos 4, podría ser un cuadrado o un rectángulo; y si obtenemos 5, sería un pentágono, y así sucesivamente. Para diferenciar entre un cuadrado y un rectángulo, se utiliza la función cv2.boundingRect, que obtiene los puntos x, y, el ancho y alto del contorno actual, y se calcula el aspect ratio.
Lea también: ¿Cómo localizar tus XML del SAT?
Si un contorno presenta más de 10 vértices después de la aproximación, generalmente se considera un círculo.
Aspect Ratio para Diferenciar Formas
El aspect ratio se obtiene de la relación del ancho y alto del objeto. Por ejemplo, si un cuadrado tiene un ancho y alto de 50, su aspect ratio sería 1. Si un rectángulo tiene un ancho de 40 y un alto de 100, su aspect ratio sería 0.4.
Operaciones Morfológicas y Elementos Estructurantes
Las operaciones morfológicas son esenciales para el preprocesamiento de imágenes, la eliminación de ruido y la simplificación de formas. Estas operaciones se aplican utilizando un elemento estructurante, que es una pequeña matriz o kernel que define la forma de la "ventana" que se desliza sobre la imagen. Es importante variar el tamaño y forma de este elemento estructurante para apreciar los distintos resultados.
Para aplicar estas operaciones, se utiliza la función cv::morphologyEx(...) de OpenCV, la cual permite aplicar diversas transformaciones morfológicas. Para indicar la operación deseada, se usa la enumeración cv::MorphTypes, que incluye opciones como MORPH_ERODE, MORPH_DILATE, MORPH_OPEN, MORPH_CLOSE, MORPH_GRADIENT, MORPH_TOPHAT, MORPH_BLACKHAT, y MORPH_HITMISS.
Gradiente Morfológico
La operación de Gradiente es equivalente a la diferencia entre las operaciones de dilatación y erosión. Esta operación es bastante útil cuando se desea buscar la silueta de una figura. Se aplica utilizando MORPH_GRADIENT en la función cv::morphologyEx.
Apertura y Cierre
La operación de apertura es el resultado de aplicar una erosión y después una dilatación. Sirve para eliminar ruido que se encuentre fuera de la estructura. Para aplicarla, se usa MORPH_OPEN. Se puede aumentar el tamaño del elemento estructurante o el número de iteraciones para eliminar marcas de ruido más grandes.
La operación de cierre se obtiene aplicando una dilatación y luego una erosión, siendo el inverso de la apertura. Sirve para limpiar la figura, es decir, eliminar el ruido interno de la misma. Se aplica usando MORPH_CLOSE en la función cv::morphologyEx.
