Saturday, October 20, 2018

Construcción de una cámara IP con una RPi y herramientas necesarias para el servidor en RPI3

Un módulo de cámara para una RPi es un buen substituto de una cámara IP, en mi caso lo acompañe de un par de sensores de infrarrojos para que se pueda utilizar por la noche, en mi caso utilice una RPi zero por sus dimensiones reducidas así como su precio. Pero cualquier modelo de RPi sirve para este caso incluso la primera versión es más que capaz. Las últimas versiones de la RPi Zero bienen con un controlador WiFi integrado, solo es necesario instalar un cliente para conectarlo a la WiFi, para lo cual recomiendo wicd-ncurses o alguno similar que se pueda utilizar por consola sin necesidad de entorno gráfico.

Una vez conectado es hora de generar el stream y para eso usamos la herramienta raspivid que nos permite capturar el video del módulo de la cámara y concatenamos la salida con un comando del vlc para generar el stream por rtsp.

raspivid -o - -t 0 -n -w 600 -h 400 -fps 12 | cvlc -vvv stream:///dev/stdin --sout '#rtp{sdp=rtsp://:9554/low}' :demux=h264


Podemos ajustar a nuestras necesidades el tamaño del vídeo y los fps del stream, una vez lanzado el comando ya podemos acceder al stream por rtsp como si se tratara de una cámara IP.

Ahora toca la parte del servidor que va en la RPi 3, para ello hay que compilar OpenCV con soporte para ffmpeg, será la herramienta que se emplee para leer y decodifcar el video, y con soporte para python.

Compilar software es una tarea de por si bastante costosa en términos computacionales, más aun para una RPi donde cualquier cosa medianamente compleja puede tardar muchas horas en compilar, por eso creo que tener un entorno con las herramientas necesarias y poder empezar a programar y probar cosas al instante es imprescindible para no estancarse en el desarrollo. Por eso utilicé docker en mi PC, para los que no esteis familiarizados con el término, se trata de un sistema de contenedores donde puedes tener herramientas concretas generadas a traves de una imagen base, algo así como una máquina virtual pero a velocidad nativa. 

No voy a entrar en más detalles sobre como funciona docker, solo decir que como base para la compilación de OpenCV cree un contenedor a partir de este Dockerfile. Si lo analizais por encima veis que son una serie de comandos a partir de una imagen base de ubuntu donde instala las dependencias necesarias y compila el codigo fuente de OpenCV. El mismo proceso se puede llevar a cabo cuando se quiera meter en la RPi teniendo en cuenta que la base es un Raspbian y no un ubuntu y es posible que algunos paquetes no se llamen igual, Pero esta imagen nos permite trabajar directamente con las herramientas que necesitamos y empezar a desarrollar directamente.

Simplemente comentar que para que funcione la compilacion en la RPi solo me funcionó con la version 3.3.0 de OpenCV y a mayores necesité cambiar un aspecto del código fuente. Aparentemente cuando OpenCV abre una conexión para comunicarse con el stream rtsp la abre por tcp, nuestros streams tanto el de la camara IP como el de la RPi abren una conexión udp, en teoría se puede cambiar con la siguiente línea de código en python.

os.environ["OPENCV_FFMPEG_CAPTURE_OPTIONS"] = "rtsp_transport;udp" 


Pero no parecía funcionarme así que opté por cambiarlo en la librería del códgo fuente. El siguiente comando reemplaza en el código "tcp" por "udp" y de esta forma ya se puede leer nuestros streams desde el programa.

sed "s/\btcp\b/udp/g" -i /tmp/opencv/modules/videoio/src/cap_ffmpeg_impl.hpp


Una vez compilado podemos ejecutar la siguiente línea en una consola de python para ver si hicimos correcta la compilación de OpenCV

import cv2; print(cv2.getBuildInformation())

Video I/O:
DC1394 1.x: NO
DC1394 2.x: NO
FFMPEG: YES
avcodec: YES (ver 57.24.102)
avformat: YES (ver 57.25.100)
avutil: YES (ver 55.17.103)
swscale: YES (ver 4.0.100)
avresample: NO
GStreamer: NO
OpenNI: NO
OpenNI PrimeSensor Modules: NO
OpenNI2: NO
PvAPI: NO
GigEVisionSDK: NO
Aravis SDK: NO
UniCap: NO
UniCap ucil: NO
V4L/V4L2: NO/YES
XIMEA: NO
Xine: NO
gPhoto2: NO

La parte que nos interesa es la que pone FFMPEG: YES

Aunque no es imprescindible y en gran parte dependerá del uso que se le vaya a dar, opté por que la instalación del sistema base estuviera en una partición en usb. En condiciones normales no es que genere muchos accesos de escritura / lectura (se puede comprobar con iotop) Pero si que es cierto que la parte de detección de movimiento puede generar alguna carga. Para evitar que nuestra tarjeta sd se muera podemos editar en la partición de boot el fichero cmdline.txt para que arranque la partición del usb (blkid para conocer su UUID)

Esto no va afectar al rendimiento, en teoría no importa mucho el tipo de tarjeta sd o el usb que se use, siempre va haber una limitación probocada por el bus de entrada de la RPi y nunca se va alcanzar las tasas máximas que ofrece el dispostivo.

En el siguiente post veremos en detalle como funciona el código de detección de movimiento.

No comments:

Post a Comment