¡Saludos, estudiantes!. Hace un par de artículos explicábamos cómo podíamos coger una imagen, tratarla de un modo determinado (aplicando un filtro, en nuestro ejemplo de luminosidad), para a continuación tratar el resultado como una máscara que combinábamos con dos imágenes: en una, recortábamos la imagen siguiendo dicha máscara como patrón; en otra, recortábamos siguiendo el inverso de dicha máscara, de modo que ambas imágenes se superpusieran, complementándose de modo perfecto; éste era el resultado de nuestro ejemplo:
¿En qué se diferencia el video de la imagen estática?
Recordemos el programa más básico en Python que muestra en una ventana la imagen capturada por la webcam (tenéis más información en nuestro primer artículo de la serie):
import numpy as np
import cv2
cap = cv2.VideoCapture(0)
while(True):
ret, frame = cap.read()
cv2.imshow('Hola Mundo',frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
El código era muy sencillo: importamos las librerías numpy y cv2, declaramos un objeto cap asociado a nuestra webcam, y durante un bucle indefinido que dura hasta que pulsamos 'q' va asociando a dos objetos (son dos por necesidad de la propia librería) ret y frame cada imagen que captura, a la velocidad (en frames por segundo) de que sea capaz la propia webcam. Mostramos el segundo objeto, frame por una ventana denominada 'Hola Mundo' con la imagen capturada en ese instante, y repetimos el proceso.
Pruébalo, si no me crees (so desconfiado). Mira, mírame a mí haciendo el tonto (otra vez):
¿Cómo extrapolamos lo aprendido sobre filtros y máscaras a video?.
¡Hombre!, ¡hombre!, me alegro de que me hagas esa pregunta. La verdad es que no tengo ni idea. No, ahora en serio, como voy aprendiendo a base de experimentar y tocar teclas, lo que ahora me parece muy básico y sencillo me costó más de un par de semanas de investigación, experimentación y rezarle a San Google. Lo bueno de eso es que si eres tan pardillo como yo, lo que ahora te va a parecer muy difícil y casi cosa de magia, en cuanto lo leas un par de veces, te parecerá incluso lógico.
Análogamente al artículo que trabajaba con filtros e imágenes estáticas, vamos a aplicar un filtro de luminosidad a la imagen capturada por la webcam, de modo que los puntos más luminosos (las zonas blancas), en lugar de aparecer en la ventana de vídeo, serán sustituídos por los píxeles de la imagen estática que habremos cargado previamente. Concretamente, voy a utilizar esta foto del desierto (Sahara.jpg)
(por cierto, recomiendo que no haya mucha diferencia de tamaño en píxeles entre el archivo de imagen y el tamaño de salida de video que pueda dar tu webcam; por ejemplo, esta foto está en 640x480 píxeles, lo que supone un ajuste perfecto).
Básicamente, el proceso será el siguiente:
- Importar las librerías numpy y cv2
- Cargar el archivo con la foto que queremos mezclar con nuestro video ('Sahara.jpg'). Ya sabes que el archivo debe estar en la misma ruta que el programa, o de lo contrario tendrás que especificar la ruta completa.
- Iniciamos el bucle de grabación con while(True): , que se interrumpirá sólo si tecleamos 'q' (o la tecla que elijas). Ahora, en cada ciclo del proceso:
- Al objeto frame (junto con ret) se le asigna la imagen capturada por la webcam
- Hacemos una conversión a escala de grises con cv2.cvtColor() que asignamos al objeto gray, que a su vez se utilizará para hacer un filtro de luminosidad con cv2.threshold(), que se aplicará al objeto filtro. Aplicándole el bitwise_not(), nos quedaremos con el filtro contrario, que se asignará al objeto filtroInvertido
- Ya tenemos dos filtros opuestos. Al video le recortaremos toda la parte blanca aplicándole un bitwise_and() con filtroInvertido. Así tenemos el objeto videoRecortado. A la imagen le haremos lo mismo, pero combinándola con filtro (pues queremos recortarle toda la parte que no vamos a usar, a saber, la parte de video que no es de color muy blanco). Obtenemos así el objeto fotoRecortada.
- El método cv2.add() nos permite combinar estos últimos dos objetos contrapuestos en el objeto videoFinal, que se muestra por la ventana con el título 'Filtros en video' (Nota: me como algunas tildes en comentarios y demás porque sois muy tiquismiquis con el tema de la codificación.
- Si no se ha pulsado 'q', repetimos el bucle.
Código y resultado final.
Sí, sí, lo sé. Estáis impacientes. ¡Ea, pues!. ¡Ahí está vuestro código!
import numpy as np
import cv2
cap = cv2.VideoCapture(0)
#Aqui cargas la imagen en jpg que tu quieras
imagen=cv2.imread('Sahara.jpg')
#Iniciamos ciclo que se cerrara al pulsar 'q'
while(True):
ret, frame = cap.read()
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
#Aplicamos filtro de luminosidad y creamos mascaras filtro y filtroInvertido
ret,filtro=cv2.threshold(gray,150,255,cv2.THRESH_BINARY)
filtroInvertido=cv2.bitwise_not(filtro)
#Recortamos video y foto con ambas mascaras
videoRecortado = cv2.bitwise_and(frame,frame,mask = filtroInvertido)
fotoRecortada=cv2.bitwise_and(imagen,imagen,mask=filtro)
#Sumamos las imagenes recortadas y las mostramos por ventana
videoFinal=cv2.add(videoRecortado,fotoRecortada)
cv2.imshow('Filtros en video',videoFinal)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
Y éste es el resultado capturado desde mi despacho (si queréis verlo en vídeo, tenéis este enlace):
¡Y eso es todo por hoy!. ¡Ya tenéis tarea!. ¡El próximo día nos ponemos a detectar rostros de manera inteligente!. ¡Seguid disfrutando!. ¡Seguid creando!.