7

Detección de colores con OpenCV y Python

Ya sea para fabricar cromas, analizar cultivos de células o segmentar imágenes térmicas, la detección de colores es omnipresente en el mundo de la visión por computador. En el tutorial de hoy veremos cómo detectar colores con la librería OpenCV y Python tanto en imágenes estáticas como en un vídeo en tiempo real. Empezaremos por un ejemplo muy sencillito que vamos a ir complicando poco a poco.

¿Qué necesitamos?

Para este tutorial necesitaremos Python con las siguientes librerías instaladas:

Para algunos ejemplos también necesitaréis una webcam configurada para que funcione con vuestro sistema operativo.

¡Y por supuesto, ya sabéis que me gusta trabajar con un poco de música! Hoy os dejo elegir entre la Nocturna de Chopin  ó Black Hill & Silent Island.

 


Un apunte para los que estéis en Linux o Mac. A día de hoy (Mayo de 2020) algunas versiones recientes de OpenCV dan problemas al llamar a la función cv2.imshow() y aparece un error parecido a este:
QObject::moveToThread: Current thread (0x2db1b40) is not the object's thread (0x3097410).
Cannot move to target thread (0x2db1b40)

(y con la versión 4.3.0 puede que directamente diga que la función imshow() no está implementada y os invite amablemente a escribirla).
En tal caso os recomiendo cambiar a una versión anterior de OpenCV o a utilizar otra librería (como Matplotlib) para mostrar las imágenes, puesto que de momento no hay forma fácil de solucionarlo.


Descargar la imagen de ejemplo

Debajo está la imagen que utilizaremos para la mayoría de ejemplos de este tutorial. Descargadla con el nombre ‘bolas_colores.jpg’.

Guardad esta imagen con el nombre ‘bolas_colores.jpg’

Todos los códigos de python que escribamos en este tutorial deberéis ejecutarlos en el mismo directorio en el que esté la imagen (o cambiar la ruta a la imagen cuando llaméis a la función cv2.imread() )


Ejemplo 1: Primeros pasos

Vamos a empezar detectando las bolas azules de la imagen.

¿Cómo lo hace OpenCV para detectar colores? En el espacio de color RGB podemos pensar cada píxel como un vector de tres componentes [R, G, B] que indican la cantidad de rojo, verde y azul. En OpenCV estos tres valores oscilan entre 0 y 255.

La forma más fácil de detectar colores es estableciendo un rango de valores mínimos y máximos para las componentes R,G,B y quedarnos con todos los píxeles que estén dentro de este rango. Por ejemplo, si queremos detectar píxeles azules podríamos fijarnos en los píxeles que cumplan:

  • El valor de su componente B sea alto, por ejemplo entre 100 y 255.
  • El valor de sus componentes G y R sean comparativamente más bajos, entre 0 y 120.

Podemos codificar este “rango” en dos vectores: un vector de “bajos” que guarde los valores mínimos, y un vector de “altos” que guarde los valores máximos:
bajos = [0,0,40]
altos = [120,120,255]

OpenCV utiliza el espacio de color BGR en vez de RGB (es decir, invierte el orden de las componentes R y B) así que el rango anterior se convertiría en:
bajos = [40,0,0]
altos = [255,120,120]

Para detectar colores OpenCV utiliza la función cv2.inRange() que recibe como parámetros una imagen y un rango de valores como el anterior, y crea una máscara con todos los píxeles que estén dentro del rango. Una máscara no es más que una imagen binaria cuyos píxeles sólo tienen los valores 0 ó 1 (negro/blanco puro).

Bien, ¡basta ya de explicaciones! Vamos a escribir un script en python que nos detecte las bolas azules:

# -*- coding: latin-1 -*-
"""
EJEMPLO 1 - Primeros pasos

Detectamos el color azul en una imagen estática.

Escrito por Glare y Transductor
www.robologs.net
"""
import cv2
import numpy as np

