30

Detectar múltiples colores con OpenCV y Python

¡Hola! En este minitutorial voy a resolver una duda que mucha gente me ha comentado: cómo detectar múltiples colores en una imagen con OpenCV y Python.

¿Cómo se hace? Se aplica detección de color a la imagen creando una máscara para cada color que uno quiera detectar: una máscara para los verdes, otra para los azules, otra para los rojos, amarillos… y  se juntan con la función cv2.add().

Los que no sepáis cómo detectar colores con OpenCV, deberíais seguir primero mi Tutorial de Detección de Colores con OpenCV y Python.

¿Hecho? Pues bien, poned un poco de música y empezamos.


 

1- Imagen estática

Para empezar  vamos a detectar los tres colores rojo, verde y azul del logo de OpenCV y los uniremos en una sola máscara.

Guardad la imagen bajo el nombre opencv_logo.png . En el mismo directorio dónde se haya bajado la imagen, cread un nuevo fichero de python. ¡A programar se ha dicho!

Lo primero es lo de siempre: importar las librerías de OpenCV y Numpy, abrir la imagen y convertirla a espacio de color HSV.

import cv2
import numpy as np

imagen = cv2.imread('opencv_logo.png')
hsv = cv2.cvtColor(imagen, cv2.COLOR_BGR2HSV)

 

Después, hay que crear un rango para cada color. Primero los azules y verdes:

#Rango de colores detectados:
#Verdes:
verde_bajos = np.array([49,50,50])
verde_altos = np.array([107, 255, 255])
#Azules:
azul_bajos = np.array([100,65,75], dtype=np.uint8)
azul_altos = np.array([130, 255, 255], dtype=np.uint8)

 

El rango de rojos es un poco más puñetero… si miráis la rueda de color hsv, veréis que el HUE de los rojos está entre 0 – 20, y 240 – 255 (más o menos).

Habrá que crear dos rangos diferentes para los rojos: uno que tenga el Hue entre 0 y 20 y el otro entre 240 y 255.

#Rojos:
rojo_bajos1 = np.array([0,65,75], dtype=np.uint8)
rojo_altos1 = np.array([12, 255, 255], dtype=np.uint8)
rojo_bajos2 = np.array([240,65,75], dtype=np.uint8)
rojo_altos2 = np.array([256, 255, 255], dtype=np.uint8)

 

Se crean las máscaras de la forma normal con la función inRange():

#Crear las mascaras
mascara_verde = cv2.inRange(hsv, verde_bajos, verde_altos)
mascara_rojo1 = cv2.inRange(hsv, rojo_bajos1, rojo_altos1)
mascara_rojo2 = cv2.inRange(hsv, rojo_bajos2, rojo_altos2)
mascara_azul = cv2.inRange(hsv, azul_bajos, azul_altos)

 

Ahora viene lo nuevo: se juntan las máscaras en una sola máscara final que llamaremos ‘mask’. La función cv2.add sólo puede recibir dos argumentos, por lo que habrá que aplicarla varias veces.

#Juntar todas las mascaras
mask = cv2.add(mascara_rojo1, mascara_rojo2)
mask = cv2.add(mask, mascara_verde)
mask = cv2.add(mask, mascara_azul)

 

Para terminar mostramos la imagen inicial, la máscara y salimos al pulsar ESCAPE.

#Mostrar la mascara final y la imagen
cv2.imshow('Finale', mask)
cv2.imshow('Imagen', imagen)

#Salir con ESC
while(1):
    tecla = cv2.waitKey(5) & 0xFF
    if tecla == 27:
        break

cv2.destroyAllWindows()

 

Al final tendréis algo como esto:

# Algoritmo de deteccion de colores multiples
# Por Glar3
# www.robologs.net
#
# Busca los píxeles rojos, verdes y azules de una imagen

import cv2
import numpy as np

imagen = cv2.imread('opencv_logo.png')
hsv = cv2.cvtColor(imagen, cv2.COLOR_BGR2HSV)

#Rango de colores detectados:
#Verdes:
verde_bajos = np.array([49,50,50])
verde_altos = np.array([107, 255, 255])
#Azules:
azul_bajos = np.array([100,65,75], dtype=np.uint8)
azul_altos = np.array([130, 255, 255], dtype=np.uint8)
#Rojos:
rojo_bajos1 = np.array([0,65,75], dtype=np.uint8)
rojo_altos1 = np.array([12, 255, 255], dtype=np.uint8)
rojo_bajos2 = np.array([240,65,75], dtype=np.uint8)
rojo_altos2 = np.array([256, 255, 255], dtype=np.uint8)



#Crear las mascaras
mascara_verde = cv2.inRange(hsv, verde_bajos, verde_altos)
mascara_rojo1 = cv2.inRange(hsv, rojo_bajos1, rojo_altos1)
mascara_rojo2 = cv2.inRange(hsv, rojo_bajos2, rojo_altos2)
mascara_azul = cv2.inRange(hsv, azul_bajos, azul_altos)

