? CONTANDO OBJETOS (Aplicando detección de bordes con CANNY) en Python-OpenCV
En el post anterior habíamos hablado de como contar objetos usando threshold o umbralización simple, ahora vamos a hacer algo similar con la diferencia que estaremos usando detección de bordes para encontrar los objetos (cartas o barajas) que deseamos contar.
El proceso será el siguiente:
- Leer la imagen de entrada.
- Transformarla a escala de grises.
- Aplicar detección de bordes con cv2.Canny.
- Buscar los contornos correspondientes a los objetos (cartas).
- Contar/Enumerar cada uno de los objetos (cartas) encontradas.
Leer la imagen de entrada
En esta ocasión vamos a usar la siguiente imagen, de la cual debemos enumerar las 4 cartas o barajas que aparecen en ella.
import cv2 imagen = cv2.imread('cartas.png')
Y empezamos importando OpenCV con import cv2, ahora leeremos la imagen que vamos a analizar, en este caso cartas.png, y procedemos a visualizarla, todo este proceso ya lo hemos hecho anteriormente en los videos.
Transformar una imagen de BGR a escala de grises
Para la transformación de BGR a escala de grises usaremos cv2.cvtColor
, de la siguiente manera:
grises = cv2.cvtColor(imagen, cv2.COLOR_BGR2GRAY)
Aplicar detección de bordes con cv2.Canny
Para poder realizar la detección de bordes, vamos a usar la función cv2.Canny
. Esta función nos pide:
- Imagen de entrada
- Primer umbral (minVal)
- Segundo umbral (maxVal)
Puedes ingresar otros datos, para saber más sobre ellos puedes visitar este enlace, y si deseas estudiar el proceso que realiza esta función te dejo este otro.
Para que los bordes se dibujen o no, se necesita de dos umbrales, minVal y maxVal. De este modo, todos los bordes superiores a maxVal se dibujarán. Los bordes que estén dentro del maxVal y minVal se dibujarán solo si se encuentran conectados a los que superan maxVal. Por el contrario todos los bordes por debajo de minVal no serán dibujados. Veamos la siguiente imagen:
La figura 3 muestra una imagen que tomé de la documentación de OpenCV, la cual he separado en 3 colores. El color verde correspondiente a valores mayores a maxVal indica todos los bordes que serán dibujados, en este caso A. Luego en el color naranja están los bordes que se encuentran dentro de minVal y maxVal, en donde se dibujarán los bordes que se encuentren conectados a los que superen maxVal, por ello C se dibujará, mientras que el borde B no se dibujará. Por último el área roja indica los valores menores a minVal, los cuales no serán dibujados.
Una vez que tengamos claro el uso de estos dos umbrales podemos hacer pruebas para analizar como se van dibujando los distintos bordes dada una imagen. Para el caso de enumeración de cartas o barajas que estamos viendo hoy, se ha especificado:
bordes = cv2.Canny(grises, 100, 200)
De este modo obtendremos la siguiente imagen:
NOTA: Puedes cambiar los valores de los umbrales de tal manera que puedas conseguir los que mejor se adapten a tu proyecto.
Encontrar y dibujar los contornos de la imagen binaria
Una vez que tenemos la imagen binaria, correspondiente a la detección de bordes, podemos aplicar la función cv2.findContours
. De este modo podremos encontrar las 4 cartas/barajas que se encuentran en la imagen. Este procedimiento también se lo realizó en el post anterior.
#Para OpenCV3 _, ctns, _ = cv2.findContours(bordes, cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
#Para OpenCV4 ctns, _ = cv2.findContours(bordes, cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
Una vez obtenidos los contornos, procedemos a dibujarlos con cv2.drawContours
(Si quieres más información de esta función, visita este post).
cv2.drawContours(imagen, ctns, -1, (0,0,255), 2)
Gracias a esta función se dibujarán todos los contornos encontrados de color rojo con un grosor de 2 pixeles en imagen
. Veamos:
Contar / enumerar cada uno de los objetos (cartas) encontradas
Para poder contar cada uno de los objetos encontrados, podríamos imprimir la cantidad de elementos almacenados en cnts
, que corresponderán al número total de cartas encontradas:
print('Número de contornos encontrados: ', len(ctns))
En este caso se imprimirá el número de contornos encontrados:
Ahora con esta información no nos queda más que imprimirla en la imagen.
texto = 'Contornos encontrados: '+ str(len(ctns)) cv2.putText(imagen, texto, (10,20), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 0, 0), 1) cv2.imshow('Imagen', imagen) cv2.waitKey(0) cv2.destroyAllWindows()
En la línea 16 estoy convirtiendo el número de contornos (len(cnts)
) a string y uniéndolo a un mensaje ('Contornos encontrados: '
), esto es necesario para que se pueda visualizar en la función cv2.putText
. Si tienes un poco de problemas con esta función te recomiendo este post.
Y este sería el resultado final:
A continuación te dejo todo el programa. ¡Espero que te sirva!.
import cv2 imagen = cv2.imread('cartas.png') grises = cv2.cvtColor(imagen, cv2.COLOR_BGR2GRAY) bordes = cv2.Canny(grises, 100, 200) #Para OpenCV3 #_, ctns, _ = cv2.findContours(bordes, cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE) #Para OpenCV4 ctns, _ = cv2.findContours(bordes, cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE) cv2.drawContours(imagen, ctns, -1, (0,0,255), 2) print('Número de contornos encontrados: ', len(ctns)) texto = 'Contornos encontrados: '+ str(len(ctns)) cv2.putText(imagen, texto, (10,20), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 0, 0), 1) cv2.imshow('Imagen', imagen) cv2.waitKey(0) cv2.destroyAllWindows()
Bien, esto es todo por este post. Recuerda que puedes experimentar con cada una de las funciones que he utilizado aquí. Y cualquier pregunta que tengas la puedes dejar en la sección de los comentarios, así nos podemos ayudar entre todos a aprender más y más. ¡Lindo día!
Referencias
- https://docs.opencv.org/3.1.0/da/d22/tutorial_py_canny.html
Una consulta openCV sirve para detectar pilas de objetos ejemplo una pila de cuadernos,libros, o cajas no armadas es posible que si las cuente
Hola Jose David, tendrías que estudiar los métodos ya existentes para el proyecto que deseas realizar, y poder aplicar alguna función de OpenCV. O tal vez necesites ayuda de aprendizaje automático con otras librerías.
hola,como puedo detectar los bordes de figuras unicolor, es decir tengo piezas fabricada mediante impresion 3D y tiene figuras o extrusiones internas como cuadrados y circulos, pero los bordes lo qu ehace es una comparativa de pixels a pixels y filtra por color, dado que son unicolor es complejo encontrar un umbral que me de los contorno que necesito,el resultado obtenido realmente solo son lineas al azar en el resultado binario despues del tratamiento
Hola Sergio, a mi parecer debes encontrar una forma para que esas figuras puedan resaltar más, creo que podrías hacerlo manejando distinta iluminación.
Hola Gabriela como estas 🙂 ? gracias por tu ayuda por tus videos, te quería preguntar si fuera para contar los objetos pero en tiempo real, pero que solo los que aparezcan en cámara y no que se se valla almacenando el contador como se debería hacer ?
Hola Sebastian, podrías usar tracking de objetos para poder conseguirlo.
Hola Gabriela ¿Se puede aplicar la tecnica con video streaming de una banda de producción conectada a un motor con velocidad variable con un máximo de 1800 rpm o debo convertir el videostreaming a imagen en tiempo real?
Hola Gaby, espero que te encuentres muy bien, gracias por todo tu conociemiento que compartes.
Soy nueva en estos, y me gustaria saber como podria detectar ciertos objetos pero en tiempo real, y con una camara SP32Cam. te super agradezco la ayuda.
Hola Gabriela, gracias por compartir tus conocimientos, me has ayudado mucho.