#Cargamos la imagen:
img = cv2.imread("bolas_colores.jpg")
#(Si la imagen está en otro directorio podéis escribir la ruta, p. ej: cv2.imread('/home/minombre/imagenes/bolas_colores.jpg')


#Establecemos el rango mínimo y máximo de (Blue, Green, Red):
azul_bajos = np.array([40,0,0])
azul_altos = np.array([255, 120, 120])
# Recordatorio: el rango sirve para determinar qué píxeles detectaremos.
# Cada píxel tiene asignado un valor [B, G, R] según su cantidad de Azul, Verde y Rojo. 
# Con el rango que hemos definido, detectaremos los píxeles que cumplan estas tres condiciones:
# -Su valor B esté entre 40 y 255
# -Su valor G esté entre 0 y 120
# -Su valor R esté entre 0 y 120


#Detectamos los píxeles que estén dentro del rango que hemos establecido:
mask = cv2.inRange(img, azul_bajos, azul_altos)


#Mostramos la imagen original y la máscara:
cv2.imshow("Original", img)
cv2.imshow("Azul", mask)

#Salimos pulsando cualquier tecla:
print("\nPulsa cualquier tecla para cerrar las ventanas\n")
cv2.waitKey(0)
cv2.destroyAllWindows()

Recordad que el programa debe ejecutarse en el mismo directorio en el que tengáis la imagen de las bolas. Si todo ha funcionado bien, veréis que aparecen dos ventanas. La primera es la imagen original en color, y la segunda es la máscara binaria en blanco y negro. Los píxeles blancos son aquellos que están dentro del rango que hemos establecido:


Ejemplo 2: BGR vs. HSV

En el espacio BGR, el azul es un color muy puro y por tanto es fácil determinar un rango de valores adecuado: basta con detectar aquéllos píxeles cuyo valor de Blue sea alto, y Green y Red sean bajos.

Sin embargo… ¿cómo podríamos detectar las bolas amarillas? ¿Hay que subir el verde y el azul…? ¿Y si además queremos que nos tome los píxeles ocres…? Como podéis ver, el espacio de color BGR a veces no es muy práctico para detectar colores.

Necesitamos otra forma de codificar los colores: el espacio de color HSV (Hue-Saturation-Value). Este espacio de color nos permite separar las propiedades del color en tres canales:

  • Hue – Este canal codifica la tonalidad del color: rojo, azul, amarillo, verde… En OpenCV el valor del Hue está entre 0-179.
  • Saturation – Este canal codifica la intensidad o pureza del color: cuanta menos saturación más grisáceo será el color. En OpenCV el valor de Saturation oscila entre 0-255.
  • Value – Este canal codifica la luminosidad: cuanto menor sea, más negro/oscuro será el color.

HSV representado como una rueda de colores.

Así pues, este espacio de color es perfecto porque nos permite separar las cualidades que definen el color en tres canales distintos (a diferencia del sistema BGR en el que las propiedades del color estaban “entremezcladas” en los tres canales).

Este nuevo código es muy parecido al del Ejemplo 1. La única diferencia está en que esta vez intentamos detectar las bolas amarillas; para hacerlo convertimos la imagen a HSV y definimos un rango adecuado:

# -*- coding: latin-1 -*-
"""
EJEMPLO 2 - HSV vs. BGR

Buscamos bolas de color amarillo en una imagen estática, convertida
de BGR a HSV.

Escrito por Glare y Transductor
www.robologs.net
"""

import cv2
import numpy as np

#Cargamos la imagen:
img = cv2.imread("bolas_colores.jpg")

#Convertimos la imagen a hsv:
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
#Nota 1: la constante COLOR_BGR2HSV indica que queremos pasar de BGR a HSV.
#Nota 2: la función cvtColor() también sirve para transformar a otros espacios de color.