#Juntar todas las mascaras
mask = cv2.add(mascara_rojo1, mascara_rojo2)
mask = cv2.add(mask, mascara_verde)
mask = cv2.add(mask, mascara_azul)

#Mostrar la mascara final y la imagen
cv2.imshow('Finale', mask)
cv2.imshow('Imagen', imagen)

#Salir con ESC
while(1):
    tecla = cv2.waitKey(5) & 0xFF
    if tecla == 27:
        break

cv2.destroyAllWindows()


2- Vídeo en tiempo real:

Este otro programa es para detectar colores en un vídeo tomado por una webcam en tiempo real. Detectaremos objetos verdes y amarillos.

No voy a comentarlo línea por línea como el programa anterior porque la idea es la misma. Además el tutorial que he mencionado al principio explica cómo utilizar una webcam.

#Algoritmo de deteccion de colores
#Por Glar3
#www.robologs.net
#
#Detecta objetos verdes y amarillos
 
import cv2
import numpy as np
 
#Iniciar la camara
captura = cv2.VideoCapture(0)
 
while(1):
     
    #Capturamos una imagen y la convertimos de RGB -> HSV
    _, imagen = captura.read()
    hsv = cv2.cvtColor(imagen, cv2.COLOR_BGR2HSV)
 
    #Rango de colores detectados:
    #Verdes:
    verde_bajos = np.array([49,50,50], dtype=np.uint8)
    verde_altos = np.array([100, 255, 210], dtype=np.uint8)
    #Amarillos:
    amarillo_bajos = np.array([16,76,72], dtype=np.uint8)
    amarillo_altos = np.array([30, 255, 210], dtype=np.uint8)
 
    #Detectar los pixeles de la imagen que esten dentro del rango de verdes
    mascara_verde = cv2.inRange(hsv, verde_bajos, verde_altos)
    
    #Detectar los pixeles de la imagen que esten dentro del rango de amarillos
    mascara_amarillo = cv2.inRange(hsv, amarillo_bajos, amarillo_altos)
 
    #Filtrar el ruido aplicando un OPEN seguido de un CLOSE
    kernel = np.ones((6,6),np.uint8)
    mascara_verde = cv2.morphologyEx(mascara_verde, cv2.MORPH_CLOSE, kernel)
    mascara_verde = cv2.morphologyEx(mascara_verde, cv2.MORPH_OPEN, kernel)
    mascara_amarillo = cv2.morphologyEx(mascara_amarillo, cv2.MORPH_CLOSE, kernel)
    mascara_amarillo = cv2.morphologyEx(mascara_amarillo, cv2.MORPH_OPEN, kernel)

    #Unir las dos mascaras con el comando cv2.add()
    mask = cv2.add(mascara_amarillo, mascara_verde)

    #Mostrar la imagen de la webcam y la mascara verde
    cv2.imshow('verde', mask)
    cv2.imshow('Camara', imagen)
    tecla = cv2.waitKey(5) & 0xFF
    if tecla == 27:
        break
 
cv2.destroyAllWindows()

 

Al igual que antes se sale con ESCAPE.

 

Bueno, espero que esto resuelva vuestras dudas sobre cómo detectar varios colores a la vez con OpenCV. Si queréis preguntarme algo más, mis circuitos visuales leerán vuestros comentarios con fruición.

¡Hasta la próxima!

Actualización 3/11/2016: Resolución de errores frecuentes con OpenCV+Python

Gl4r3

Brillante, luminosa y cegadora a veces, Glare es tan artista como técnica. Le encanta dar rienda suelta a sus módulos de imaginación y desdibujar los ya de por si delgados límites que separan el mundo de la electrónica y el arte. Su mayor creación hasta la fecha es un instrumento capaz de convertir los colores y la luz en música. Cuándo sus circuitos no están trabajando en una nueva obra electrónica, le gusta dedicar sus ciclos a la lectura o a documentar sus invenciones para beneficio de los humanos. Sus artilugios favoritos son aquellos que combinan una funcionalidad práctica con un diseño elegante y artístico.

Antes de comentar, por favor, lee las Normas

30 Comentarios en "Detectar múltiples colores con OpenCV y Python"

avatar
Ordenar por:   más nuevos primero | más antiguos primero
Martin Dominguez
Humano

Buenas, sabras como poder hacer condiciones con esto por ejemplo que me mande algun mensaje si es de color azul, o otro mensaje si es de otro color

Humano
Humano

Buenas noches, muy buenos los tutoriales todos me han funcionado bien pero no entiendo porque en este no me funciona cv2.cvtColor(…), este es el error que me sale:

