? RESALTANDO UN COLOR de un fondo en grises | OpenCV con Python
¡Qué grato tenerte aquí en un nuevo tutorial!. Hace unos días una lectora de este blog dejó el siguiente comentario:
«Hola, una pregunta como puedo hacer que el fondo se vea en escala de grises y solo se visualice el color rojo?» – Alondra
En primer lugar agradezco mucho a los lectores del blog y a los suscriptores del canal que siempre tienen ideas, preguntas y demás para colaborar con el contenido que desarrollo sobre visión por computador.
Pues bien, el planteamiento de Alondra me pareció muy interesante de realizar, ya que he visto algunas aplicaciones que llevan a cabo este tipo de efecto sobre imágenes, agregándoles gran atractivo y un toque especial. Por ello, en esta ocasión te mostraré como resaltar un color de una imagen, mientras que el fondo de la misma se presenta en escala de grises, para este procedimiento estaré usando la detección de colores que habíamos empleado en tutoriales anteriores.
CONTENIDO
- ¿En qué consiste nuestro problema a resolver?
- Determinar los rangos del color a detectar en el espacio de color HSV
- Leer la imagen y transformarla a otros espacios de color
- Detección del color rojo en la imagen
- Fondo en escala de grises
- Sumando imágenes para obtener el efecto de resaltar el color rojo sobre grises
- Pero, ¿este programa puede servir para otros colores?
– Programa completo
– Programa para realizar el mismo procedimiento sobre un video
¿En qué consiste nuestro problema a resolver?
Lo que necesitamos hacer es, dada cierta imagen detectar el color rojo dentro de ella. Una vez que obtengamos la detección, podremos dejar este área a color, mientras que transformaremos el resto de la imagen a escala de grises.
Este proceso necesitará también de la suma de dos imágenes, para fusionarlas y lograr este efecto, a continuación veremos como realizarlo.
Determinar los rangos del color a detectar en el espacio de color HSV
Voy a crear un programa llamado redGrayImage.py, allí especificaremos las librerías que usaremos y además los rangos en donde se encuentra el color rojo a detectar. De ser necesario, puedes dirigirte a mis posts sobre detección de colores para una explicación más detallada: Detección de colores en OpenCV – Python (En 4 pasos) y DETECCIÓN DE COLORES Y Tracking en OpenCV – Parte2.
import cv2 import numpy as np import imutils rojoBajo1 = np.array([0, 140, 90], np.uint8) rojoAlto1 = np.array([8, 255, 255], np.uint8) rojoBajo2 = np.array([160, 140, 90], np.uint8) rojoAlto2 = np.array([180, 255, 255], np.uint8)
Línea 1 a 3: Importamos OpenCV, numpy e imutils.
Línea 5 a 8: Establecemos los rangos en donde está presente el color rojo en el espacio de color HSV.
Leer la imagen y transformarla a otros espacios de color
Para la realización de este ejemplo voy a usar la siguiente imagen:
Vamos a continuar con nuestro programa:
# Leer la imagen image = cv2.imread('img_00.jpeg') image = imutils.resize(image, width=640) # Pasamos las imágenes de BGR a: GRAY (esta a BGR nuevamente) y a HSV imageGray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) imageGray = cv2.cvtColor(imageGray, cv2.COLOR_GRAY2BGR) imageHSV = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
Línea 11: Leemos la imagen de entrada correspondiente a la figura 1.
Línea 12: En esta línea estoy redimensionando la imagen a un ancho de 640. Podrías omitir este paso.
Línea 15 y 16: Transformamos la imagen de entrada a escala de grises, y esta a su vez la volvemos a transformar a BGR, con esto conseguiremos tener una imagen en 3 canales que mostrará niveles de grises.
NOTA: Si hubiéramos mantenido solo la imagen de la línea 15 en escala de grises, obtendríamos errores en pasos posteriores, específicamente con la suma de imágenes de 3 canales.
Línea 17: Transformamos la imagen de entrada al espacio de color HSV.
Detección del color rojo en la imagen
Una vez que tenemos la imagen en HSV, podemos proceder a la detección del color rojo, veamos:
# Detectamos el color rojo maskRojo1 = cv2.inRange(imageHSV, rojoBajo1, rojoAlto1) maskRojo2 = cv2.inRange(imageHSV, rojoBajo2, rojoAlto2) mask = cv2.add(maskRojo1,maskRojo2) mask = cv2.medianBlur(mask, 7)
Línea 20 y 21: De imageHSV
vamos a encontrar los rangos del color rojo contenidos en dicha imagen, estos se almacenarán en maskRojo1
y maskRojo2
en forma de imagen binaria, en donde el color blanco representará la presencia del color rojo, mientras que en negro la no presencia del mismo
Línea 22 y 23: Con cv2.add
sumamos las dos imágenes binarias maskRojo1
y maskRojo2
para obtener una sola que se almacenará en mask
, a esta a su vez le aplicaré cv2.medianBlur
para mejorar los bordes del área en blanco. Veamos como se vería la imagen contenida en mask
:
En la figura 2 podemos apreciar como se ha detectado el color rojo que se representa en blanco, pero ¿qué te parece si visualizamos el color real de este área en la imagen?, para ello emplearemos la siguiente línea:
redDetected = cv2.bitwise_and(image,image,mask=mask)
Línea 24: Vamos a ayudarnos de cv2.bitwise_and
, para tomar el color rojo detectado de la imagen de entrada y visualizarlo, mientras que el resto de la imagen se mantendrá en negro. Si quieres saber un poco más sobre esta función te dejo este post: Operadores BITWISE (AND-OR-NOT-XOR) con OpenCV y Python :).
Ahora que ya tenemos los objetos, en este caso las rosas rojas en su color original, procedemos a trabajar en el fondo en grises de la imagen.
Fondo en escala de grises
En este paso necesitamos de la imagen de la línea 16, en ella en donde está ubicado el color rojo deberá mostrarse en negro, mientras que el resto de la imagen debe estar en grises. Con ello podremos sumar dicha imagen con la que tenemos en redDetected
para realizar el efecto del color rojo sobre un fondo en grises.
# Fondo en grises invMask = cv2.bitwise_not(mask)
Línea 27: Vamos a invertir la imagen binaria con cv2.bitwise_not
. Y obtendremos lo siguiente:
Prosigamos con la programación, ¡ya falta poco!
bgGray = cv2.bitwise_and(imageGray,imageGray,mask=invMask)
Línea 28: Ahora al igual que en la línea 24 usamos cv2.bitwise_and
. En el área blanca se mostrará la imagen en grises, veamos:
Ahora solo nos queda sumar las dos imágenes contenidas en las figuras 3 y 5.
Sumando imágenes para obtener el efecto de resaltar el color rojo sobre grises
Ya estamos en la parte final de este tutorial. Procedemos a realizar el siguiente planteamiento:
Como puedes apreciar en la figura 6, vamos a sumar dos imágenes que ya habíamos obtenido anteriormente para finalmente obtener el efecto plateado, veamos el resto del programa:
# Sumamos bgGray y redDetectedCreamos finalImage = cv2.add(bgGray,redDetected) # Visualización cv2.imshow('Image',image) cv2.imshow('finalImage', finalImage) cv2.waitKey(0) cv2.destroyAllWindows()
Línea 31: Con cv2.add
sumamos las dos imágenes bgGray
y redDetected
. Para más información sobre esta función por favor visita el siguiente tutorial: ADICIÓN y SUSTRACCIÓN de imágenes con OpenCV y Python.
Línea 34 a 37: Visualizamos la imagen de entrada y la imagen resultante. Esta visualización se presentará hasta que se presione una tecla y finalmente se cerrarán las ventanas creadas.
¡Lo hemos logrado, ya hemos finalizado con la programación! En la figura 7 podemos ver los resultados y en el inicio de este post también puedes ver otros ejemplos de imágenes a las cueles se les ha aplicado el mismo procedimiento.
Pero, ¿este programa puede servir para otros colores?
La respuesta es si, podrías usarlo para cualquier otro color. Para resaltar el color amarillo por ejemplo, tendrías que modificar los rangos en HSV para detectar dicho color. Mira a continuación como se vería:
Programa completo
import cv2 import numpy as np import imutils rojoBajo1 = np.array([0, 140, 90], np.uint8) rojoAlto1 = np.array([8, 255, 255], np.uint8) rojoBajo2 = np.array([160, 140, 90], np.uint8) rojoAlto2 = np.array([180, 255, 255], np.uint8) # Leer la imagen image = cv2.imread('img_00.jpeg') image = imutils.resize(image, width=640) # Pasamos las imágenes de BGR a: GRAY (esta a BGR nuevamente) y a HSV imageGray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) imageGray = cv2.cvtColor(imageGray, cv2.COLOR_GRAY2BGR) imageHSV = cv2.cvtColor(image, cv2.COLOR_BGR2HSV) # Detectamos el color rojo maskRojo1 = cv2.inRange(imageHSV, rojoBajo1, rojoAlto1) maskRojo2 = cv2.inRange(imageHSV, rojoBajo2, rojoAlto2) mask = cv2.add(maskRojo1,maskRojo2) mask = cv2.medianBlur(mask, 7) redDetected = cv2.bitwise_and(image,image,mask=mask) # Fondo en grises invMask = cv2.bitwise_not(mask) bgGray = cv2.bitwise_and(imageGray,imageGray,mask=invMask) # Sumamos bgGray y redDetected finalImage = cv2.add(bgGray,redDetected) # Visualización cv2.imshow('Image',image) cv2.imshow('finalImage', finalImage) cv2.waitKey(0) cv2.destroyAllWindows()
Programa para realizar el mismo procedimiento sobre un video
import cv2 import numpy as np import imutils cap = cv2.VideoCapture('video1.mp4') rojoBajo1 = np.array([0, 140, 90], np.uint8) rojoAlto1 = np.array([8, 255, 255], np.uint8) rojoBajo2 = np.array([160, 140, 90], np.uint8) rojoAlto2 = np.array([180, 255, 255], np.uint8) while True: ret, frame = cap.read() if ret == False: break frame = imutils.resize(frame,width=640) # Pasamos las imágenes de BGR a: GRAY (esta a BGR nuevamente) y a HSV frameGray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) frameGray = cv2.cvtColor(frameGray, cv2.COLOR_GRAY2BGR) frameHSV = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) # Detectamos el color rojo maskRojo1 = cv2.inRange(frameHSV, rojoBajo1, rojoAlto1) maskRojo2 = cv2.inRange(frameHSV, rojoBajo2, rojoAlto2) mask = cv2.add(maskRojo1,maskRojo2) mask = cv2.medianBlur(mask, 7) redDetected = cv2.bitwise_and(frame,frame,mask=mask) # Fondo en grises invMask = cv2.bitwise_not(mask) bgGray = cv2.bitwise_and(frameGray,frameGray,mask=invMask) # Sumamos bgGray y redDetected finalframe = cv2.add(bgGray,redDetected) # Visualización cv2.imshow('Frame',frame) cv2.imshow('finalframe', finalframe) if cv2.waitKey(1) & 0xFF == 27: break cap.release() cv2.destroyAllWindows()
En la línea 5 puedes establecer el uso de un video en directo, o puedes leer un video almacenado.
Y esto fue todo por este tutorial, espero que te haya gustado y que lo encuentres útil. Nos vemos en un próximo post/video.
Hola me gusto mucho el vídeo y me has resulto muchas dudas, solo que me surgió una duda mas. Este efecto de resaltar el color rojo de un fondo gris de una imagen como se podría hacer para un vídeo. Lo he intentado pero no logro concretar un buen resultado.
Muchas felicidades por tu blog, me gusta como explicas y me ayuda mucho para seguir mejorando.
Hola Esteban, me alegra mucho que te haya gustado el tutorial. Te comento que el código para realizarlo a través de un video está en este mismo post, échale un ojo a: Programa para realizar el mismo procedimiento sobre un video, que está al final de este post.
Me gusto mucho el video, pero ¿como se podrían remarcar los contornos de los objetos rojos de un vídeo a escala de grises ?
Hola Juan Pablo, muchas gracias. No entiendo muy bien lo que me preguntas, podrías explicármelo?
Claro! Muchas gracias por atender mi duda
Mira estoy intentando realizar la detección de los contornos de todos los objetos que tengan el color rojo en un video con fondo gris. Utilizando el código que anterior mente proporcionas (RESALTANDO UN COLOR de un fondo en grises )
Pero no concreto un resultado ya que me marca varios errores.
Quiero realizar la detección de los contornos de todo aquello que tenga color rojo en un vídeo con fondo gris
Hola como seria la conversión para el amarillo, no se si podrías pararlo por aca, excelente video, gracias.