#Establecemos el rango mínimo y máximo de H-S-V:
amarillo_bajos = np.array([20,50,50])
amarillo_altos = np.array([40, 255, 255])
#Recordatorio: El rango HSV funciona de la siguiente forma:
#-La 1a componente es la tonalidad (Hue), en nuestro caso amarillo.
#-La 2a componente es la saturación (Saturation) , que hace el color + o - grisáceo.
#-La 3a componente es el valor (Value), que hace el color + o - oscuro.


#Detectamos los píxeles que estén dentro del rango que hemos establecido:
mask = cv2.inRange(hsv, amarillo_bajos, amarillo_altos)


#Mostramos la imagen original y la máscara:
cv2.imshow("Original", img)
cv2.imshow("Amarillo", mask)

#Salimos pulsando cualquier tecla:
print("\nPulsa cualquier tecla para cerrar las ventanas\n")
cv2.waitKey(0)
cv2.destroyAllWindows()

 

Al ejecutar el código deberían aparecer dos ventanas: una con la imagen en color y la otra con la máscara correspondiente a los píxeles amarillos:


Ejemplo 3: Eliminar el ruido

Vamos progresando, pero nuestra máscara tiene mucho ruido y parece un cuadro puntillista (y no precisamente uno bonito). Necesitamos que en la máscara únicamente aparezca el área de las bolas, ignorando los píxeles de aquellas regiones que son demasiado pequeñas (y, por tanto, sean probablemente ruido). También queremos que elimine los “agujeros” que queden dentro de las regiones blancas.

 

La forma de hacerlo será definiendo un Kernel y aplicando las transformaciones morfológicas OPEN y CLOSE sobre la máscara.

# -*- coding: latin-1 -*-
"""
EJEMPLO 3 - Eliminar el ruido

Volvemos a detectar bolas amarillas, pero esta vez eliminamos el ruido de
la máscara definiendo un kernel y aplicando un CLOSE+OPEN

Escrito por Glare y Transductor
www.robologs.net
"""
import cv2
import numpy as np

#Cargamos la imagen:
img = cv2.imread("bolas_colores.jpg")

#Convertimos la imagen a HSV:
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)


#Establecemos el rango mínimo y máximo de HSV:
amarillo_bajos = np.array([20,50,50])
amarillo_altos = np.array([40, 255, 255])


#Detectamos los píxeles que estén dentro del rango que hemos establecido:
mask = cv2.inRange(hsv, amarillo_bajos, amarillo_altos)


#Creamos un kernel:
kernel = np.ones((6,6),np.uint8) #Matriz de 6x6 llena de '1'


#Eliminamos el ruido con un CLOSE seguido de un OPEN:
mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel)
mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel)


#Mostramos la imagen original y la máscara:
cv2.imshow("Original", img)
cv2.imshow("Amarillo", mask)


#Salir pulsando una tecla:
print("\nPulsa cualquier tecla para cerrar las ventanas\n")
cv2.waitKey(0)
cv2.destroyAllWindows()

Como podéis ver al ejecutar este código, la máscara ha quedado mucho más refinada que en el Ejemplo 2.


Ejemplo 4: Detectar múltiples colores

A veces nos puede interesar detectar varios colores diferentes a la vez. ¿Cómo podemos conseguirlo?

Una forma fácil es detectar cada color por separado (como habéis hecho hasta ahora) y crear una máscara para cada uno. Después estas máscaras pueden juntarse con la función cv2.bitwise_or(). Por ejemplo, si queremos detectar bolas azules y amarillas:

 

# -*- coding: latin-1 -*-
"""
EJEMPLO 4 - Detectar múltiples colores

Este código detecta los colores azul y amarillo en una imagen estática.

Escrito por Glare y Transductor
www.robologs.net
"""
import cv2
import numpy as np

#Cargamos la imagen:
img = cv2.imread("bolas_colores.jpg")

#Convertimos la imagen a hsv:
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