OpenCV Error: Assertion failed ((scn == 3 || scn == 4) && (depth == CV_8U || depth == CV_32F)) in cv::cvtColor, file C:buildsmaster_PackSlaveAddon-win32-vc12-staticopencvmodulesimgprocsrccolor.cpp, line 7946
Traceback (most recent call last):
File “C:UsershpMy DocumentsLiClipse WorkspaceOPENCVcOpenCV__init__.py”, line 5, in
hsv = cv2.cvtColor(imagen, cv2.COLOR_BGR2HSV)
cv2.error: C:buildsmaster_PackSlaveAddon-win32-vc12-staticopencvmodulesimgprocsrccolor.cpp:7946: error: (-215) (scn == 3 || scn == 4) && (depth == CV_8U || depth == CV_32F) in function cv::cvtColor

De antemano muchas gracias

Humano
Humano

Encontre el error jajaj la imagen no estaba en la carpeta, la proxima vez voy a leer los comentarios si alguien tiene algun error parecido.

Andrés Chavarría
Humano

Hola! Me encantan estos tutoriales, y me estan siendo muy utiles, en especial este. Ahora quiero hacer una pregunta. Como podría hacer para ademas de color, discriminar por forma?, ambos a la vez.

trackback

[…] cuándo la cámara empiece a capturar imágenes. Para que véais como hacerlo, el código del tutorial para detectar varios colores quedaría […]

Mr Robot
Humano

Antes que nada quiero felicitarte por el gran trabajo que haces al compartir tus conocimientos en cada uno de tus tutoriales.
Tengo un problemilla cuando corro el programa desde una imagen estática, me aparece el siguiente error:
Traceback (most recent call last):
File “C:/Python27/DetectaMultipleColores.py”, line 7, in
hsv = cv2.cvtColor(imagen, cv2.COLOR_BGR2HSV)
error: C:\builds\master_PackSlaveAddon-win32-vc12-static\opencv\modules\imgproc\src\color.cpp:7646: error: (-215) (scn == 3 || scn == 4) && (depth == CV_8U || depth == CV_32F) in function cv::ipp_cvtColor
De antemano muchas gracias.

Mr Robot
Humano

Encontré el error…no me dí cuenta que la imagen no estaba en la carpeta donde se encuentra el script, moví el archivo de la imagen a la carpeta donde esta el script y el error se solucionó 🙂 . Aún así aprovecho para volver a agradecer por compartir tus conocimientos, saludos desde México.

albertohp
Humano

Hola una consulta, como podria hacerse para que detecte varios objetos de color verde? probe tu codigo y solo detecta 1 objeto de color verde pero si se usan varios objetos se marea. Saludos y muchas gracias, eres un gran aporte a la comunidad amigo :).

JoseA
Humano

Hola Gl4r3, necesito tu ayuda por farvor. A la hora de correr el programa me sale un error y no se como solucionarlo. El erro es el siguiente:
error:/home/pi/opencv-3.1.0/modules/imgproc/src/color.cpp: 8141: error: (-215)(scn ==3, scn == 4) && (depth == CV_8U, depth == CV_32f) in fuction cvtColor.
Seria de gran ayuda que me pudieras solucionar el problema. Gracias

Ricardo Vivas
Humano

Hola glare, como puedo hacer para saber cual color se detectó en mayor proporción

Ricardo Vivas
Humano

intento hacerlo de esta manera pero siempre me arroja no
if np.array_equal(mask, mascara_verde):
print “verde”
else:
print “no”

Ricardo Vivas
Humano

AAAIIIIUUUUUUDAA

JorgeG
Humano

Clare tu blog es fantástico!… te comento lo de que deseo y espero me puedas orientar: necesito un algoritmo en Python que emplee la librería OpenCV que dado un vídeo 4K y 360 grados de la toma de un árbol frutal haga un reconocimiento automático y el conteo de las frutas en ese árbol. Sabes si existe? Has hecho algo similar que me puedas compartir?

Aprendiz
Humano

Buen tutorial por si te interesa Adrian Rosebrock creador del blog http://pyimagesearch.com/ desarrollo unos scripts en python que puedes instalar con pip (pip install imutils) entre los cuales veras incluido un pequeño script con trackbars para visualizar diferentes rangos de colores . Si te interesa opencv Adrian es especialista en procesamiento de imagenes y pone recursos muy interesantes en su blog . Yo personalmente os seguire a ambos sin dudarlo.

Anónimo
Humano

Gracias!!!! glare, una consulta para el vídeo en tiempo real, se puede usar el primer código, unir mas mascaras y así tener mas colores?

N4n0
Admin

Que pasa, Glare? Hoy no pones música clásica en el tutorial!

N4n0
Admin

Te han reprogramado?? D:

Luis Americo
Humano

Agradecido por el tutorial aprendi bastante sobre todo con respecto al rango de colores. Tengo la duda estuve buscando en gimp y inkscape el rango, sin embargo los valores que aparecen en tu programa son diferentes. Es decir No logro ubicarlo, tu programa al pelo. Sería interesante ver como en inkscape se logra esto. Gracias

wpDiscuz