En OpenCV findContours es una función que permite encontrar los n contornos externos e internos de una imagen binaria (blanco y negro). Por ejemplo, de acuerdo al método de detección seleccionado, se puede encontrar una jerarquía del contorno mayor al menor. También se diferencia entre contornos externos e internos.
La función de OpenCV findContours se puede utilizar para crear aplicaciones con visión artificial. Por ejemplo, una de sus principales usos es en la detección de formas, colores u objetos en conjunto con otro tipo de funciones. También si te interesan mas funciones, puedes ver este otro tutorial, como para enmarcar el contorno.
Conocimientos previos
- Crear proyecto nuevo en QT.
- OpenCV GaussianBlur.
- Variables Mat.
- Leer imágenes con imRead y OpenCV en QT.
- Cambio de espacio de color con cvtColor.
- Cronometro con QTimer.
Sintaxis para c++.
- void findContours(Imagen-Binaria, Vector-de-vectores, Jerarquía, Modo, Método, Offset);
Donde:
- Imagen-binaria. Es una imagen de 1 canal de 8 bits. Por ejemplo 8UC1. Todos los pixeles que no son cero, se consideran como ‘1’. En otras palabras, si el pixel no esta apagado se considera como color blanco (imagen binaria). Por lo general se utilizan a las siguientes funciones para obtener una imagen binaria:
- compare(): Compara dos arreglos matriciales (imágenes) o un arreglo con un valor escalar.
- inRange(): Permite crear un filtro ventana para cada uno de los canales de una imagen.
- threshold(): Es un filtro tipo umbral, que permite digitalizar una imagen (crear imagen binaria) a partir de los pixeles que superen cierto limite.
- adaptiveThreshold(): Está función es similar a la anterior, sólo que aplica un filtro adaptativo tipo umbral.
- Canny(): Permite detectar bordes, se desarrollo por John F. Canny en 1986.
- Vector-de-vectores. En esta variable, se guardan a todos los contornos encontrados. Por ejemplo, cada contorno se guarda como un vector de puntos (coordenadas). Entonces esta es una salida de la función y se considera como un vector de vectores de puntos que guardan al contorno.
- Jerarquía. Es otra variable de salida que guarda la organización de los contornos de la imagen. Por ejemplo, cuantos contornos tiene. Los contornos se guardan con un indice. Entonces, el primer contorno esta guardado en Vector-de-vectores[0]. Incluso cada contorno puede tener contornos internos, de esta forma un contorno del contorno cero se guardaría en Vector-de-vectores[0][n] donde n es el enésimo contorno.
Modos de detección de contornos con OpenCV findcontours
Puede ser cualquiera de las siguientes constantes:
- CV_RETR_EXTERNAL. Regresa como salida los contornos externos extremos.
- CV_RETR_LIS. Este parámetro regresara los contornos sin establecer jerarquía de tamaños o cualquier otro tipo de jerarquía.
- CV_RETR_CCOMP. Regresa cualquier contorno y los organiza en una jerarquía de dos niveles. Por ejemplo, el primer nivel considera a los contornos externos. Entonces en el segundo nivel estan los limites o perímetros internos.
- CV_RETR_TREE. Retornará a todos los contornos y construye una jerarquía de contornos anidados.
- Método. Configura el método para la detección de los contornos.
- CV_CHAIN_APPROX_NONE. Guarda todos los puntos de los contornos.
- CV_CHAIN_APPROX_SIMPLE. Considera solo los segmentos horizontales, verticales y diagonales dejando sólo sus puntos que forman a dichos segmentos. Un ejemplo, sería un rectángulo, el cual estaría formado por 4 puntos.
- CV_CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS. Es un algoritmo especial.
- Offset. Es un parámetro opcional, esta opción permite desplazar cada punto del contorno encontrado.
Área de un contorno con contourArea
En OpenCV findcontours también incluye a una función que permite determinar el área de un contorno. Entonces, se puede utilizar a la función contourArea. Entonces, está es una función de openCV que recibe como entrada a un vector de puntos. Por ejemplo:
- int area = contourArea(contorno[i]);
Donde i es el enésimo contorno encontrado con la función de OpenCV findContours.
Encontrar el área de un color en QT Creator con OpenCV findCountours
Para este ejemplo, se comenzara a partir del programa que se desarrollo en el tutorial de OpenCV inRange. Entonces el código se puede descargar del siguiente enlace: https://hetpro-store.com/TUTORIALES/EjemplosProgramas/QT-OpenCV-9-inRange.zip
- #include <QDebug>
Paso # 1 – Descargar el código de OpenCV
El código del proyecto que se utilizo en la función inRange, crea un filtro de color para formar una imagen binaria. Es importante también mencionar que se requiere agregar a la biblioteca qDebug.
Paso # 2. Agregar las siguientes variables globales:
- using namespace std;
- RNG rng(12345);
Paso # 3. Agregar una etiqueta nueva, que se llamará labelContornos.
Paso # 4 – Agregar el siguiente código en MainWindow.cpp en la función fTimer.
El siguiente código se agregará después de la función inRange y antes de mostrar las imágenes en la función fTimer. La línea 1, declara un vector de vectores, cada vector guardará un vector de los puntos que forman el contorno encontrado. Mientras que la segunda línea declara un vector que permite guardar la jerarquía de los contornos. Un paso importante es la línea 3, la cual guarda una copia de la imagen binaria que resulta del proceso del filtro de color (inRange). Entonces en la línea 5 se detectan los contornos. Para la línea 6 a la 12 se crea un ciclo for que permite para los i contornos encontrados, dibujar el contorno así como imprimir en la consola el área enésima encontrada.
- vector<vector<Point> > contornos;
- vector<Vec4i> jerarquia;
- Mat copiaImagenFiltrada;
- copiaImagenFiltrada = ImagenFiltrada;
- findContours(copiaImagenFiltrada, contornos, jerarquia, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );
- Mat drawing = Mat::zeros( copiaImagenFiltrada.size(), CV_8UC3 );
int area = 0; - for( int i = 0; i< (int)contornos.size(); i++ ){
- Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) );
- drawContours( drawing, contornos, i, color, 2, 8, jerarquia, 0, Point() );
- area = contourArea(contornos[i]);
- qDebug() << «Area » << i << » : » << area;
- }
Paso # 5 – Mostrar a las imágenes del filtro de color y de los contornos.
- QImage qImage = Mat2QImage(drawing);
- QPixmap pixmap = QPixmap::fromImage(qImage);
- ui->labelContornos->clear();
- ui->labelContornos->setPixmap(pixmap);
- qImage = Mat2QImage(ImagenFiltrada);
- pixmap = QPixmap::fromImage(qImage);
- ui->labelInrange->clear();
- ui->labelInrange->setPixmap(pixmap);
Código en github*
*Si navegas en un dispositivo móvil, te recomendamos seguir el siguiente enlace al código de la función ftimer en github.
Resultado
Descargar el proyecto completo
Autor: Dr. Rubén Estrada Marmolejo