#Establecemos el rango mínimo y máximo de HSV:
azul_bajos = np.array([100,50,50])
azul_altos = np.array([130, 255, 255])
amarillo_bajos = np.array([20,50,50])
amarillo_altos = np.array([40,255,255])

#Detectamos los píxeles que estén dentro del rango que hemos establecido:
mask_azul = cv2.inRange(hsv, azul_bajos, azul_altos)
mask_amarillo = cv2.inRange(hsv, amarillo_bajos, amarillo_altos)

#Unimos estas dos mascaras:
mask_union = cv2.bitwise_or(mask_azul, mask_amarillo)

#Eliminamos el ruido de esta nueva máscara:
kernel = np.ones((6,6),np.uint8)
mask_union = cv2.morphologyEx(mask_union, cv2.MORPH_CLOSE, kernel)
mask_union = cv2.morphologyEx(mask_union, cv2.MORPH_OPEN, kernel)

#Mostramos la imagen original y la máscara:
cv2.imshow("Original", img)
cv2.imshow("Amarillo+Azul", mask_union)
print("\nPulsa cualquier tecla para cerrar las ventanas\n")
cv2.waitKey(0)
cv2.destroyAllWindows()

 

Y si tenéis ganas de más os propongo un pequeño ejercicio: en el espacio de color HSV, la tonalidad (Hue) del rojo está cortada y va de 0-20 y de 160-179 (aproximadamente). Ahora que ya sabéis cómo detectar varios colores, ¿os animáis a escribir un programa para detectar ÚNICAMENTE las bolas rojas? 😉


Ejemplo 5: Sliders

Incluso utilizando espacios de color como HSV a veces es complicado determinar cuál es el rango de colores óptimo. Para no tener que estar reescribiendo a cada momento el rango de colores, ¿no estaría chuli ejecutar el código y poder ir variando los parámetros de nuestro detector de colores mediante sliders? Pues es justamente lo que vamos a hacer:

# -*- coding: latin-1 -*-
"""
EJEMPLO 5 - Sliders

Este código detecta colores en una imagen estática. Los parámetros
(rango de colores, dimensión del kernel) pueden ajustarse mediante
sliders.

Escrito por Glare y Transductor
www.robologs.net
"""
import cv2
import numpy as np

#Cargamos la imagen y la convertimos a HSV:
img = cv2.imread("bolas_colores.jpg")
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

#Función auxiliar:
def nothing(x):
   pass

#Creamos la ventana con las trackbars:
cv2.namedWindow('Parametros')
cv2.createTrackbar('Hue Minimo','Parametros',0,179,nothing)
cv2.createTrackbar('Hue Maximo','Parametros',0,179,nothing)
cv2.createTrackbar('Saturation Minimo','Parametros',0,255,nothing)
cv2.createTrackbar('Saturation Maximo','Parametros',0,255,nothing)
cv2.createTrackbar('Value Minimo','Parametros',0,255,nothing)
cv2.createTrackbar('Value Maximo','Parametros',0,255,nothing)
cv2.createTrackbar('Kernel X', 'Parametros', 1, 30, nothing)
cv2.createTrackbar('Kernel Y', 'Parametros', 1, 30, nothing)


#Recordamos al usuario con qué tecla se sale:
print("\nPulsa 'ESC' para salir\n")


