? ROPA INVISIBLE – OpenCV y Python
En el post de hoy vamos a divertirnos un poco creando un efecto de invisibilidad con el color rojo de mi chaqueta. Para ello preparé un video que podrás encontrar en mi repositorio en gitHub, además del archivo de python que crearemos hoy.
El proceso a seguir es el siguiente:
- Leer un video o realizar video streaming
- Detectar el color rojo
- Haciendo invisible la chaqueta roja
- Reemplazar el color rojo de la chaqueta por el del fondo
- Quitar el color rojo de la chaqueta del video
- Unir las dos imágenes
Leer un video
A pesar que preparé un video para este post, si deseas probarlo a través de un video streaming eres libre de hacerlo.
import cv2 import numpy as np cap = cv2.VideoCapture('video1.mp4') bg = None rojoBajo1 = np.array([0, 150, 40], np.uint8) rojoAlto1 = np.array([8, 255, 255], np.uint8) rojoBajo2 = np.array([170, 150, 40], np.uint8) rojoAlto2 = np.array([180, 255, 255], np.uint8) while True: ret, frame = cap.read() if ret == False: break if bg is None: bg = frame
Línea 1 y 2: Importamos OpenCV y numpy.
Línea 6: Se declara la variable bg = None
, luego a esta se le asignará la imagen del fondo o background.
Línea 8 a 11: Se especifican los límites bajos y altos en donde se encuentra el color rojo dentro del espacio de color HSV. Puedes revisar esto más a fondo en este post.
Línea 13 a 17: Se leen los fotogramas correspondientes al video, estas imágenes se almacenan en la variable frame
. Luego si por alguna razón no se ha obtenido ninguna imagen salimos del ciclo con la línea 17.
Línea 19: Aquí necesitamos almacenar el fondo de la escena, por ello asignamos frame
a bg
.
Detectando el color rojo
Ahora es el momento de detectar el color rojo, para ello necesitamos del espacio de color HSV y de los límites bajos y altos que habíamos declarado en la sección previa. Luego vamos a mejorar la detección aplicando un filtro lineal para suavización y dilatando la imagen binaria obtenida.
Te recomiendo que veas mi video en youtube, en donde explico paso a paso cada uno de las secciones que veremos hoy.
frameHSV = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) maskRojo1 = cv2.inRange(frameHSV, rojoBajo1, rojoAlto1) maskRojo2 = cv2.inRange(frameHSV, rojoBajo2, rojoAlto2) mask = cv2.add(maskRojo1,maskRojo2) mask = cv2.medianBlur(mask, 13) kernel = np.ones((5,5),np.uint8) mask = cv2.dilate(mask, kernel, iterations=2)
Línea 22: Transformamos las imágenes de BGR al espacio de color HSV.
Línea 23 y 24: Se busca en la imagen frameHSV
los pixeles que estén dentro de los límites bajos y altos que declaramos en las líneas 8 a 11.
Línea 25: Unimos las imágenes binarias obtenidas en maskRojo1
y maskRojo2
ya que ambas corresponden al color rojo.
Línea 26 a 28: En la línea 26 usamos un filtro lineal para la suavización de la imagen binaria obtenida de la detección del color rojo. Esta nos ayuda a eliminar pequeñas áreas blancas que hacían de ruido en nuestra aplicación y a suavizar el borde de la chaqueta roja. En la línea 28 se está aplicando dilatación de imágenes que nos ayudará también a mejorar la imagen binaria.
A continuación veamos una imagen tomada del video y la imagen binaria mask
donde muestra la detección del color rojo correspondiente a la chaqueta.
- Imagen 1: Imagen de entrada
- Imagen2: Imagen binarizada (el área en blanco representa la presencia del color rojo)
Haciendo invisible la chaqueta roja
Es hora de hacer magia, ¿estás listo?. Para crear este efecto de transparencia necesitamos unas pocas líneas de código, ya verás que es un proceso bastante sencillo.
Bien, dado que hemos obtenido una imagen binaria en donde la región en blanco representa el color rojo y en negro la no presencia del mismo, necesitamos que en el área blanca se vea el fondo de la escena (como puedes ver en la parte superior izquierda de la imagen).
Luego procederemos a invertir la imagen binaria, para obtener todo el video a color a excepción de la región en donde está presente la chaqueta, que se mostrará en negro (como puedes ver en la parte inferior izquierda de la imagen).
Una vez que obtengamos estas dos imágenes, debemos unirlas para obtener el efecto de INVISIBILIDAD.
Reemplazar el color rojo de la chaqueta por el del fondo
Ahora que tenemos la imagen binaria mask
, nuestro objetivo será que en vez de la chaqueta, se vea el fondo de la imagen, por ello usaremos cv2.bitwise_and
(para más información de esta función puedes dar clic en este post), para ello necesitamos una imagen que contenga el fondo de la escena (este procedimiento es parecido al de detección de movimiento con sustracción de imágenes, por si deseas puedes revisarlo).
areaColor = cv2.bitwise_and(bg, bg, mask=mask)
Línea 29: Usamos cv2.bitwise_and
, especificamos bg
(que corresponde al fondo/background de la imagen) en los dos primeros argumentos, y mask
que corresponde a la detección del color rojo. Este procedimiento se almacenará en areaColor
.
Tomando en cuenta la imagen la imagen 1 e imagen 2 que vimos en la sección anterior, al aplicar la línea 29 obtendremos:

