Thursday, November 1, 2018

Resultados y rendimiento


Los resultados obtenidos y el funcionamiento del sistema van a depender de muchos factores, pero los dos más significativos van a ser la calidad del video y los fps del stream, esto es algo que en la camara hecha con la RPi tenemos control sobre estos parámetros y podemos modificar, en la camara IP no tenemos manera de cambiar estos parámetros. Otros factores como la cantidad de movimiento que hay en el entorno o la complejidad del lugar al que apunta la camara también va a repercutir en el rendimiento final. Suponemos que las cámaras van a estar en un entorno con poco movimiento (una casa) y no en un lugar público donde el algoritmo de detección se estaría ejecutando constatemente y ralentizaría el rendimiento.

Lo primero será analizar con que parámetros vamos a trabajar en la cámara IP, pódemos mirarlo con este comando.

ffprobe rtsp://192.168.1.104:554/onvif1

Input #0, rtsp, from 'rtsp://192.168.1.104:554/onvif1':
  Metadata:
    title           : H.264 Video, RtspServer_0.0.0.2
  Duration: N/A, start: 0.000000, bitrate: N/A
    Stream #0:0: Video: h264 (Baseline), yuv420p(progressive), 1280x720, 5 fps, 5 tbr, 90k tbn, 180k tbc
    Stream #0:1: Audio: pcm_alaw, 8000 Hz, 1 channels, s16, 64 kb/s


Podemos ver que se trata del codec H.264 y un vídeo hd de 720p y 5 fps.

Nuestra cámara hecha con la RPi podemos ajustar los parámetros con el comando raspivid que analizamos en el post  de "construcción de una cámara IP con RPi".

Ahora como podemos ver el rendimento real de nuestro programa, pues con la función FPS de la librería imutils.video. Esta librería usa un thread a parte para llevar la cuenta de frames, solo hace falta iniciar el thread con start antes del bucle y acabarlo con stop despues del bucle y cambiar el bucle infinito por un número concreto de frames (200 en todas las pruebas)

fps = FPS().start()

while fps._numFrames < 200
   ...
   fps.update()

fps.stop()
print("[INFO] elasped time: {:.2f}".format(fps.elapsed()))
print("[INFO] approx. FPS: {:.2f}".format(fps.fps()))


Se obtuvo la siguiente baterías de prueba, con los siguientes parametros en las cámaras. Los de la cámara IP son los arriba descritos y para la cámara con RPi un vídeo H.264 de 600x400, los fps tras realizar varias pruebas se dejaron en 5, con 10 o más ya empezaba a encolar frames, lo cual tampoco es un problema pero de esta forma tenemos vídeo en tiempo real.

1º Prueba, procesado de vídeo mostrandolo por pantalla y sin mostralor (imshow)

Mostrando las imágenes por pantalla

[INFO] elasped time: 34.95
[INFO] approx. FPS: 5.72

Solo procesado

[INFO] elasped time: 34.70
[INFO] approx. FPS: 5.76

Sin demasiada diferencia, la idea de esto es que en vez de mostrar las imágenes podemos guardar los frames para construir otro stream rtsp en un servidor web, lo cual nos permite tener un historico de grabaciones que poder visualizar, sería interesante tener esto en cuenta para un trabajo futuro.

2º Prueba, una cámara con detección de movimiento.

La idea es generar movimiento y ver como lo procesa y el resultado obtenido.

[INFO] elasped time: 20.04
[INFO] approx. FPS: 9.98

Un momento, parece que el rendimiento es mejor que cuando solo se procesa el vídeo, ¿como es posible? Eso es debido a que el momento en el que hay movimiento y empieza con la lógica de detección necesita de un proceso computacional a mayores y empieza a encolar frames, estos frames que están en la cola no cuentan en el computo de los fps y por eso sale mejor rendimiento, aunque no es el caso, simplemente lo que hace encolar frames es aumentar la latencia y el retardo del vídeo.

¿Os acordais de la anterior función que comentaba en el primer post que hacía el procesado en el thread principal? Bueno pues estos son lo resultados solo para procesar el vídeo, es decir sin tener movimiento que detectar.

[INFO] elasped time: 61.72
[INFO] approx. FPS: 3.24

Y estos con deteccion de movimento

[INFO] elasped time: 90.41
[INFO] approx. FPS: 2.21

Parece una buena idea usar threads distintos.

Ahora probemos con ambas cámaras funcionando simultanemanete, basta con lanzar el script en segundo plano dos veces con la direcciones del stream de cada cámara.

Ambas cámaras funcionando (sin detección de movimiento)

Cámara 1
[INFO] elasped time: 34.50
[INFO] approx. FPS: 5.80

Cámara 2
[INFO] elasped time: 33.84
[INFO] approx. FPS: 5.91

En el siguiente post veremos como crear un bot en telegram y la lógica que le tenemos que añadir a nuestro programa para que nos lleguen notificaciones al móvil cuando detecta movimiento.

Apéndice.

Flags para la compilacion de OpenCV para obtener un rendimiento óptimo en RPi.

cmake -D CMAKE_BUILD_TYPE=RELEASE     -D CMAKE_INSTALL_PREFIX=/usr/local    -D ENABLE_NEON=ON -D ENABLE_VFPV3=ON  -D OPENCV_EXTRA_MODULES_PATH=/mnt/opencv_contrib-3.3.0/modules -D BUILD_PYTHON_SUPPORT=ON -D WITH_FFMPEG=ON -D WITH_V4L=ON -D WITH_IPP=OFF  -D BUILD_TESTS=OFF -D INSTALL_PYTHON_EXAMPLES=OFF -D BUILD_EXAMPLES=OFF -D PYTHON_EXECUTABLE=/usr/bin/python ..