while(1): 
  #Leemos los sliders y guardamos los valores de H,S,V para construir los rangos:
  hMin = cv2.getTrackbarPos('Hue Minimo','Parametros')
  hMax = cv2.getTrackbarPos('Hue Maximo','Parametros')
  sMin = cv2.getTrackbarPos('Saturation Minimo','Parametros')
  sMax = cv2.getTrackbarPos('Saturation Maximo','Parametros')
  vMin = cv2.getTrackbarPos('Value Minimo','Parametros')
  vMax = cv2.getTrackbarPos('Value Maximo','Parametros')

  #Creamos los arrays que definen el rango de colores:
  color_bajos=np.array([hMin,sMin,vMin])
  color_altos=np.array([hMax,sMax,vMax])

  #Leemos los sliders que indican las dimensiones del Kernel:
  kernelx = cv2.getTrackbarPos('Kernel X', 'Parametros')
  kernely = cv2.getTrackbarPos('Kernel Y', 'Parametros')
 
  #Creamos el kernel:
  kernel = np.ones((kernelx,kernely),np.uint8)

  #Detectamos los colores y eliminamos el ruido:
  mask = cv2.inRange(hsv, color_bajos, color_altos)
  mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel)
  mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel)
 
  #Mostramos los resultados y salimos:
  cv2.imshow('Original',img)
  cv2.imshow('Mascara',mask)
  k = cv2.waitKey(5) & 0xFF
  if k == 27:
    break
cv2.destroyAllWindows()

 

Al ejecutarlo se abren tres ventanas: la imagen original, la máscara (por ahora es toda negra) y un panel con sliders:

 

Moviendo los sliders variará el contenido de la máscara:


Ejemplo 6: Webcam

Como ya habéis visto cómo hacer detección de colores sobre una imágen estática, hacer el paso a vídeo es trivial. Un vídeo (sea pregrabado o capturado con una webcam) no es más que una colección imágenes estáticas capturadas una tras de otra.

Para detectar colores en un vídeo vamos a seguir este esquema:

Esta vez vamos a detectar objetos de color AZUL. Aseguráos de que la webcam esté bien configurada y que la habitación dónde estéis disponga de buena iluminación.

# -*- coding: latin-1 -*-
"""
EJEMPLO 6 - Webcam

Este código detecta objetos de color azul en un vídeo en tiempo real.

Escrito por Glare y Transductor
www.robologs.net
"""
import cv2
import numpy as np

#Iniciar la webcam:
webcam = cv2.VideoCapture(0)
#Nota: si no funciona puedes cambiar el 0 por 1 o por la dirección de tu webcam (ej. "/dev/video0")


#Definimos el kernel:
kernel = np.ones((6,6), np.uint8)


#Establecemos el rango mínimo y máximo de HSV:
azul_bajos = np.array([100,50,50])
azul_altos = np.array([130, 255, 255])


#Recordamos al usuario con qué tecla se sale:
print("\nPulsa 'ESC' para salir\n")


while(1):

  #Capturamos una imagen con la webcam:
  valido, img = webcam.read()

  #Si la imagen se ha capturado correctamente, continuamos:
  if valido:

    #Convertimos la imagen a hsv:
    hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

    #Detectamos los píxeles que estén dentro del rango que hemos establecido:
    mask = cv2.inRange(hsv, azul_bajos, azul_altos)

    #Eliminamos el ruido con un CLOSE seguido de un OPEN:
    mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel)
    mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel)

    #Mostramos la imagen original y la máscara azul:
    cv2.imshow("Webcam", img)
    cv2.imshow("Azul", mask)

    #Salir con 'ESC':
    k = cv2.waitKey(5) & 0xFF
    if k == 27:
      cv2.destroyAllWindows()
      break

webcam.release()

 

¡Y eso no es todo! También vamos a adaptar el código del Ejemplo 5 para que funcione con la webcam:

# -*- coding: latin-1 -*-
"""
EJEMPLO 6 (bis) - Webcam

Este código detecta colores en un vídeo en tiempo real. Los parámetros
pueden ajustarse mediante sliders.

Escrito por Glare y Transductor
www.robologs.net
"""
import cv2
import numpy as np

#Iniciar la webcam:
webcam = cv2.VideoCapture(0)
#Nota: si no funciona, puedes cambiar el 0 por 1 o por la dirección de tu webcam (ej. "/dev/video0")


#Función auxiliar:
def nothing(x):
   pass