Imagen 3: El área donde está presente la chaqueta roja ahora se visibiliza el fondo de la escena.
Quitar el color rojo de la chaqueta del video
Ahora invertimos mask
, aplicándole cv2.bitwise_not
, y obtendremos que en vez de las áreas que antes aparecían en blanco ahora se muestran en negro, y las de negro en blanco. Esto nos servirá para que todo lo que NO corresponda al color de la chaqueta roja se visualice normalmente.
maskInv = cv2.bitwise_not(mask) sinAreaColor = cv2.bitwise_and(frame,frame,mask=maskInv)
Línea 30: Aplicamos cv2.bitwise_not
a la imagen binaria obtenida de la detección del color rojo.
Línea 31: Aplicamos cv2.bitwise_and
, pero esta vez especificamos frame
, frame
, y la máscara invertida.
- Imagen 4: Visualización de ‘maskInv’
- Imagen 5: Visualización de ‘sinAreaColor’
Unir las dos imágenes
El último paso para obtener el efecto de transparencia o invisibilidad, será sumar estas dos imágenes con cv2.addWeighted
.
finalFrame = cv2.addWeighted(areaColor,1,sinAreaColor,1,0)
Línea 32: Aquí unimos las imágenes areaColor
y sinAreaColor
, con cv2.addWeighted
.

Imagen 6: Visualización ‘finalFrame’
Por último, visualizamos…
cv2.imshow('Frame',frame) #cv2.imshow('mask', mask) #cv2.imshow('areaColor', areaColor) #cv2.imshow('maskInv',maskInv) #cv2.imshow('sinAreaColor',sinAreaColor) cv2.imshow('finalFrame',finalFrame) if cv2.waitKey(1) & 0xFF == ord('q'): break cap.release() cv2.destroyAllWindows()
Línea 32 a 37: Tenemos las distintas imágenes que se pueden mostrar en el proceso de realización de esa pequeña aplicación. Para comparar entre las imágenes de entrada y de salida podemos visualizar frame
y finalFrame
.
Las líneas restantes corresponden a la finalización del video cuando se presione la tecla ‘q’ o cuando salga del ciclo ‘while’.
Programación completa
import cv2 import numpy as np cap = cv2.VideoCapture('video1.mp4') bg = None rojoBajo1 = np.array([0, 150, 40], np.uint8) rojoAlto1 = np.array([8, 255, 255], np.uint8) rojoBajo2 = np.array([170, 150, 40], np.uint8) rojoAlto2 = np.array([180, 255, 255], np.uint8) while True: ret, frame = cap.read() if ret == False: break if bg is None: bg = frame frameHSV = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) maskRojo1 = cv2.inRange(frameHSV, rojoBajo1, rojoAlto1) maskRojo2 = cv2.inRange(frameHSV, rojoBajo2, rojoAlto2) mask = cv2.add(maskRojo1,maskRojo2) mask = cv2.medianBlur(mask, 13) kernel = np.ones((5,5),np.uint8) mask = cv2.dilate(mask, kernel, iterations=2) areaColor = cv2.bitwise_and(bg, bg, mask=mask) maskInv = cv2.bitwise_not(mask) sinAreaColor = cv2.bitwise_and(frame,frame,mask=maskInv) finalFrame = cv2.addWeighted(areaColor,1,sinAreaColor,1,0) cv2.imshow('Frame',frame) #cv2.imshow('mask', mask) #cv2.imshow('areaColor', areaColor) #cv2.imshow('maskInv',maskInv) #cv2.imshow('sinAreaColor',sinAreaColor) cv2.imshow('finalFrame',finalFrame) if cv2.waitKey(1) & 0xFF == ord('q'): break cap.release() cv2.destroyAllWindows()
Resultado Final
Ahora ya podemos visualizar el efecto de invisibilidad.
Referencias
- https://www.learnopencv.com/invisibility-cloak-using-color-detection-and-segmentation-with-opencv/
- https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_imgproc/py_filtering/py_filtering.html
- https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_imgproc/py_morphological_ops/py_morphological_ops.html
Excelente post.