mayo 20, 2022 10:00 am

Jesús

En el presente artículo nos enfocaremos en una aplicación sencilla, pero muy práctica, de OpenCV.

¿Cuál?

Como habrás adivinado a partir del título, usaremos OpenCV para transmitir imágenes desde nuestra webcam al navegador de tu preferencia (Chrome, Firefox, Edge, entre otros).

Aunque en principio parezca trivial hacer esto, descubrirás en breve que hay varias “piezas movibles” y conceptos de bajo nivel a tener en cuenta para poder lograr con éxito nuestro cometido.

Al final de este artículo sabrás:

  • Cómo leer imágenes de una webcam con OpenCV.
  • Cómo crear un simple servidor web con Flask.
  • Cómo codificar imágenes en formato JPEG utilizando OpenCV.

¿Preparado? De ser así, pongámonos en acción.

Streaming de Imágenes de OpenCV a tu Navegador

OpenCV y Flask (un micro framework web de Python) forman la pareja perfecta para proyectos de streaming web y videovigilancia.

Antes de continuar, lo más sensato es que discutamos brevemente, a alto nivel, cómo funcionará nuestra solución.

A grandes rasgos, estos son los pasos que nuestro algoritmo seguirá para cada frame proveniente de la webcam:
  1. 1
    Leerá el frame actual y lo redimensionará manteniendo la relación de aspecto.
  2. 2
    Estampará el frame con el día de la semana, fecha y hora.
  3. 3
    Codificará la imagen en formato JPEG usando OpenCV.
  4. 4
    Servirá los bytes de la imagen al navegador mediante una llamada al servidor web implementado en Flask.

Facilito, ¿no?

Creación del Entorno de Desarrollo con Anaconda

Abajo puedes ver la estructura de nuestro proyecto. Como has de notar, los archivos más relevantes son:

  • datasmarts/templates/index.html: Archivo HTML súper trivial donde mostraremos el feed en vivo de nuestra webcam con estampas de tiempo superpuestas
  • datasmarts/stream.py: Implementa la lógica de streaming de imágenes al navegador, así como el servidor web en Flask

Si gustas descargar el proyecto, simplemente llena este formulario:

Para crear el entorno de desarrollo con Anaconda, primero ubícate en la raíz del proyecto, y después ejecuta la siguiente instrucción en la consola:

conda env create -f opencv-document-alignment-registration

La configuración del ambiente (opencv-html-video-stream) es esta:

Para activar el ambiente, corre este comando:

conda activate opencv-html-video-stream

¡Listo! Continuemos.

Transmisión de Imágenes con OpenCV y Flask

El primer archivo que tienes que abrir es datasmarts/templates/index.html, cuyo contenido verás a continuación:

Como puedes notar, consiste de una plantilla muy sencilla, en la cual insertaremos el live feed de la webcam mediante el URL de la función video_feed().

El siguiente paso es abrir el archivo datasmarts/stream.py, e insertar estas líneas para importar las dependencias del proyecto:

Para impedir condiciones de carrera cada vez que leemos frames de la cámara web, obtendremos un “lock” o candado que nos permitiré bloquear el acceso a la misma cuando lo necesitemos; esto lo logramos mediante la función thread.lock():

Inicializamos la aplicación de Flask, así como el lector de frames:

La primera función auxiliar que constuiremos es timestamp_feed(), la cual aplica una estampa de tiempo a cada frame proveniente de un stream (webcam):

Después de obtener referencias a las variables globales, iteramos infinitamente para obtener cada frame, redimensionarlo y estamparle la fecha actual:

Fíjate que la última instrucción del extracto anterior lo que hace es asignar la imagen estampada a la variable global output_frame, si y solo sí tenemos el lock sobre dicho recurso:

La próxima función auxiliar (generate()) se encarga de generar imágenes codificadas en formato JPEG

Si y solo si tenemos el lock sobre output_frame, usamos la función cv2.imencode() para codificar su contenido en formato JPEG:

Finalmente, generamos el contenido de la imagen como un arreglo de bytes:

Creamos el controlador index(), correspondiente a la ruta /, el cual simplemente renderiza el template ubicado en datasmarts/templates/index.html:

El siguiente controlador, video_feed(), correspondiente a la ruta /video_feed, genera una respuesta por cada llamada al generador generate(), asociando el MIME Type apropiado:

Para culminar, corremos la función timestamp_feed() en su propio hilo, y desplegamos el servidor Flask en la ruta https://127.0.0.0.1:4747

¡ATENTO!

Antes de ejecutar el código, asegúrate de hallarte en la raíz del proyecto para que los comandos funcionen correctamente.

Para correr el programa, simplemente ejecuta:

python datasmarts/stream.py

En el resultado se verá así:

Genial, ¿no?

El lado bueno es que, a pesar de que lo que hicimos es trivial, puedes sustituir el estampado de tiempo con cualquier otra operación (por ejemplo, detección facial, procesamiento de imágenes, clasificación, etcétera) ya que las demás piezas permanecen constantes.

Resumen

Hoy aprendimos a extraer imágenes de nuestra webcam, transformarla, y luego mostrar el resultado en el navegador.

Concretamente, nuestra transformación consiste meramente de añadir una estampa de tiempo a la imagen.

No obstante, usando este framework podemos crear programas mucho más interesantes que ejecuten tareas más serias, como detección de objetos, clasificación, detección de movimiento, entre un sinfín de opciones.

Lo importante es saber que para poder darle vida a este tipo de aplicaciones requerimos estos elementos:

  • Una plantilla HTML donde colocar los frames procesados.
  • Un generador que codifique los frames en un formato que el navegador entienda, típicamente JPEG.
  • Un servidor web para recibir y responder las peticiones hechas por el navegador. Aunque en este apartado contamos con excelentes alternativas, la que menos mala vida nos dará es Flask.

¡Hasta pronto!

Sobre el Autor

Jesús Martínez es el creador de DataSmarts, un lugar para los apasionados por computer vision y machine learning. Cuando no se encuentra bloggeando, jugando con algún algoritmo o trabajando en un proyecto (muy) cool, disfruta escuchar a The Beatles, leer o viajar por carretera.