#Creamos la ventana con los sliders:
cv2.namedWindow('Parametros')
cv2.createTrackbar('Hue Minimo','Parametros',0,179,nothing)
cv2.createTrackbar('Hue Maximo','Parametros',0,179,nothing)
cv2.createTrackbar('Saturation Minimo','Parametros',0,255,nothing)
cv2.createTrackbar('Saturation Maximo','Parametros',0,255,nothing)
cv2.createTrackbar('Value Minimo','Parametros',0,255,nothing)
cv2.createTrackbar('Value Maximo','Parametros',0,255,nothing)
cv2.createTrackbar('Kernel X', 'Parametros', 1, 30, nothing)
cv2.createTrackbar('Kernel Y', 'Parametros', 1, 30, nothing)


#Recordamos al usuario con qué tecla se cierra:
print("\nPulsa 'ESC' para salir\n")


while(1):

  #Capturamos una imagen con la webcam:
  valido, img = webcam.read()

  #Si la imagen se ha capturado correctamente, continuamos:
  if valido:

    #Convertimos la imagen a hsv:
    hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

    #Leemos los sliders y guardamos los valores de H,S,V para construir los rangos:
    hMin = cv2.getTrackbarPos('Hue Minimo','Parametros')
    hMax = cv2.getTrackbarPos('Hue Maximo','Parametros')
    sMin = cv2.getTrackbarPos('Saturation Minimo','Parametros')
    sMax = cv2.getTrackbarPos('Saturation Maximo','Parametros')
    vMin = cv2.getTrackbarPos('Value Minimo','Parametros')
    vMax = cv2.getTrackbarPos('Value Maximo','Parametros')

    #Establecemos el rango mínimo y máximo de HSV:
    color_bajos = np.array([hMin, sMin, vMin])
    color_altos = np.array([hMax, sMax, vMax])

    #Detectamos los píxeles que estén dentro del rango que hemos establecido:
    mask = cv2.inRange(hsv, color_bajos, color_altos)

    #Leemos los sliders que definen las dimensiones del Kernel:
    kernelx = cv2.getTrackbarPos('Kernel X', 'Parametros')
    kernely = cv2.getTrackbarPos('Kernel Y', 'Parametros')

    #Creamos el kernel y eliminamos el ruido:
    kernel = np.ones((kernelx, kernely), np.uint8)
    mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel)
    mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel)

    #Mostramos la imagen original y la máscara:
    cv2.imshow("Webcam", img)
    cv2.imshow("Mask", mask)

    #Salimos si se pulsa 'ESC':
    k = cv2.waitKey(5) & 0xFF
    if k == 27:
      cv2.destroyAllWindows()
      break

webcam.release()

Extra: ¿Cómo puedo encontrar el centro y el contorno de cada región/bola?

Encontrar el centro y el contorno de una región va un poco más allá del alcance de este artículo, pero si te interesa escribí este otro tutorial en el que expliqué como encontrar el centro y el contorno de las bolas de una supuesta mesa de billar:

Este era el resultado final. Cada bola tiene marcado el centro (rojo) y el contorno (verde).

Si quisiéramos hacer lo mismo con nuestra imagen, nos encontraríamos con el problema de que las bolas están pegadas entre sí y nos marcaría con un mismo contorno la región  correspondiente a varias bolas. Habría que utilizar un método como Watershed para separarlas (que también queda fuera del alcance de este tutorial).


Errores y preguntas frecuentes

Como es costumbre cuando redacto un tutorial de visión por computador, intento recoger (algunos) de los errores más frecuentes que podéis encontrar a la hora de probar los ejemplos. Si encontráis un error que no está recogido aquí podéis dejarme un comentario, pero por favor: leed y revisad bien todos los pasos del tutorial y/o aseguráos que una búsqueda en Google no resuelve el problema (más de la mitad de las dudas que contestamos en Robologs se resuelven con el primer resultado de una búsqueda por Internet).

Y lógicamente, si encontráis algún error en el tutorial estaré muy agradecida si me avisáis 😉

1. QObject::moveToThread error

Como he dicho al principio, si utilizáis alguna versión reciente de Python puede que aparezca un error como este al iniciar el programa:

QObject::moveToThread: Current thread (0x1d2c9cf0) is not the object's thread (0x1d347b20).
Cannot move to target thread (0x1d2c9cf0)

Por lo que he leído, este error se debe a una incompatibilidad de OpenCV con las librerías de QT, y no hay una forma sencilla de resolverlo. Si os ocurre, os sugiero cambiar a una versión anterior de OpenCV y/o de Python. Alternativamente podéis usar Matplotlib para mostrar las imágenes, o podéis utilizar cv2.imwrite() para guardar el resultado en una imagen y después abrirla con otro programa.

2. No se puede cargar la imagen

Si OpenCV no puede abrir la imagen de ejemplo sobre la que hay que detectar colores, aparecerá un error parecido a este:

Traceback (most recent call last):
File "deteccion.py", line 19, in
img_hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
cv2.error:
/build/opencv-ys8xiq/opencv-2.4.9.1+dfsg/modules/imgproc/src/color.cpp:3737:
error: (-215) scn == 3 || scn == 4 in function cvtColor

Si habéis copiado los ejemplos sin hacer cambios, comprobad que la imagen de las bolas esté en el mismo directorio en el que estáis ejecutando el programa. Si utilizáis una imagen que esté en otro directorio, comprobad que la ruta que le habéis pasado a la función cv2.imread() sea la correcta.

3. ¿Cómo puedo detectar el color [X]?

Una pregunta recurrente que recibí en la versión antigua de este tutorial era cómo detectar un color particular que no estuviera en los ejemplos (por ejemplo marrón, naranja, púrpura…).

La respuesta siempre es la misma: tienes que definir un rango adecuado. Para hacerlo puedes utilizar el Ejemplo 5 de este tutorial cargando una imagen que contenga todas las tonalidades que te gustaría detectar, e ir ajustando los sliders.

La otra opción es abrir un programa de diseño gráfico que pueda trabajar con HSV (como Gimp, Inkscape o Photoshop) y utilizar la paleta de colores para determinar los valores del rango que deseas detectar.

Ten en cuenta que algunos de estos programas utilizan rangos un poco diferentes para los colores (Hue puede ir de 0-255 o de 0-359 en vez de 0-179). En tal caso tendrás que hacer una regla de tres para convertirlos.

4. ¿Cómo puedo detectar un color especificado por el usuario?

Es tan fácil como crear un diccionario dónde cada opción que pueda elegir el usuario tenga asociado un rango.

5. (Visual Studio) No se encuentra ‘imread’ ni ‘imwrite’

Si programáis con Visual Studio puede que os aparezca este error:
Module ‘cv2’ has no ‘imread’ member pylint(no-member)
Module 'cv2' has no 'imwrite' member pylint(no-member)

Por muy absurdo que parezca, la forma de resolverlo consiste en cambiar la línea de código:
import cv2
Por:
from cv2 import cv2
[Fuente]

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.

guest
7 Comments
más nuevos primero
más antiguos primero
Inline Feedbacks
Ver todos los comentarios
jorge acuna
jorge acuna
2 meses

Hola buenos días, mi nombre es jorge acuña, leí tu articulo y me pareció muy interesante, quiero hacer un proyecto para detectar el impacto de una ojiva en un blanco de papel y dar una puntuación.

La cámara que estoy utilizando es una fpv y lo proyecto en una tableta con android, podrías decirme que tendría que hacer.

Gracias y espero tu amable respuesta.
jorge.acuna1@gmail.com

Angel
Angel
2 meses

Como hago para tomar la imagen con la webcam
por qué quedan abiertas las dos ventanas de la webcam y de la mascara pero no logro capturar la imagen??

Romeo
Romeo
2 meses

Interesante articulo, esta muy bien. No puedo utilizar colores en HEX>>?