scieee AI-readable full text Open interactive document viewer

Control y procesamiento de vídeo en cámaras IP desde una plataforma Android

Molina Alarcón, David

Abstract

La aplicación Control Camera IP, desarrolla como Proyecto Fin de Carrera en la ETS. De Ingeniería Informática de la Universidad de Málaga, fue concebida como una interfaz de usuario para la monitorización y control de cámaras IP de forma remota, pudiendo ésta ejecutarse en diferentes plataformas, incluyendo dispositivos móviles con sistemas Android. En aquel momento sin embargo, las plataformas Android no disponían de una librería oficial dentro del marco de la herramienta de desarrollo utilizada (la biblioteca de desarrollo multiplataforma Qt), por lo que fue utilizada una versión alternativa no oficial denominada Necessitas Qt for Android. Hoy, con la versión 5 de Qt, existe la posibilidad de dar soporte a las plataformas Android de forma oficial, por lo que es posible adaptar la aplicación a esta nueva versión. En este Trabajo Fin de Grado, se ha adaptado la aplicación Control Camera IP a la versión 5 de Qt, logrando así crear plataformas para dispositivos Android de forma oficial. Además, se hace uso de la biblioteca OpenCV para el desarrollo de varios métodos de procesamiento sobre la imagen recibida por la cámara IP, así como algoritmos de detección de movimiento y de caras de personas, haciendo uso de técnicas de visión por computador. Finalmente, se introduce la posibilidad de utilizar APIs estandarizadas para la conectividad de la aplicación con cámaras IP de bajo coste, adaptando algunas de sus funciones a la aplicación Control Camera IP.

Full text

ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA GRADO EN INGENIERÍA DE COMPUTADORES CONTROL Y PROCESAMIENTO DE VIDEO EN CÁMARAS IP DESDE UNA PLATAFORMA ANDROID CONTROL AND VIDEO PROCESSING OVER IP CAMERAS RUNNING ON AN ANDROID PLATFORM Realizado por David Molina Alarcón Tutorizado por D. José María González Linares Departamento Arquitectura de Computadores UNIVERSIDAD DE MÁLAGA MÁLAGA, Diciembre de 2015 Fecha defensa: El Secretario del Tribunal ~ 3 ~ ~ 4 ~ Resumen: La aplicación Control Camera IP, desarrolla como Proyecto Fin de Carrera en la ETS. De Ingeniería Informática de la Universidad de Málaga, fue concebida como una interfaz de usuario para la monitorización y control de cámaras IP de forma remota, pudiendo ésta ejecutarse en diferentes plataformas, incluyendo dispositivos móviles con sistemas Android. En aquel momento sin embargo, las plataformas Android no disponían de una librería oficial dentro del marco de la herramienta de desarrollo utilizada (la biblioteca de desarrollo multiplataforma Qt), por lo que fue utilizada una versión alternativa no oficial denominada Necessitas Qt for Android. Hoy, con la versión 5 de Qt, existe la posibilidad de dar soporte a las plataformas Android de forma oficial, por lo que es posible adaptar la aplicación a esta nueva versión. En este Trabajo Fin de Grado, se ha adaptado la aplicación Control Camera IP a la versión 5 de Qt, logrando así crear plataformas para dispositivos Android de forma oficial. Además, se hace uso de la biblioteca OpenCV para el desarrollo de varios métodos de procesamiento sobre la imagen recibida por la cámara IP, así como algoritmos de detección de movimiento y de caras de personas, haciendo uso de técnicas de visión por computador. Finalmente, se introduce la posibilidad de utilizar APIs estandarizadas para la conectividad de la aplicación con cámaras IP de bajo coste, adaptando algunas de sus funciones a la aplicación Control Camera IP. Palabras Clave: cámara, IP, plataforma, conexión, red, API, control, monitorización, procesamiento, imagen, técnicas, visión, artificial, algoritmos, detección, tratamiento. Abstract: The IP Camera Control application, developed as Degree project in the ETS. De Ingeniería Informática at the University of Malaga, it was conceived as a user interface for monitoring and control IP cameras remotely, so it can run on different platforms, including mobile devices with Android operative systems. At that time however, the Android platform did not have an official library within the framework of the development tool used (the cross-platform Qt development library), which was used an unofficial alternative version called Necessitas Qt for Android. Today, with Qt on its 5th version, there is support for the Android platform officially, making it possible to adapt the application to the new version. ~ 5 ~ In this Final Project, the IP Camera Control application has been adapted to the 5th version of Qt, having succeeded indeed the creation of platforms for Android devices officially. In addition, OpenCV library has been used to develop various methods of processing on the image received by the IP camera, as well as motion and face detection algorithms by using computer vision techniques. Finally, the possibility of using standardized APIs for the application connectivity with low cost IP cameras, adapting some of its functions to the IP Camera Control application, has been introduced. Keywords: camera, IP, platform, connection, network, API, control, monitoring, processing, image, techniques, vision, artificial, algorithms, detection, treatment. ~ 6 ~ Contenido Capítulo 1 .................................................................................................................................... 13 1.1 Objetivos del Trabajo ....................................................................................................... 14 1.2 Ejemplos de uso de las cámaras IP ................................................................................... 15 1.3 Cámaras IP en la actualidad ............................................................................................. 16 1.4 Introducción a la biblioteca OpenCV ................................................................................ 17 1.4.1 Módulo Core ............................................................................................................... 18 1.4.2 Módulo ImgProc ......................................................................................................... 18 1.4.3 Módulo HighGui ......................................................................................................... 19 1.4.4 Módulo Features2D .................................................................................................... 19 1.4.6 Módulo ObjDetect ...................................................................................................... 20 1.5 Contenido de la memoria .................................................................................................. 20 Capítulo 2 .................................................................................................................................... 21 2.1 La aplicación original ......................................................................................................... 21 2.1.1 Descripción general de la aplicación .......................................................................... 22 2.1.2 Funciones más importantes ....................................................................................... 23 2.1.3 Creación de Múltiples Plataformas ............................................................................ 29 2.2 Adaptación de la aplicación a Qt 5 .................................................................................... 30 2.2.1 QWidgets como módulo separado ............................................................................ 30 2.2.2 Cambios en las funciones de red ................................................................................ 31 2.2.2.2 Las nuevas clases del módulo Network ............................................................... 32 2.2.2.1 Eliminación de la clase auxiliar HttpManager ..................................................... 33 2.2.2.3 La nueva estructura del módulo de control ........................................................ 33 2.2.3 Eliminación de la clase auxiliar Temporizador ........................................................... 35 2.3 Creación de Plataformas Android en Qt 5 ......................................................................... 37 Capítulo 3 .................................................................................................................................... 39 3.1 VAPIX, el API de AXIS ......................................................................................................... 40 3.2 El API estandarizado IPCAM CGI ........................................................................................ 41 3.2.1 Funciones de estado y de obtención de parámetros de la cámara ........................... 43 3.2.2 La función camera_control.cgi ................................................................................... 43 3.2.3 Funciones de permisos de usuario y configuración de red ........................................ 44 3.2.4 Las funciones snapshot.cgi y videostream.cgi ........................................................... 45 3.2.5 La función decoder_control.cgi .................................................................................. 46 ~ 7 ~ 3.3 Adaptación de la aplicación Control Cámara IP al nuevo API ........................................... 47 3.3.1 La cámara de bajo coste modelo Conceptronic Pan & Tilt Wireless .......................... 48 3.3.2 Modificaciones en el código de la aplicación ............................................................. 50 3.3.2.1 Modificaciones para la recepción de imágenes .................................................. 50 3.3.2.2 Modificaciones de los controles de la cámara .................................................... 51 3.3.3 Capturas de las pruebas realizadas ............................................................................ 52 Capítulo 4 .................................................................................................................................... 55 4.1 La biblioteca de visión artificial OpenCV ........................................................................... 55 4.1.1 Funciones del módulo Core ........................................................................................ 56 4.1.1.1 Trabajando con imágenes IplImage .................................................................... 58 4.1.1.2 Trabajando con la clase Mat ............................................................................... 59 4.1.2 Funciones del módulo ImgProc .................................................................................. 61 4.1.2.1 Función blur() ...................................................................................................... 62 4.1.2.2 Función Canny() ................................................................................................... 63 4.1.2.3 Ecualización de histogramas ............................................................................... 63 4.1.3 Funciones del módulo ObjDetect ............................................................................... 65 4.1.3.1 Clasificador en cascada basado en características tipo Haar .............................. 65 4.1.3.2 Cargando un clasificador con la función load() ................................................... 67 4.1.3.3 La función detectMultiScale ................................................................................ 67 4.2 Integración de las librerías de OpenCV en Qt5 ................................................................. 68 4.2.1 Integrando las librerías de OpenCV para la plataforma Microsoft Windows 7.......... 68 4.2.2 Integrando las librerías de OpenCV para la plataforma Linux Ubuntu 14.04 ............ 69 4.2.2 Integrando las librerías de OpenCV para la plataforma Android ............................... 71 4.3 Desarrollo de los métodos de procesamiento de video ................................................... 73 4.3.1 La nueva clase auxiliar FuncionesOpenCV ................................................................. 75 4.3.1.1 Conversión de QPixmap a Mat ............................................................................ 76 4.3.1.2 Conversión de Mat a QPixmap ............................................................................ 77 4.3.2 Implementación del método de detección de bordes ............................................... 78 4.3.2.1 Descripción del método ...................................................................................... 80 Aplicación de filtro Gaussiano ..................................................................................... 81 Obtención del gradiente de intensidad de la imagen ................................................. 81 4.3.2.2 Diálogo BorderDetectionDialog ........................................................................... 83 4.3.3 Implementación de las funciones de brillo y contraste ............................................. 87 4.3.3.1 Descripción del método ...................................................................................... 88 ~ 8 ~ 4.3.3.2 Diálogo BrightContrastDialog ............................................................................. 88 4.3.4 Implementación del algoritmo de sustracción de fondo ........................................... 89 4.3.4.1 Descripción del método ...................................................................................... 91 4.3.4.2 Diálogo BackgroundSubDialog ............................................................................ 92 4.3.5 Implementación del algoritmo de detección de BLOBs de color ............................... 94 4.3.5.1 Descripción del método ...................................................................................... 96 4.3.5.2 Diálogo BlobColorDialog...................................................................................... 98 4.3.6 Implementación del método de detección de caras .................................................. 99 4.3.6.1 Descripción del método .................................................................................... 100 Capítulo 5 .................................................................................................................................. 103 5.1 Mejoras en la detección de objetos en la imagen .......................................................... 104 5.1.1 Detección de esquinas ............................................................................................. 104 5.1.2 Blobs de circularidad ................................................................................................ 105 5.2 Mejoras en la detección de caras .................................................................................... 106 5.3 Integrar la aplicación en una solución para el análisis de información visual con cámaras instaladas en Drones ............................................................................................................. 106 5.1.2 Técnicas de visión artificial para la navegación y análisis de información con drones ........................................................................................................................................... 107 5.4 Adaptación completa de la aplicación para su funcionamiento con APIs estandarizados ............................................................................................................................................... 109 Bibliografía ................................................................................................................................ 111 ~ 9 ~ Figuras Figura 1. La nueva generación de Cámaras IP: Smart IPC ........................................................... 16 Figura 2. Logo de OpenCV ........................................................................................................... 18 Figura 3. Ejecución de la aplicación Control Camera IP en el entorno Microsoft Windows 7 .... 22 Figura 4. Creación del túnel de comunicación con la cámara con PuTTY ................................... 23 Figura 5. Estructura general de las clases del paquete ‘controlCamara’ .................................... 25 Figura 6. Grupo de acciones del menú Controles ....................................................................... 27 Figura 7. Edición de máscaras con la aplicación Control Camera IP ........................................... 28 Figura 8. Máscara activa en la aplicación (izquierda) y máscara PBM (derecha) ....................... 28 Figura 9. Vista de la interfaz gráfica para el Tablet PC ViewPad-S10 con Android-ViewComb ... 30 Figura 10. Nueva estructura del módulo de control de la aplicación Control Camera IP ........... 34 Figura 11. Lectura de controles mediante el proceso de “transición de carga” ......................... 36 Figura 12. Configuración para los dispositivos Android en la versión 5 del entorno Qt Creator 37 Figura 13. Configuración de plataforma Android en la versión 5 del entorno Qt Creator ......... 38 Figura 14. Algunos modelos de Cámaras IP de Foscam .............................................................. 42 Figura 15. Cámara Conceptronic Pan & Tilt Wireless .................................................................. 48 Figura 16. Modo Navegador de la cámara Conceptronic PTIW .................................................. 49 Figura 17. Captura de cámara Conceptronic tras aplicar el comando 6 (Pan) onestep a la derecha ........................................................................................................................................ 52 Figura 18. Captura de cámara Conceptronic aplicando el algoritmo de Canny .......................... 53 Figura 19. Captura de cámara Conceptronic aplicando el algoritmo de sustracción de fondo .. 53 Figura 20. Captura de cámara Conceptronic aplicando el método de detección de caras ........ 54 Figura 21. Visualización de las componentes RGB haciendo zoom sobre una imagen .............. 57 Figura 22. Imagen HSV y sus distintos componentes de color ................................................... 60 Figura 23. Función blur sobre una imagen usando diferentes tamaños de kernel ..................... 62 Figura 24. Ejemplo de imagen tras aplicar la ecualización de histograma. ................................ 64 Figura 25. Ejemplo de cálculo de características tipo Haar para la detección de caras ............. 66 Figura 26. Diseño del nuevo menú Procesamiento de Video con sus distintas acciones ........... 74 Figura 27. Nueva estructura del proyecto Qt .............................................................................. 74 Figura 28. Nueva Clase FuncionesOpenCV del paquete auxiliares ............................................. 75 Figura 29. Dialogo de control para la detección de bordes en la imagen ................................... 79 ~ 10 ~ Figura 30. Coeficientes de un kernel Gaussiano de tamaño 5 .................................................... 81 Figura 31. Rastreo de bordes y salida final ................................................................................. 83 Figura 32. Detección de bordes con un tamaño de Kernel igual a 5 ........................................... 84 Figura 33. Detección de bordes con un tamaño de Kernel igual a 3 ........................................... 85 Figura 34. Detección de bordes con ratio 1:2 y umbral bajo a 96 .............................................. 86 Figura 35. Detección de bordes con ratio 1:3 y umbral bajo a 19 .............................................. 86 Figura 36. Dialogo de control para las funciones de brillo y contraste ....................................... 87 Figura 37. Operaciones de Brillo y Contraste sobre la imagen con diferentes niveles de corrección .................................................................................................................................... 89 Figura 38. Esquema que refleja la idea del método de sustracción de fondo ............................ 90 Figura 39. Dialogo de control para el algoritmo de sustracción de fondo .................................. 90 Figura 40. Algoritmo de sustracción de fondo con valor de umbral 27 y sensibilidad 7 ............ 93 Figura 41. Algoritmo de sustracción de fondo con valor de umbral 7 y sensibilidad 67 ............ 93 Figura 42. Degradación del color AquaMarine (RGB[127,255,212]) ........................................... 95 Figura 43. Rueda de color de la componente de matiz Hue ....................................................... 96 Figura 44. Captura del algoritmo de BLOBs de color seleccionando la opción de tonos rojos ... 98 Figura 45. Captura del algoritmo de BLOBs de color seleccionando la opción de tonos azules . 99 Figura 46. Activando y desactivando el método de detección de caras ................................... 100 Figura 47. Detección de caras en la aplicación Control Camera IP ........................................... 102 Figura 48. Aplicación de un algoritmo de detección de bordes sobre una imagen .................. 105 Figura 49. Dron con varios sensores entre los que se incluyen varias cámaras ....................... 106 Figura 50. Matching entre dos frames consecutivos para establecer la localización ............... 108 Figura 51. Proyección de un punto en el espacio 3D ................................................................ 109 ~ 11 ~ lenguaje C, C++ y Python optimizados que aprovechan las capacidades de los procesadores multinúcleo modernos. Figura 2. Logo de OpenCV La amplia variedad de funciones de su API (Application Programming Interface) están organizadas por distintos módulos dedicados cada uno de ellos a propósitos bien diferenciados. A continuación, describimos algunos de los módulos más utilizados (y que serán usados en nuestra aplicación), así como algunos de sus métodos y funciones más importantes de cada uno de ellos: 1.4.1 Módulo Core Como su propio nombre indica, está compuesto por aquellas funciones que definen el núcleo de la funcionalidad de OpenCV. Se tratan de funciones y estructuras de datos básicas que son utilizadas por el resto de módulos y que facilitan en gran medida cuestiones como la manipulación de imágenes, definición de elementos 2D sobre la imagen, creación de matrices (Mat), creación de estructuras dinámicas como grafos, árboles, clusterización, operaciones de persistencia, etc. En este trabajo utilizaremos las estructuras más comunes para el procesado de imágenes tales como las estructuras Mat e IplImage que permiten almacenar fácilmente las imágenes en forma de matrices, donde cada elemento almacena un canal de color (escala de grises) o varios colores (RGB, RGBA, etc.). Además utilizaremos los métodos y funciones para trabajar con estas estructuras tales como la función create(), size(), convertTo(), copyTo(), depth(), release(), etc. 1.4.2 Módulo ImgProc El módulo ImgProc (de Image Processing) contiene todas las funciones de OpenCV que permiten la manipulación y transformación de imágenes de cualquier tipo, ~ 18 ~ incluyendo además algoritmos de detección de características sobre la imagen, así como algoritmos para análisis estructurales, descripción de contornos y detección de objetos. Utilizaremos el módulo ImgProc a un nivel muy básico sobre todo para tareas de conversión de imágenes. Tal y como comentamos anteriormente, las imágenes de varios canales de color que podamos obtener de cualquier fuente vendrán dadas normalmente en la configuración RGB. Hay que tener en cuenta sin embargo que OpenCV trabaja usualmente con los canales de color invertidos. Es decir, en lugar de la típica secuencia RGB (Red Green Blue), los canales de color de las imágenes en OpenCV suelen tener la configuración BGR (Blue Green Red). Es por esta razón que uno de los métodos más utilizados del módulo ImgProc suele ser el método de conversión de color cvtColor(), el cual usaremos frecuentemente para hacer algunas conversiones sobre la imagen en este trabajo. 1.4.3 Módulo HighGui Independientemente de que OpenCV esté diseñado para el uso en aplicaciones que estén creadas bajo frameworks con gran riqueza de funcionalidades para la creación de interfaces de usuario (tal y como lo es Qt), o incluso para aplicaciones sin interfaz de usuario, en ocasiones es necesario disponer de herramientas que permitan realizar pruebas rápidas para visualizar resultados sin tener que recurrir a componentes con los que está diseñada la propia aplicación. Es para ello para lo que se ha diseñado el módulo HighGui. Funciones como namedWindow() y imshow(), ofrecen la posibilidad de mostrar los resultados de las operaciones realizadas sobre imágenes en una ventana de forma independiente. Además, este módulo dispone también de funciones para la lectura y escritura de imagen (imread, imwrite) y de video (VideoCapture). 1.4.4 Módulo Features2D Es un módulo también muy utilizado sobre todo en el ámbito de la visión por computador. Dispone de funciones y algoritmos de gran eficiencia que permiten realizar una descripción y detección de una serie de características sobre la imagen. Entre los algoritmos más conocidos de descripción de características destacan el BRIEF (Binary Robust Independent Elementary Features), el FAST, un detector de esquinas de gran efectividad, y el FREAK (Fast REtinA Keypoint), que se inspira en el sistema de ~ 19 ~ visión humano. Los detectores y extractores de características más conocidos son el SIFT y el SURF, y son verdaderamente efectivos. El problema es que estos algoritmos pertenecen al módulo NonFree de OpenCV [9], que contiene algoritmos que pueden estar patentados y que por ello su uso está limitado. Sin embargo, existe una alternativa gratuita con el nombre ORB (Oriented-FAST and Rotated BRIEF) que está basada en los dos anteriores, y que también es bastante eficiente. Este algoritmo también se encuentra en el módulo Features2D. 1.4.6 Módulo ObjDetect Por último, el módulo ObjDetect nos permite definir clasificadores en cascada (Cascade Classifiers), los cuales pueden ser entrenados con muestras de objetos concretos de una escala y tamaño determinados, para ser aplicado a una región de interés dentro de una imagen de entrada y de esta forma poder detectar si esta zona de interés es parecida a dichos objetos similares con los que se ha entrenado el clasificador. Más adelante explicaremos la funcionalidad para detección de caras que se ha implementado en este Trabajo Fin de Grado utilizando funciones del módulo ObjDetect. 1.5 Contenido de la memoria En el capítulo 2, “Control y Procesamiento de Video en Cámaras IP desde una plataforma Android”, mostraremos las modificaciones que se han realizado en la aplicación Control Cámara IP desarrollada en el PFC original, con el propósito de crear una nueva plataforma para dispositivos Android haciendo uso de las librerías oficiales que vienen incorporadas en la última versión de Qt. En el capítulo 3, “Funcionamiento de la Aplicación en Cámaras IP de Bajo Coste”, se realizará un estudio acerca de la posibilidad de integración de la aplicación con cámaras IP de bajo coste. En el capítulo 4, “Integración de Procesamiento de Vídeo con la Librería OpenCV”, realizaremos una descripción de los nuevos métodos y funciones de procesamiento de vídeo añadidos a la aplicación Control Cámara IP, mostrando capturas y ejemplos de las pruebas realizadas. En el capítulo 5, “Conclusiones y Trabajos Futuros” se mencionan de forma breve las conclusiones y trabajos que en un futuro se pueden desarrollar para la ampliación de este proyecto. ~ 20 ~ Capítulo 2 Control y Procesamiento de Video en Cámaras IP desde una plataforma Android En este capítulo trataremos de recordar de forma resumida los aspectos más importantes en la realización de la aplicación Control Cámara IP englobada dentro del PFC de nombre Interfaz Gráfica Multiplataforma para control de Cámaras IP, la cual ha sido modificada para incorporar las mejoras y ampliaciones realizadas en el presente Trabajo Fin de Grado. Uno de estos cambios ha consistido en adaptar la aplicación a la última versión de la biblioteca de desarrollo Qt, la cual incorpora ya de manera oficial, la posibilidad de crear plataformas Android dentro del entorno QtCreator. En la última sección de este capítulo explicaremos como hemos llevado a cabo esta adaptación. 2.1 La aplicación original La idea de la aplicación Control Cámara IP surgió de la dificultad presente en aquel momento de encontrar soluciones software de videovigilancia por red, que fueran capaces de funcionar en las diversas plataformas con las que nos encontramos hoy día (smartphones, tablets, desktop, etc.). En definitiva, se trataba de crear una aplicación de control y monitorización de videovigilancia en red fácilmente distribuible que fuera capaz de ejecutarse tanto en entornos de escritorio como en dispositivos móviles, y que además este cambio de entorno no afectara a su funcionalidad. Desde el principio se pensó en la biblioteca de desarrollo Qt para la elaboración del proyecto, ya que dispone de una alta capacidad multiplataforma y además se compone de una framework en C++ orientada al desarrollo de interfaces gráficas, que dispone a su vez de una serie de módulos con funciones que ofrecen un alto rendimiento y flexibilidad. Sin embargo, en aquel momento, la versión de Qt (que por aquel entonces pertenecía a la compañía Nokia [10]) no ofrecía soporte para las plataformas Android, lo cual era fundamental para los requerimientos iniciales que nos habíamos marcado para el proyecto. Es por esto que hubo que hacer uso de una herramienta no oficial creada por un grupo de desarrolladores de Qt, que ofrecía la posibilidad de compilar las ~ 21 ~ aplicaciones desarrolladas con la biblioteca Qt de forma que éstas pudieran ser ejecutadas en dispositivos Android. A este proyecto se le llamó Necessitas Project, y a día de hoy todavía sigue estando presente en la web, ofreciendo soporte a través de la propia página oficial de Qt [11]. 2.1.1 Descripción general de la aplicación La aplicación Control Camera IP muestra en su ejecución una interfaz gráfica de usuario sencilla, caracterizada por disponer de una zona principal de monitorización y control sobre las imágenes recibidas a través de la conexión con una cámara de red (cámara IP). También dispone de una barra de menús desde la que se pueden comandar diferentes aspectos de conexión y control, edición de máscaras, carga de controles preestablecidos, etc. Figura 3. Ejecución de la aplicación Control Camera IP en el entorno Microsoft Windows 7 Para el proceso de conexión con la cámara utilizada en la realización del PFC (Axis Domo modelo 232D+) se creó una pasarela de comunicación haciendo uso de un túnel SSH para encapsular las peticiones HTTP realizadas por la aplicación a la cámara, estableciéndose por tanto una comunicación cifrada que garantizara la seguridad y evitara el acceso de terceras personas. ~ 22 ~ Este túnel permitía redirigir la información hacia el destino especificado. En nuestro caso, utilizábamos el cliente PuTTY para conectar con la dirección del host del Departamento de Arquitectura de Computadores de la E.T.S. de Ingeniería Informática de la Universidad de Málaga (ssh.ac.uma.es). Una vez establecida la comunicación la información se redirigía a través de la técnica port_forwarding a la dirección privada y el puerto de conexión configurados para la cámara. Finalmente, el túnel quedaba establecido redirigiendo la información enviada por la cámara a la dirección local de nuestro dispositivo (localhost) en el puerto 8080. Figura 4. Creación del túnel de comunicación con la cámara con PuTTY Una vez establecida la conexión directa con la cámara, la aplicación Control Camera IP dispone de una opción de inicio de sesión en el menú Archivo que muestra un diálogo de login o autenticación. A través de este diálogo la aplicación aplicará un segundo nivel de seguridad sobre el usuario que intenta identificarse, en el que se determinará si figura en el registro de usuarios de la cámara, así como el nivel de privilegios en función del grupo al que pertenezca. Una vez aceptado el diálogo, la aplicación se inicia mostrando las imágenes enviadas por la cámara en tiempo real, y permitiendo al usuario interactuar con los distintos controles disponibles. 2.1.2 Funciones más importantes En este apartado explicaremos algunas de las funciones principales de la aplicación original incluyendo algunos detalles de implementación. Esto nos permitirá entender ~ 23 ~ algunas de las claves más destacadas sobre las modificaciones que se han realizado para adaptar la aplicación al ámbito del presente Trabajo Fin de Grado. El Módulo de Control Uno de los pilares fundamentales para el funcionamiento de la aplicación está constituido por el módulo de control (controlCamara), que es el encargado de realizar todas aquellas peticiones a la cámara a través de comandos CGI (Common Gateway Interface) que devuelven la diferente información aportada por la cámara bajo la forma de objetos MIME (Multiporpose Internet Mail Extensions), haciendo uso del protocolo HTTP para ello. Esto quiere decir que cada vez que la aplicación necesita hacer una petición de una imagen o de un control de la cámara determinado (pan, tilt, focus, etc.), ésta se realizara a través de la creación de una nueva sesión HTTP que recibirá como parámetro una URL, que está formada por el comando CGI que ejecuta el programa en la cámara para la obtención del recurso solicitado. La petición podrá ser lanzada a través de uno de los dos métodos de HTTP más utilizados, GET y POST. A diferencia del método GET, las peticiones POST permiten enviar junto con la URL información que posteriormente será procesada en el servidor HTTP. En una petición GET, esta información solo puede enviarse encapsulada dentro de la propia URL. En la aplicación original todas las peticiones se realizan con el método GET, ya que es en la propia URL donde se incluyen los parámetros necesarios para hacer las modificaciones oportunas, y para que la cámara nos responda con los nuevos recursos modificados. La aplicación se compone principalmente de tres tipos de peticiones: petición de imagen, petición de lectura de controles y petición de escritura de controles. A continuación podemos ver un esquema de cómo estaba organizado el módulo de control dentro de la aplicación Control Camera IP original: ~ 24 ~ Figura 5. Estructura general de las clases del paquete ‘controlCamara’ La parte referente a la conexión inicial con la cámara se lleva a cabo a través de la combinación de dos peticiones. Por un lado una petición de los controles actuales de la cámara para poder almacenarlos en memoria, y una petición de la imagen actual que, tras su carga, dará luz verde para que se empiece a ejecutar el temporizador (timer) que controla la carga de las imágenes en la aplicación. Temporización Como acabamos de comentar, en la aplicación original la carga de las imágenes está comandada por un temporizador (esto ya no sucede así, tal y como explicaremos en la próxima sección). El funcionamiento es sencillo: cada vez que finaliza el Timer de refresco se realiza una petición de carga de imagen. A continuación, el temporizador se para y el programa espera a que se reciba la señal done() comandada por la instancia de la clase HttpManager, tal y como se aprecia en la imagen anterior. Una vez recibida la señal, esto quiere decir que hemos obtenido respuesta de la cámara y que la información está almacenada en memoria. Acto seguido, la imagen es cargada en el monitor de la interfaz principal, y es en ese momento cuando se vuelve a lanzar el Timer de carga de la nueva imagen. En el caso de las peticiones de lectura y escritura de controles, el proceso se realiza de forma similar, habiéndose implementado diferentes temporizadores para cada tipo de petición. ~ 25 ~ La razón de la utilización de temporizadores para el manejo de las peticiones dentro de la aplicación fue debida a la falta de mecanismos de control de la clase de QHttp (disponible en la versión 4.8 de la biblioteca Qt pero no en la versión 5) para manejar las sucesivas peticiones asíncronas que pueden darse en una sesión HTTP, de forma que en muchos casos la aplicación no era capaz de recibir correctamente la información ya que ésta se solapaba con la información recibida de otras peticiones que se ejecutaban en un momento anterior o posterior, pudiendo por tanto llegar a producir errores de red y en algunos casos la salida del programa. Añadiendo por tanto el mecanismo de temporización comentado anteriormente se solucionaron estos problemas. En la nueva versión 5 de Qt, la clase QHttp utilizada en la aplicación original ha quedado obsoleta y, por tanto, se hace necesario sustituirla por otras funciones del módulo de red que se han mantenido en la versión 5, y que han resultado ser incluso más eficientes en relación a los inconvenientes que hemos comentado. Es por ello que, al no seguir existiendo la clase QHttp en la nueva versión de Qt, el módulo de control de la aplicación se ha modificado casi por completo incluyendo un nuevo mecanismo de peticiones HTTP para obtener los recursos de la cámara. Aunque por un lado nos hemos visto en la obligación de tener que modificar gran parte del código de la aplicación, las nuevas funciones de red de Qt utilizadas en esta nueva versión del proyecto nos permiten prescindir de las temporizaciones, ya que ahora las respuestas a las peticiones HTTP sí son controladas por las propias clases de Qt, por lo que se simplifica el control sobre la recepción de información de la cámara por parte de la aplicación. Este proceso de adaptación de la aplicación original a la nueva versión de Qt será explicado con más detalle en la próxima sección. Lectura y Escritura de Controles Tal y como ya hemos visto, a parte de la carga de las imágenes de la cámara en el monitor, la aplicación original consta de funcionalidad básica para el manejo de los controles principales de la cámara de red. Concretamente, los controles con los que podemos interactuar son el pan (movimiento horizontal de 360º), el tilt (movimiento vertical de 90º), el zoom, el focus (enfoque de la cámara) y el iris (exposición lumínica). Además, también podremos modificar la resolución de la imagen atendiendo a tres tipos de resolución: QCIF (baja), CIF (media) y 4CIF (alta). ~ 26 ~ Cada vez que iniciamos la aplicación obtenemos de la cámara los valores de sus controles actuales y los guardamos en un fichero de texto llamado Inicial.txt. De esta forma si en el transcurso del tiempo en el que estamos usando la aplicación hemos modificado los controles de posición, zoom o enfoque de la cámara y queremos volver a los controles iniciales, simplemente leeremos los controles de ese fichero inicial. Figura 6. Grupo de acciones del menú Controles Para la lectura de controles en la aplicación se creó un mecanismo que ejecutaba un proceso de carga escalonada a través de temporizadores que permitía solventar los problemas relativos a los solapamientos de las diferentes sesiones HTTP creadas con la clase QHttp de la versión 4.8 de Qt. Debido a los cambios realizados para adaptar la aplicación a la versión 5, este mecanismo ya no será necesario. De forma similar, la parte relativa al proceso de escritura de controles en un fichero plano se verá modificada para ser adaptada a la nueva versión de Qt. Edición de Máscaras Otra funcionalidad que se desarrolló como uno de los objetivos para el PFC fue la posibilidad de crear y editar máscaras que pudieran superponerse sobre la imagen, utilizando para ello las funciones de dibujo en 2D que incorpora la biblioteca Qt. El módulo de edición y gestión de máscaras se compone por un lado de opciones de edición que nos permiten dibujar líneas y polígonos sobre el monitor de la aplicación (acciones del menú Dibujo), y por otro, de varias opciones de creación, almacenamiento y carga de máscaras a partir de un fichero de texto (acciones del menú Archivo). ~ 27 ~ Figura 10. Nueva estructura del módulo de control de la aplicación Control Camera IP Tal y como podemos apreciar en el esquema anterior, cada una de las clases del módulo de control se encargan ahora de gestionar sus propias peticiones haciendo uso de las funcionalidades de QNetworkAccessManager. Las señales de error y finalización se tratan directamente dentro de las mismas, permitiendo de esta manera obtener la respuesta en el mismo ámbito de la petición y poder así generar un arrayBuffer con la información que será enviada directamente a la interfaz principal MainWindow a través de las señales correspondientes para que pueda ser tratada por la aplicación. Este mecanismo no solo nos ofrece un nivel de simplificación bastante elevado con respecto al anterior esquema, sino que también permite manejar de forma mucho más eficiente los tiempos de respuesta entre peticiones. Internamente, cada una de las clases de petición de recursos a la cámara implementarán una petición GET o POST en función de las necesidades. Tal y como ya hemos comentado, este tipo de comunicaciones son de naturaleza asíncrona, por lo que la señal readyRead() de QIODevice se lanzará cada vez que existan datos disponibles en la respuesta, pero esto no querrá decir que toda la información haya sido recibida en su totalidad. A diferencia del mecanismo utilizado a través de la clase QHttp, las peticiones en este caso no necesitarán habilitar o deshabilitar el modo ReadReady para la lectura escalonada de los controles por ejemplo, o para la escritura de los mismos en un fichero de texto. Este mecanismo es cubierto como ya hemos comentado por la señal ~ 34 ~ finished(QNetworkReply*) de QNetworkAccessManager, que permite devolver la respuesta integra en el momento en que se lanza la señal de finalización de la petición. Para construir una petición GET o POST en esta nueva estructura se incluirá como argumento de entrada a la misma un objeto de tipo QNetworkRequest. Esta clase permite crear una petición HTTP desde cero a partir de los diferentes elementos que la integran (URL, atributos, cabeceras, contenido, etc.). En principio, para nuestro caso, solo es necesaria la URL puesto que el programa CGI de la cámara se encarga de montar las cabeceras y el contenido de la respuesta sin necesidad de tener que enviarle más información. Sin embargo, aunque todas las peticiones se puedan hacer con GET pasando los argumentos en la URL, gracias a la clase QNetworkRequest es posible realizar peticiones POST a la cámara encapsulando los argumentos dentro del cuerpo (body) de la petición con QUrlQuery. De esta forma, se pueden separar las peticiones que requieran el envío de parámetros a la cámara (como por ejemplo las peticiones de modificación de algún control), por peticiones POST, dejando aquellas que solo requieren recibir los recursos de la cámara como peticiones GET. 2.2.3 Eliminación de la clase auxiliar Temporizador Una de las cuestiones que se ha eliminado después de las modificaciones del módulo de control de peticiones a la cámara, ha sido la necesidad de incluir temporizaciones (timers) para evitar posibles conflictos que ocurrían al recibir la respuesta de las peticiones HTTP debido a la mayor dificultad que tenía la clase QHttp para el control de la recepción de respuestas múltiples a múltiples peticiones (tales como las peticiones de secuencias de imágenes). Había por tanto que evitar el conflicto entre peticiones a través de algún mecanismo. La clase Temporizador del módulo de funciones auxiliares se creó para solventar este problema. Disponía de una serie de timers que lanzaban una señal de finalización tras un tiempo de finalización (timout) determinado y que permitían en ese momento lanzar la petición requerida. Antes de activar un timer (como por ejemplo la petición de un control a la cámara), el resto de timers que pudieran estar activos se paraban, de forma que no interfirieran en esa petición concreta. Tras finalizar la petición, el resto de timers volvían a habilitarse. Este tipo de temporizaciones ayudaron también a implementar un mecanismo de carga de controles de un estado de la cámara a través de un fichero, y cuyo proceso era ~ 35 ~ manejado de forma escalonada por diferentes timers que realizaban la carga de controles de forma paulatina. A este mecanismo se le llamó transición de carga, y en la siguiente captura se puede ver un esquema simple de su funcionamiento: Figura 11. Lectura de controles mediante el proceso de “transición de carga” Tal y como ya hemos comentado anteriormente, las nuevas funciones de comunicación con la cámara de la clase QNetworkAccessManager, se resuelve el conflicto entre peticiones debido a la diferenciación en el manejo de señales entre cada una de las clases que gobiernan las peticiones HTTP. En consecuencia, ahora las respuestas se procesan en SLOTs internos de la propia clase de forma excluyente, por lo que cualquier otra respuesta entrante deberá esperar su turno para procesarse. Se elimina por tanto la clase Temporizador y todos aquellos puntos del código donde se crean y eliminan los timers. El temporizador de la carga de imagen deja de ser necesario. Con el slot finish() de QAccessNetwork se controla que no se cargue la siguiente imagen hasta que no se ha cargado la anterior. De esta forma, el tiempo de delay entre capturas se ajusta a la capacidad de transmisión de la red y no a un timer, tal y como ocurría antes. Finalmente, siempre que se produzca alguna petición de control, se para la carga de imagen y se reanuda después de la petición, tal y como ya ocurría antes, con la diferencia de que ahora no tendremos que controlar los temporizadores. La transición de carga se ha adaptado de forma que ahora se utilizan una serie de flags que van emitiendo señales que lanzan de forma sincronizada la carga de los controles. Al igual ~ 36 ~ que con la carga de imagen, el tiempo de delay se ajustará a la transmisión de la red y no al timer. 2.3 Creación de Plataformas Android en Qt 5 A partir de la versión 5, Qt incorpora la plataforma Android para el desarrollo de aplicaciones heredando la funcionalidad directamente del proyecto Necessitas que se había iniciado unos años antes para hacer compatible la versión 4.8 con la creación de aplicaciones para la plataforma Android. El entorno QtCreator es prácticamente un calco al entorno de la versión QtCreator Necessitas for Android, utilizada para desarrollar la aplicación original, así como sus opciones de configuración. Figura 12. Configuración para los dispositivos Android en la versión 5 del entorno Qt Creator Una funcionalidad nueva que incorpora el panel de configuración de opciones de Android de la imagen anterior, es la posibilidad de descargar las JDK, SDK y NDK directamente desde el mismo panel. Una vez configurados todos los parámetros, se pueden añadir AVDs (Android Virtual Devices) al entorno para probar en modo simulación. No obstante en este Trabajo Fin de Grado, del mismo modo que se hizo en el PFC original, las pruebas se realizarán sobre el dispositivo Tablet PC ViewPad-S10 con sistema operativo Android-ViewComb. La parte de creación de plataformas del modo Proyectos de QtCreator tampoco ha cambiado mucho en relación a la versión de Necessitas, a excepción de incorporar ~ 37 ~ algunas opciones más en la configuración de compilación y ejecución (como es la firma de paquetes y el uso de certificaciones). Figura 13. Configuración de plataforma Android en la versión 5 del entorno Qt Creator Como observamos en la imagen, al configurar la plataforma podemos seleccionar entre otras cosas la versión del API de Android del dispositivo sobre el que deseamos instalar la aplicación. También nos permite instalar la aplicación Ministro [12] para cargar las librerías de Qt en el dispositivo, así como crear el AndroidManifest.xml para poder configurar parámetros de la aplicación Android dentro del propio QtCreator. A partir de aquí los pasos a realizar para instalar la aplicación Android en cualquier dispositivo serán los mismos que los llevados a cabo en el PFC original. Por otro lado, para incluir las librerías de OpenCV para el procesamiento de vídeo en la configuración de este tipo de plataformas hemos tenido que realizar algunos ajustes que incluyen entre otros, añadir la librería opencv_java de la versión de OpenCV para Android. Estos ajustes y correcciones surgidos en la configuración de OpenCV serán descritos con más detenimiento en el siguiente capítulo, donde también realizaremos un análisis de las nuevas funcionalidades de procesado de video añadidas a la aplicación a través de esta librería. ~ 38 ~ Capítulo 3 Funcionamiento de la aplicación en Cámaras IP de bajo coste Ante las nuevas funcionalidades añadidas en este Trabajo Fin de Grado a la aplicación Control Camera IP, en relación al tratamiento y a la aplicación de técnicas de detección sobre las imágenes recibidas desde la cámara IP A232D, utilizando para ello las librerías de la biblioteca de código abierto de OpenCV, se plantea la necesidad de verificar, también en este trabajo, que la aplicación es fácilmente adaptable para su funcionamiento en cámaras IP de distinto tipo y modelo al empleado hasta este momento en las pruebas realizadas. De cara a la implantación de futuras soluciones “smart” para la videovigilancia, es interesante la posibilidad de maximizar la compatibilidad de nuestra aplicación con el mayor número de modelos de cámaras IP del mercado, incluyendo tanto las gamas más altas como las de bajo coste, pudiendo por tanto flexibilizar al máximo la creación de soluciones de videovigilancia IP abiertas y fácilmente adaptables. Sin embargo, este propósito no es fácil de conseguir. Para empezar, muchas de las empresas venden sus productos de video IP dentro de soluciones cerradas, donde sus cámaras IP utilizan protocolos específicos para la petición de recursos desde sus propias aplicaciones de gestión de video, también cerradas. Por otro lado, no todas las cámaras disponen de APIs (Application Programming Interface) abiertos para su libre uso y distribución, y/o estandarizados, de forma que una misma API común pueda ser utilizado en una amplia gama de productos de diferentes marcas y proveedores. En relación a este último caso, sí que es factible hoy en día encontrar estándares de APIs para cámaras IP en aquellos modelos de bajo coste. La ventaja de las cámaras IP de bajo coste está ligada al hecho de que suelen estar dirigidas a un mercado de clientes mucho más amplio que el de las cámaras que forman parte de soluciones más sofisticadas, sobre todo dirigidas al ámbito de la seguridad, y que consecuentemente, suelen ser más caras de cara al usuario medio. Es por tanto interesante explorar las capacidades que nos ofrece las cámaras IP de bajo coste, no solo por su reducido precio, ~ 39 ~ sino también por la posibilidad que nos brindan para compatibilizar nuestra aplicación con una gran variedad de productos IP a través de un protocolo abierto y estandarizado. Una de estas APIs estandarizadas que cada vez está siendo más seguida por fabricantes de cámaras IP de bajo coste, es el API IPCAM CGI de Foscam [13]. Se trata de una API basada en comandos CGI, que engloba una serie de funciones de las cámaras IP más comunes, incluyendo funcionalidades PTZ (Pan, Tilt, Zoom), modos de vigilancia, etc. A diferencia del API CGI de las cámaras Axis (VAPIX) [14], el estándar abierto de Foscam incluye una aplicación CGI llamada decoder_control.cgi en la cual se integran todos los comandos más comunes que pueden aplicarse a las diferentes cámaras que sigan el estándar, de forma que si alguna cámara no dispone de un comando concreto, simplemente no tomará en cuenta la orden dada. En este capítulo, estudiaremos más detenidamente este API estandarizado, y analizaremos también algunos de sus CGIs, incluido el CGI decoder_control con algunos de sus comandos más utilizados. No obstante, previamente recordaremos de forma breve el funcionamiento del API de las cámaras AXIS (VAPIX), y algunos de los comandos CGI utilizados en la aplicación Control Camera IP. 3.1 VAPIX, el API de AXIS La aplicación original, utiliza para la conexión con la cámara A232D un API del fabricante AXIS denominado VAPIX. Este API, al igual que el API estandarizado IPCAM CGI que veremos a continuación, está conformado por un conjunto de funciones CGI que permiten la recepción de imágenes y parámetros, así como la ejecución de todas aquellas acciones para el control remoto de las cámaras IP de AXIS. Entre las funciones más destacadas de VAPIX que son lanzadas dentro de la aplicación Control Camera IP, encapsuladas dentro de peticiones HTTP, podemos destacar las siguientes: Recepción de imágenes con image.cgi La función image.cgi de VAPIX, permite la recepción de imágenes JPG con una compresión y resolución establecidas por los parámetros compression y resolution respectivamente. Las posibles resoluciones de las imágenes para la cámara A232D son tres: 4CIF, CIF y QCIF, las cuales pueden ser obtenidas directamente de la aplicación a ~ 40 ~ través del fichero de configuración valores.txt de cada plataforma. Por tanto, la expresión utilizada para realizar peticiones de imágenes a la cámara sería la siguiente: axis-cgi/jpg/image.cgi?resolution=<4CIF|CIF|QCIF>&compression=25 El valor de compresión se establece a 25 para todas las peticiones de imágenes en la aplicación. Obtención de controles PTZ La cámara A232D dispone de los tres controles PTZ que caracterizan a este tipo de cámaras IP, y que hace referencia a aquellas cámaras que son capaces de realizar movimientos en horizontal (Pan) hasta 360º y en vertical (Tilt) hasta 90º. Además también disponen de la función Zoom, que en el caso de la cámara A232D, su óptica integrada permite realizar un aumento de hasta 10X. Para utilizar los controles PTZ en la aplicación original, se utiliza la función ptz.cgi, a la cual se le puede pasar una serie de parámetros en función de la acción a realizar. He aquí algunos de los utilizados en la aplicación Control Camera IP:  Parámetro “move”: con los valores up, down, left y right, hace que la cámara se mueva un solo paso a alguna de las direcciones indicadas.  Parámetro “[r/d] zoom”: permite incrementar (rise) o decrementar (decrease) el zoom de la imagen.  Parámetro “<control>=<grados>”: establece el control Pan o Tilt en una posición determinada por el valor en grados asignado al parámetro.  Parámetros [r/d] focus e iris: similar al parámetro de zoom pero para incrementar o decrementar el enfoque de la imagen (focus), o la apertura (iris). Además de los parámetros anteriores, el parámetro query con el valor position, permite obtener los valores de los controles actuales de la cámara en texto plano. Esto permite que se puedan almacenar los controles de la cámara en el fichero de controles (controles.txt), el cual es utilizado posteriormente para la carga en la aplicación de unos controles determinados a través de la acción de lectura de controles. 3.2 El API estandarizado IPCAM CGI Foscam es una empresa de fabricación de productos de video ubicada en China, especializada en dispositivos de vigilancia, grabación de video y monitorización de ~ 41 ~ bebés. Hoy en día es mundialmente reconocida, gracias sobre todo a que sus productos ofrecen una alta funcionalidad práctica a un precio razonable, abarcando por tanto un mercado de clientes muy amplio. Figura 14. Algunos modelos de Cámaras IP de Foscam Es por eso mismo que Foscam decidió crear un sencillo API basado en CGI (IPCAM CGI), que permitiera a los usuarios desarrollar sus propias soluciones y aplicaciones para conectarse e interactuar con las cámaras Foscam, pero que no limitara la posibilidad de utilizar este mismo API con otro tipo de cámaras que quisieran seguir esta especificación. Así, con el tiempo, algunos fabricantes adoptaron este API, convirtiéndose en un estándar muy utilizado hoy en día sobre todo en productos de video IP de bajo coste. Entre los fabricantes que hoy en día permiten el uso del API de Foscam en sus cámaras podemos encontrar por ejemplo a Solwise [15], HooToo o INSTAR [16]. A continuación, vamos a analizar brevemente, algunas de las funciones más utilizadas del API IPCAM CGI (sobre todo aquellas que utilizaremos para adaptar nuestra aplicación), comenzando por las funciones de estado y de obtención de parámetros de la cámara. Hay que recordar, que una petición CGI se realiza a la cámara a través del protocolo HTTP, de igual forma que hacemos para conectarnos a la cámara A232D. En el caso del API IPCAM CGI, las peticiones son realizadas siempre con el mismo formato: http://<dirección_ip>/<comandoCGI>.cgi[?param=valor&...] ~ 42 ~ donde la expresión [?param=valor&...]indica la secuencia de parámetros opcionales que puede recibir la función CGI. 3.2.1 Funciones de estado y de obtención de parámetros de la cámara La función getStatus.cgi devuelve un contenido en texto plano (plain/text) con la información general de la cámara entre la que podemos incluir la siguiente:  Id: identificador del dispositivo  Now: la hora actual  Alarm Status: estado de la alarma, donde el valor recibido indica si la alarma está desactivada, si está activa la alarma por detección de movimiento o si está activa la alarma de detección por voz.  Wifi Status: en caso de que se trate de una cámara Wifi, indica si la conexión Wifi está activa o no. La función get_camera_params.cgi en cambio, obtiene los parámetros establecidos en la cámara también a través de texto plano. Los parámetros estándar que devuelve esta función son:  Resolution: resolución de la cámara (QVGA, VGA, etc…)  Brightness: brillo de la imagen (valores en el rango [0 – 255])  Contrast: contraste de la imagen con valores entre 0 y 6  Flip: permite voltear la imagen de la cámara tanto horizontal como verticalmente (muy útil para cámaras fijadas al techo) Hay que destacar que al ser un API diferente al de AXIS, muchos de los parámetros de las funciones CGI no coincidirán ni en su nombre ni en sus valores, por lo que habrá de ser tenido en cuenta al tratar de hacer la adaptación de un API al otro. 3.2.2 La función camera_control.cgi Esta función permite modificar los parámetros del sensor de la cámara entre los que se incluyen algunos de los parámetros comentados en la función get_camera_params. Como ya vimos, para establecer los parámetros utilizaremos la expresión [?param=valor&...]. Por tanto, si queremos modificar por ejemplo el brillo de la imagen al valor 135 realizaremos la petición: http://<dirección_ip>/camera_control.cgi?brightness=135 ~ 43 ~ los privilegios por lo que podrá realizar cualquier modificación en los parámetros y funciones de configuración de la cámara. 3.3.2 Modificaciones en el código de la aplicación Para empezar, la primera modificación a llevar a cabo, indispensable para el funcionamiento de la aplicación, es la relativa a la recepción de imágenes desde la cámara. 3.3.2.1 Modificaciones para la recepción de imágenes Para ello, y tal como ya hemos comentado, utilizaremos la función videostream.cgi del API IPCAM CGI en conjunción con la clase VideoCapture de la librería de video de OpenCV. La clase VideoCapture permite capturar secuencias de video a través de diferentes dispositivos, en función del parámetro que pasemos en su constructor. El más típico suele ser un valor entero (0,1,…) que representa el identificador de dispositivo de captura de video de alguna cámara que esté conectada a nuestro PC (una webcam por ejemplo. También puede recibir como parámetro un fichero de video o de una secuencia de imágenes, a través del acceso a una ruta local o a una localización remota. Este último caso es interesante debido a que podemos utilizarlo para abrir un flujo de captura de imágenes utilizando como fuente la secuencia de imágenes en stream que devuelve la función videostream.cgi. Así pues, primera modificación a realizar en nuestro código es la inclusión de la línea que ya mostramos anteriormente: VideoCapture captura(“http://<IP>/videostream.cgi”) A la función videostream.cgi le añadiremos también los parámetros admin y pwd para identificarnos como usuario, y además podremos incluir los parámetros resolution y rate para establecer la resolución y la tasa de imágenes por segundo respectivamente. El frame rate no lo hemos modificado, ya que por defecto está a full speed (valor 0), y ésta es una buena configuración para apreciar mejor los cambios en la imagen, a la hora de aplicar algunos de los métodos de detección y procesamiento sobre la imagen que se han desarrollado en este trabajo. La resolución en cambio, la hemos ajustado a los tres tipos de resolución que ya existían para su modificación en la aplicación, relativos a las cámaras AXIS: 4CIF, CIF y QCIF. ~ 50 ~ Aunque los valores de las resoluciones son diferentes, solo tenemos que modificar estos valores por los requeridos por la función videostream.cgi (por ejemplo, el valor “32” es el equivalente a la resolución 640x480) en el fichero valores.txt asociado a cada una de las plataformas, y utilizarlo en la línea de código anterior. Utilizando el operador >> de C++, podemos volcar en cualquier momento, un frame capturado del stream de video de la siguiente manera: captura >> frame Al tratarse de una clase de OpenCV, la variable frame será una estructura Mat que es inicializada con el contenido de la imagen volcada desde el stream de video. Así, podemos disponer directamente de la imagen Mat para procesarla utilizando los diferentes métodos desarrollados en este trabajo. No obstante, la imagen Mat habrá que convertirla a un componente QPixmap para poder mostrarla en el monitor de la aplicación. 3.3.2.2 Modificaciones de los controles de la cámara Con objeto de no extender demasiado el alcance de este Trabajo Fin de Grado, se han modificado únicamente a modo demostrativo los controles básicos de movimiento horizontal (Pan) y vertical (Tilt) en un paso, que son comandados en la interfaz de la aplicación Control Camera IP a través de las flechas de dirección en la parte derecha e inferior del monitor de recepción de imágenes. Así, deshabilitaremos para las pruebas la posibilidad de seleccionar en las barras de posicionamiento intermedias un valor concreto de Tilt y Pan, y además deshabilitaremos la función de Zoom ya que la cámara Conceptronic PTIW no dispone del mismo. Los controles de enfoque (focus) y de exposición del sensor (iris) tampoco están disponibles en esta cámara por lo que también serán deshabilitados. Por lo tanto, haremos únicamente que la cámara se mueva horizontalmente y verticalmente paso a paso. Como hemos comentado, como modo de demostrar la posibilidad de adaptar la aplicación a la API presentada en este capítulo, creemos que es suficiente con disponer únicamente de estos controles básicos. Se podrían añadir no obstante algunos de los modos de ronda de vigilancia que vienen incluidos en la cámara Conceptronic PTIW, o bien barridos horizontales y verticales sin establecer el parámetro onestep. Sin embargo, nos decantaremos por proponer estas ~ 51 ~ posibles mejoras para una futura ampliación de este trabajo, en la que se pueda realizar una adaptación integral y mucho más completa de la API en nuestra aplicación. En el siguiente apartado mostraremos las pruebas realizadas a lo largo de las pequeñas modificaciones que hemos realizado para hacer funcionar la aplicación Control Camera IP con la cámara Conceptronic PTIW, utilizando para ello la API IPCAM CGI estandarizada de Foscam. 3.3.3 Capturas de las pruebas realizadas Tras adaptar la aplicación Control Camera IP a las funciones de la API IPCAM CGI, incluyendo la recepción de imágenes a través del comando videostream.cgi, y el movimiento básico de la cámara con los controles de Tilt y Pan utilizando el parámetro onestep en la función CGI decoder_control, obtenemos el resultado que se puede observar en la siguiente captura: Figura 17. Captura de cámara Conceptronic tras aplicar el comando 6 (Pan) onestep a la derecha Además, incluimos también algunas capturas aplicando los nuevos métodos de OpenCV (los cuales describiremos en el capítulo 4), sobre la imagen capturada por la cámara Conceptronic PTIW. ~ 52 ~ Figura 18. Captura de cámara Conceptronic aplicando el algoritmo de Canny Figura 19. Captura de cámara Conceptronic aplicando el algoritmo de sustracción de fondo ~ 53 ~ Figura 20. Captura de cámara Conceptronic aplicando el método de detección de caras ~ 54 ~ Capítulo 4 Integración de Procesamiento de Vídeo con la Biblioteca OpenCV En este capítulo trataremos de abordar el desarrollo realizado sobre la aplicación Control Cámara IP que incluye varios métodos y técnicas de tratamiento sobre las imágenes recibidas desde la cámara, utilizando para ello la biblioteca de visión artificial OpenCV. En un primer bloque, realizaremos una descripción del funcionamiento de los módulos y funciones de OpenCV utilizadas en los desarrollos de este trabajo. Acto seguido, veremos el aspecto de la integración de la biblioteca OpenCV en Qt, así como la inclusión de librerías particulares para cada una de las plataformas. Por último, nos dedicaremos a explicar los detalles de diseño e implementación de los desarrollos realizados, incluyendo una descripción detallada de los métodos y algoritmos específicos utilizados para la obtención de las distintas soluciones de procesamiento de video incluidas en la aplicación. 4.1 La biblioteca de visión artificial OpenCV Tal y como ya hemos comentado en el capítulo de introducción, la biblioteca de procesamiento de video y visión artificial OpenCV está constituida por un conjunto de librerías de código abierto y de libre distribución, que ofrece amplias capacidades para todo tipo de aplicaciones relacionadas con la visión y el tratamiento de imágenes, con más de 500 funciones disponibles en cada uno de sus módulos. Para los desarrollos realizados en este Trabajo Fin de Grado, los cuales explicaremos más adelante, se han utilizado varias de estas clases y funciones pertenecientes a varios de los módulos de OpenCV. A continuación, realizaremos un breve análisis de cada una de estas funciones, y de su utilidad de cara a su uso en nuestra aplicación. ~ 55 ~ 4.1.1 Funciones del módulo Core En el módulo Core están definidas todas aquellas estructuras de datos y funciones básicas que establecen la forma de trabajar con los datos en general, y con las imágenes en particular, en OpenCV. Una primera cosa a entender cuando se trabaja con OpenCV es que los tipos de datos básicos típicos que se manejan en el lenguaje C++ (unsigned char, bool, signed short, int, float, double, etc.) pueden definirse a su vez como un identificador de la forma CV_<profundidad-bits>{U|S|F}C(<número-de-canales>). Esta manera particular de OpenCV de definir un tipo primitivo permite identificar tuplas de tipos básicos en una matriz de forma que, por ejemplo, una tupla de tres elementos de tipo punto flotante (float) puede definirse como CV_32FC3, donde el número 32 indica el tamaño o profundidad en bits del tipo (32 bits), el carácter ‘F’ representa el tipo básico (Float) y el número 3 el número de elementos, o como se suele llamar en el lenguaje de OpenCV, el número de canales. El número de canales en OpenCV representa normalmente el número de componentes de un elemento dentro de un vector (std::vector) o en una matriz (cv::Mat). Este número de componentes suele definir los distintos canales de color de una imagen. Es decir, en el ejemplo anterior, la tupla con tres elementos podría definir un píxel de una imagen RGB con las tres componentes de color rojo, verde y azul (Red, Green, Blue). En la siguiente imagen podemos observar un zoom realizado sobre una captura de una imagen mostrada con la función imshow() de OpenCV, donde se pueden apreciar las tuplas de tres elementos que definen cada uno de los píxeles con cada uno de los canales RGB que lo conforman. ~ 56 ~ Figura 21. Visualización de las componentes RGB haciendo zoom sobre una imagen La estructura de almacenamiento y manejo de imágenes más utilizada hoy en día en OpenCV es la clase Mat. Esta estructura definida en el lenguaje C++, fue incorporada para suplir las funcionalidades de la estructura IplImage, concebida originalmente cuando la biblioteca OpenCV fue creada en torno al lenguaje de programación C. Aunque la estructura IplImage sigue siendo muy utilizada en muchos tutoriales y como herramienta para el aprendizaje, actualmente cada vez es menos recurrida debido, por un lado, a que responsabiliza al programador de la gestión de memoria dinámica, cuestión heredada de la definición de estructuras de tipo puntero en C, y por otro, de las inherentes dificultades de depuración añadidas por el mismo motivo para los errores en el desarrollo de métodos o algoritmos complejos. Es por ello que, desde el surgimiento de C++ orientado a objetos, la clase Mat se configura como la estructura más apropiada para el manejo de imágenes en OpenCV. Sin embargo, el problema de estar definida en C++ es que todavía hoy existen muchos sistemas de desarrollo empotrado que solo soportan el lenguaje C. Así pues, es muy común que nos encontremos con soluciones que puedan incorporar cualquiera de las dos estructuras comentadas e incluso, en muchas ocasiones, una combinación de las mismas. En nuestro código haremos uso de las dos estructuras para algunos de los ~ 57 ~ métodos desarrollados. En el caso de IplImage, utilizaremos esta estructura en el ámbito privado de algunos de los algoritmos matemáticos implementados que realizan las operaciones sobre las imágenes a más bajo nivel. De esta forma, en caso de necesitar en un futuro migrar estos métodos a otros entornos de desarrollo que solo soporten el lenguaje C, no tendremos problema para reutilizarlos. A continuación veremos cómo se utilizan estas estructuras de datos para trabajar con imágenes en OpenCV. 4.1.1.1 Trabajando con imágenes IplImage El nombre IplImage viene de Intel Image Processing Library Image, y define una estructura (struct) en C con un conjunto de campos para el almacenamiento de una imagen. No obstante, el número de campos que pueden ser utilizados al crear esta estructura no es fijo, por lo que puede ser utilizada para definir la cabecera de una imagen únicamente, donde solo se utilizan los campos referentes a los metadatos (profundidad, número de canales, etc.), o bien puede ser utilizada también para almacenar el contenido de la imagen, para lo cual se utiliza el campo imageData, así como la estructura IplROI, la cual permite procesar únicamente una región de interés (Region Of Interest) concreta de la imagen [18]. Los campos más destacados de una estructura IplImage son los siguientes:  Campo nChannels: número de canales de la imagen (de 1 a 4 canales).  Campo depth: Profundidad de cada canal en bits más un bit de signo opcional (IPL_DEPTH_SIGN). A diferencia de la estructura Mat los formatos soportados comienzan con el prefijo IPL_DEPTH en lugar de CV. Por ejemplo, el identificador de tipo punto flotante de simple precisión sería IPL_DEPTH_32F, que es equivalente a CV_32F.  Campos width y height: definen la altura (número de filas) y anchura (número de columnas) de la imagen en pixeles.  Campo imageSize: es el tamaño de la imagen en bytes, o lo que es lo mismo, el resultado de multiplicar la altura (o el número de filas) por el paso en anchura (widthStep).  Campo widthStep: el paso en anchura es el número de bytes de todos los píxeles de una fila de la imagen, que vendrá dado por el tamaño del tipo básico ~ 58 ~ almacenado multiplicado por la anchura de la imagen (número de columnas) y por el número de canales.  Campo imageData: se define como un puntero a la estructura de datos que almacena la imagen. Para crear una imagen con la estructura IplImage se utiliza la función cvCreateImage(), que acepta como parámetros de entrada los elementos básicos que conforman la cabecera de la imagen, es decir, el tamaño (cvSize), que define la altura y la anchura de la imagen, la profundidad en alguno de los formatos válidos vistos anteriormente, y el número de canales. Esta función devuelve como resultado un puntero a una estructura IplImage con una cabecera establecida y asigna memoria dinámica al campo imageData de forma que pueda ser utilizado para almacenar el contenido de la imagen. Por otro lado, si ya disponemos de una imagen almacenada como estructura IplImage, la función cvCloneImage() nos permite realizar una copia completa de la imagen, incluyendo la cabecera y el contenido de la misma. Por último, para liberar la memoria reservada para almacenar este tipo de estructura es necesario recurrir a la función cvReleaseImage(). 4.1.1.2 Trabajando con la clase Mat Desde la inclusión de librerías de clases de C++ en la biblioteca de OpenCV, se eliminó la necesidad de reservar y liberar memoria de forma manual para las diferentes estructuras de datos. Así, las nuevas funciones permitirían reservar los datos de salida de forma automática, así como hacer uso compartido y más eficiente de los recursos del sistema. La estructura Mat para almacenamiento y gestión de imágenes en OpenCV se crea en base a una matriz con dos partes bien definidas: la cabecera, que contiene entre otros datos el tamaño de la matriz, el método de almacenamiento y la dirección de memoria donde se almacena; y un puntero a la matriz conteniendo los valores de los píxeles tomando las dependencias de dimensionamiento en función del método de almacenamiento elegido. Si bien la cabecera de la matriz es fija, el tamaño de los datos contenidos en la matriz puede variar de imagen a imagen en varios órdenes de magnitud. La idea es que cada objeto Mat tiene su cabecera, pero sin embargo, el contenido de la matriz puede ser compartido por dos instancias de la misma, de forma que sus punteros ~ 59 ~ Las características tipo Haar deben su nombre a su similitud con la idea del wavelet de Haar [19]. Para el cálculo de estas características se consideran regiones rectangulares adyacentes dentro de la ventana de detección, y se calcula la diferencia entre las sumas de las intensidades de los píxeles de cada una de ellas. Estas diferencias permiten categorizar las subsecciones de una imagen, y de esta forma se puede comprobar de forma fácil y rápida si una determinada región de interés encaja con este tipo de características. En el caso de una cara por ejemplo, es fácil observar que en todas ellas la región de los ojos es más oscura que la región de las mejillas. Así pues, se puede definir una característica tipo Haar que considere dos regiones rectangulares adyacentes que encajen, una sobre los ojos, y otra sobre la región de las mejillas. Figura 25. Ejemplo de cálculo de características tipo Haar para la detección de caras La del centro clasifica la relación ojos-mejillas. La de la derecha clasifica la relación ojos-entrecejo. El clasificador Haar está diseñado para que pueda ser redimensionado fácilmente, de forma que pueda ser capaz de encontrar objetos de interés de diferentes tamaños en la imagen, lo cual es mucho más eficiente que tener que redimensionar la imagen de entrada. ~ 66 ~ 4.1.3.2 Cargando un clasificador con la función load() La función load() del módulo ObjDetect nos permite cargar un nuevo clasificador en cascada a partir de un archivo que con el clasificador entrenado por algunas de las aplicaciones de entrenamiento [20]. Para el método de detección implementado en este trabajo utilizaremos el clasificador para detección de caras en perspectiva frontal incluido en las propias librerías de OpenCV [21], y que está definido en el archivo XML lbpcascade_frontalface.xml. Una vez cargado, el clasificador puede ser utilizado por cualquier método de detección. Para este trabajo, hemos utilizado la función detectMultiScale del módulo ObjDetect de OpenCV. 4.1.3.3 La función detectMultiScale Esta función permite detectar objetos de diferentes tamaños aplicando un clasificador previamente definido. La función recibe como entrada la imagen en una estructura Mat y devuelve por referencia un vector de polígonos rectangulares (tipo Rect) que definen las regiones donde el objeto ha sido detectado. Entre otros parámetros de entrada que se pueden introducir podemos nombrar el factor de escalado, el número mínimo de vecinos o el tamaño mínimo o máximo del objeto a detectar. El parámetro “número mínimo de vecinos” está relacionado con la forma de funcionamiento del algoritmo de detección cuando va deslizando la ventana del clasificador a lo largo de las regiones de la imagen. Como ya comentamos anteriormente, la ventana del clasificador es redimensionada para ajustarse a los distintos tamaños que pueda tener el objeto a detectar. Si el rango de tamaños es lo suficientemente amplio los falsos positivos serán muy frecuentes, sobre todo si se establece un tamaño mínimo muy pequeño. Esto hace además, que para un mismo objeto a detectar (una cara por ejemplo), se obtengan múltiples coincidencias para tamaños similares, por lo que el algoritmo obtendría a la salida varios rectángulos para un mismo objeto. Para evitar los falsos positivos, se establece un número mínimo de vecinos (número de rectángulos cercanos) de forma que si el objeto tiene un número igual o superior a ese valor de rectángulos cercanos, ese será el objeto a detectar. ~ 67 ~ Más adelante, realizaremos algunas pruebas utilizando el método de detección de caras que se ha incluido en este trabajo, donde modificaremos algunos parámetros de la función detectMultiScale() para mostrar el funcionamiento del algoritmo. 4.2 Integración de las librerías de OpenCV en Qt5 El primer paso para añadir a la aplicación Control Camera IP las funcionalidades de detección y procesamiento sobre la imagen comentadas en apartados anteriores, es necesario incluir las librerías de OpenCV específicas para cada una de las diferentes plataformas sobre las que tenemos definidas una configuración de ámbito en el fichero .pro del proyecto Qt. Esto es debido a que, evidentemente, existen diferentes versiones de kit de desarrollo software (SDK) de la biblioteca OpenCV optimizadas para su utilización en las diferentes plataformas (MS Windows, Linux Debian, Android, etc.), lo que hace que al momento de enlazar estas librerías dentro del proyecto Qt tengamos que establecer las diferentes rutas a los SDKs en los diferentes ámbitos del fichero .pro en función de la plataforma. Así pues, nos disponemos a describir brevemente la instalación de OpenCV y la inclusión de sus librerías en el proyecto Qt, para las distintas plataformas que se han utilizado para probar los desarrollos realizados en este trabajo. 4.2.1 Integrando las librerías de OpenCV para la plataforma Microsoft Windows 7 La forma más sencilla de instalar OpenCV en Windows es a través de las librerías precompiladas habilitadas para ello, y que se pueden descargar directamente accediendo al siguiente enlace [22]. Al venir encapsuladas en la forma de un instalador típico para entornos Windows, el proceso de instalación de las librerías es sencillo. Una vez instaladas, dispondremos en el directorio de instalación de los diferentes subdirectorios que contienen entre otras, las librerías de enlace dinámico (.dll) para el compilador minGW utilizado por Windows para compilar los proyectos Qt. MinGW (Minimalist GNU for Windows) es una implementación de los compiladores GCC de GNU (compiladores de código C/C++ para Unix) para la plataforma Win32. Al ser la forma en la que el entorno QtCreator compila los proyectos en las plataformas ~ 68 ~ Windows, es necesario que las librerías de OpenCV se ajusten a este compilador cuando se trabaje con este tipo de plataformas. Por tanto, en el directorio de instalación de OpenCV en Windows localizaremos la siguiente ruta: <dir_instalación_OpenCV>\install\x64\mingw\bin En esta ruta se incluyen todas las librerías de OpenCV preparadas para ser enlazadas por el compilador minGW de Qt. Así pues, para configurar la plataforma win32 para que cargue en la construcción del proyecto Qt las librerías de OpenCV, editaremos el ámbito de la plataforma Windows del fichero .pro con el siguiente contenido: win32 { LIBS_PATH = "$$OPENCV_PATH\\install\\x64\\mingw\\bin" LIBS += -L$$LIBS_PATH \ -lopencv_core2410 \ -lopencv_highgui2410 \ -lopencv_imgproc2410 \ -lopencv_features2d2410 \ -lopencv_objdetect2410 } Como podemos ver, las librerías incluidas son las relativas a los módulos de OpenCV que hemos explicado en secciones anteriores. Añadiremos también las librerías del módulo Features2D para dejar abierta la posibilidad de añadir nuevas funcionalidades a la aplicación en un futuro, y que éstas puedan utilizar algunas de las funciones de detección de características de las que dispone este módulo. Asimismo, es necesario añadir también al fichero .pro las cabeceras .h de las clases C++ incluidas en las librerías, de forma que podamos importarlas directamente en el código de nuestro proyecto Qt: INCLUDEPATH += $$OPENCV_PATH\\include 4.2.2 Integrando las librerías de OpenCV para la plataforma Linux Ubuntu 14.04 Para instalar la biblioteca OpenCV en una distribución Linux basada en Debian (en nuestro caso hemos utilizado la distribución Ubuntu 14.04 – Trusty Tahr), la forma más recomendable es hacerlo a través de la herramienta de generación de código CMake. ~ 69 ~ CMake permite generar ficheros de construcción (MakeFiles) a partir de una serie de reglas establecidas en un fichero de configuración llamado CMakeLists.txt, y que indica cómo se deben construir los programas y en que localización deben almacenarse. Muchos programas de instalación para Linux, vienen ya preparados con un fichero CMakeLists para que sean construidos a partir de CMake. No obstante, quizás la forma más sencilla de instalar OpenCV en Ubuntu sea a través de la herramienta APT (Advanced Packaging Took) a través del comando: >sudo apt-get install opencv-<versión> Sin embargo, este método de instalación puede dar lugar a que algunas librerías no estén disponibles (tales como las relativas al módulo nonfree) tras la instalación, y además, no permite especificar opciones de configuración, tales como las librerías gráficas de visualización de componentes (GTK+, QtWidgets), y la opción de incluir aceleradores de rendimiento tales como OpenCL para las funciones de OpenCV. Así pues, para instalar OpenCV en Ubuntu, podemos descargar la última versión del siguiente enlace [23]. Al descomprimir el directorio, podemos seguir los siguientes pasos para la instalación con CMake: 1Nos situamos en el directorio de OpenCV 2Creamos un directorio llamado build y nos situamos dentro de él. 3Con CMake instalado escribimos en la consola: >cmake .. 4Tras el proceso de generación de MakeFiles escribimos: >make 5Y finalmente para la instalación en el sistema: >sudo make install Tras el proceso de instalación, los directorios de las librerías de OpenCV y de las cabeceras deberían de haber sido generados dentro del directorio build, y además estas deberían de haber sido incluidas en el pkg-config de la instalación. El software pkgconfig permite acceder a las librerías y cabeceras de la instalación de OpenCV de la siguiente manera: >pkg-config --cflags –libs opencv ~ 70 ~ Por tanto, para incluir las librerías y cabeceras de OpenCV dentro del ámbito de la plataforma Linux Ubuntu podemos realizarlo de forma sencilla añadiendo las siguientes líneas al fichero .pro: INCLUDEPATH += “pkg-config --cflags opencv” LIBS += “pkg-config --libs opencv” No obstante, si se quieren incluir librerías y cabeceras de módulos específicos también es posible hacerlo de la misma manera que hacíamos con la plataforma Windows tomando como ruta base el directorio build. 4.2.2 Integrando las librerías de OpenCV para la plataforma Android Las librerías de OpenCV para la plataforma Android podemos descargarlas del siguiente enlace [24]. Para este caso concreto, el proceso de incorporar las librerías es un poco más delicado que en el resto de plataformas, debido a que al compilar las librerías de OpenCV, al igual que las librerías de Qt y el resto de recursos necesarios para el funcionamiento de la aplicación, éstas además tienen que ser traducidas al mismo tiempo a código Java. Así, la nueva versión 5 de Qt incorpora un conjunto de librerías y controladores nativos para la plataforma Android, que son necesarias para que el compilador pueda traducir el código nativo en C++ a código Java, de forma que éste pueda ser interpretado por la máquina dalvik del dispositivo Android, y por lo tanto éstas librerías también deberán ser cargadas en el dispositivo destino al realizar la instalación de la aplicación. Sin embargo, entre este conjunto de elementos es necesario añadir alguna librería nativa que permita al dispositivo Android interpretar las funciones de OpenCV incluidas en la aplicación. Es por ello que el primer paso necesario antes de compilar la aplicación, consiste en copiar la librería nativa opencv_java.so en el directorio de librerías nativas de Qt para la plataforma Android. La librería opencv_java.so podemos encontrarla en la ruta del directorio de librerías nativas del SDK de OpenCV para Android. Si queremos utilizar también otras librerías nativas tales como aquellas que permiten el funcionamiento de la cámara del dispositivo, podremos incluirlas de la misma manera en el directorio de librerías nativas de Qt para la plataforma (para la cámara nativa podríamos utilizar la librería libnative_camera). Sin embargo, en algunos casos es ~ 71 ~ posible que existan dependencias con otras librerías y obtengamos por ello problemas en tiempo de compilación o ejecución, por lo que es mejor evitar utilizarlas si no las vamos a necesitar. Una vez incorporada la librería opencv_java entre las librerías nativas de Qt para la plataforma Android, tenemos que incluirla también en el fichero .pro para que pueda enlazarse con la aplicación, además de incluir también el conjunto de librerías de OpenCV de los distintos módulos que utilizaremos: android { ANDROID_LIBS = "$$ANDROID_OPENCV/sdk/native/libs" ANDROID_JNI = "$$ANDROID_OPENCV/sdk/native/jni" ANDROID_3PARTY = "$$ANDROID_OPENCV/sdk/native/3rdparty" INCLUDEPATH += \ $$ANDROID_JNI/include/ \ #core module $$ANDROID_JNI/include/opencv2/highgui/ \ #highgui module $$ANDROID_JNI/include/opencv2/imgproc/ #imgproc module LIBS += \ #Esta línea es necesaria! $$ANDROID_LIBS/armeabi-v7a/libopencv_java.so \ #$$ANDROID_LIBS/armeabi-v7a/libnative_camera_r2.2.0.so \ $$ANDROID_LIBS/armeabi-v7a/libopencv_contrib.a \ $$ANDROID_LIBS/armeabi-v7a/libopencv_legacy.a \ $$ANDROID_LIBS/armeabi-v7a/libopencv_ml.a \ $$ANDROID_LIBS/armeabi-v7a/libopencv_objdetect.a \ $$ANDROID_LIBS/armeabi-v7a/libopencv_calib3d.a \ $$ANDROID_LIBS/armeabi-v7a/libopencv_video.a \ $$ANDROID_LIBS/armeabi-v7a/libopencv_features2d.a \ $$ANDROID_LIBS/armeabi-v7a/libopencv_highgui.a \ $$ANDROID_LIBS/armeabi-v7a/libopencv_androidcamera.a \ $$ANDROID_LIBS/armeabi-v7a/libopencv_flann.a \ $$ANDROID_LIBS/armeabi-v7a/libopencv_imgproc.a \ $$ANDROID_LIBS/armeabi-v7a/libopencv_core.a \ $$ANDROID_3PARTY/libs/armeabi-v7a/liblibjpeg.a \ $$ANDROID_3PARTY/libs/armeabi-v7a/liblibpng.a \ $$ANDROID_3PARTY/libs/armeabi-v7a/liblibtiff.a \ $$ANDROID_3PARTY/libs/armeabi-v7a/liblibjasper.a \ $$ANDROID_3PARTY/libs/armeabi-v7a/libtbb.a Podemos observar que en este caso en el fichero .pro se incluyen un número más elevado de librerías que en las plataformas anteriores. Esto es necesario por dos motivos principales. El primero es que, aunque algunos de los módulos de OpenCV no los vayamos a utilizar en la aplicación actual, es aconsejable incluir todos los módulos para hacer más flexible la escalabilidad de la aplicación en un futuro en este tipo de plataformas. ~ 72 ~ El segundo motivo, y más importante, es el mismo que comentábamos anteriormente sobre las dependencias de las librerías nativas. Debido a ciertos aspectos de enlazado de las librerías por el compilador GCC armeabi (ARM Extended Application Binary Interface) de código nativo para Android utilizado por Qt, el orden de la inclusión de las librerías es importante (de hecho el orden en el que aparecen las librerías en las líneas anteriores del fichero .pro no es casual), debido sobre todo a las dependencias existentes entre ellas. Por ello, hay que tener cuidado con el orden a la hora de incluir nuevas librerías, sobre todo si implican código nativo para plataformas con arquitecturas diferentes a las más usuales. También podemos observar que se han incluido en el fichero .pro la ruta a las cabeceras de las funciones de OpenCV, y además otras librerías llamadas 3rdParty. Estas librerías son necesarias para aspectos tales como la decodificación de formatos de imagen en OpenCV. 4.3 Desarrollo de los métodos de procesamiento de video A continuación nos dedicaremos a describir los desarrollos que se han llevado a cabo en la aplicación Control Camera IP para la inclusión de procesamiento de video haciendo uso de algunas de las librerías de OpenCV, las cuales ya hemos avanzado en apartados anteriores. Para acceder a cada una de las funcionalidades de OpenCV se ha añadido a las diferentes vistas de la interfaz gráfica un nuevo elemento en la barra de menús denominado Procesamiento de Video, de forma que al desplegarlo aparecen las diferentes acciones para lanzar alguno de los métodos de procesamiento de video implementados. Estas acciones tienen como nombre "Detección de Bordes”, “Brillo y Contraste”, “Sustracción de Fondo”, “Blobs Color” y “Activar/Desactivar Detección de Caras”. ~ 73 ~ Figura 26. Diseño del nuevo menú Procesamiento de Video con sus distintas acciones Al activar alguna de las cuatro primeras acciones, se visualizará un diálogo (QDialog) que permitirá al usuario modificar algunos parámetros del método o algoritmo, pudiéndose apreciar estos cambios sobre el monitor de imágenes. Estos diálogos estarán definidos en el proyecto Qt como clases de formulario Form dentro de un nuevo paquete denominado procesamientoVideo, de forma similar a como está definido el paquete dialogoConexion. Asimismo, para organizar los distintos métodos desarrollados con OpenCV, además de las funciones auxiliares utilizadas por los mismos, se ha creado una nueva clase dentro del paquete auxiliares denominada “FuncionesOpenCV”. Figura 27. Nueva estructura del proyecto Qt Clase FuncionesOpenCV y paquete procesamientoVideo con los diálogos de los métodos de OpenCV ~ 74 ~ 4.3.1 La nueva clase auxiliar FuncionesOpenCV La clase FuncionesOpenCV definida dentro del paquete auxiliares, ha sido creada con el propósito de contener todas aquellas funciones y algoritmos que están dentro del ámbito de los nuevos desarrollos realizados con OpenCV dentro de la aplicación. Es decir, en esta clase están definidas todas aquellas operaciones de conversión, funciones de tratamiento sobre la imagen o algoritmos de detección que son utilizados por el programa principal para ejecutar los distintos métodos de procesamiento de vídeo que explicaremos más adelante. Figura 28. Nueva Clase FuncionesOpenCV del paquete auxiliares A parte de los algoritmos o funciones propias de los métodos desarrollados, en la clase FuncionesOpenCV se han incluido dos herramientas auxiliares de conversión que tienen la capacidad por un lado, de transformar las capturas de la cámara obtenidas por la aplicación y que son almacenadas como una imagen de Qt (QPixmap) en una imagen OpenCV con estructura Mat, así como también, realizar la operación inversa (de Mat a QPixmap). Estas funciones son fundamentales para poder aplicar las operaciones de OpenCV sobre la imagen cargada en el componente QLabel (monitor) de la aplicación. Así, previamente a la utilización de cualquier método de procesamiento sobre la imagen con OpenCV, se convertirá la imagen QPixmap a una estructura Mat. Asimismo, una vez realizado el tratamiento sobre la misma, la imagen Mat volverá a convertirse en una imagen QPixmap para ser cargada de nuevo en el monitor. A continuación explicamos de forma breve el funcionamiento de estas dos funciones de conversión: ~ 75 ~ requerimientos computacionales que supone la utilización de este método detección, pero fundamentalmente, y también por el mismo motivo, es debido a que uno de los pasos del algoritmo de Canny tiene como objetivo localizar cambios en la imagen donde la intensidad de los píxeles en la escala de grises ha tenido una variación significativa. Este paso se conoce como “búsqueda de gradientes de intensidad”. Los gradientes en cada píxel de la imagen filtrada se obtienen con lo que se conoce como el operador Sobel (Sobel-operator) [26] . El primer paso consiste en aproximar el gradiente (primera derivada) en la dirección x y en la dirección y respectivamente, aplicando los kernels mostrados a continuación: Así, las magnitudes de los gradientes se pueden determinar como una medida de la distancia Euclídea, o bien aplicando una medida de la distancia Manhattan (con esta última se reduce la complejidad computacional) sobre las aproximaciones de gradiente en la dirección x e y para cada uno de los píxeles de la imagen, aplicando los kernels anteriores. Supresión de los no máximos Este paso consiste básicamente en convertir los bordes difuminados obtenidos en la imagen de magnitudes de gradiente, en bordes más “refinados”. Este efecto se consigue preservando todos los máximos locales en la imagen de gradientes y eliminando todo lo demás (los no máximos). Para ello se realiza una comparación de los píxeles teniendo en cuenta la dirección de su gradiente y su módulo con respecto a sus píxeles vecinos. Si los valores de los vecinos en la línea positiva y negativa de su gradiente son mayores, el valor del píxel es suprimido. Umbral doble Los píxeles que quedan tras aplicar la supresión de los no máximos están todavía marcados con su “fuerza” o valor de gradiente. Es posible que muchos formen parte de bordes verdaderos, pero algunos serán producto del ruido o de las variaciones de color en la imagen. La mejor manera de dejar únicamente los bordes más “fuertes” (con mayor valor de gradiente) es a través de un valor de umbral o threshold. ~ 82 ~ El algoritmo de Canny utiliza dos valores de umbral. Por un lado, los píxeles de bordes más fuertes que el valor de umbral alto son marcados como fuertes (strong). Por otro, los píxeles de bordes más débiles que el valor de umbral bajo son suprimidos. Finalmente, los píxeles de bordes que están entre los dos valores de umbral serán marcados como débiles (weak). Rastreo de bordes por histéresis La idea es que los bordes fuertes sean interpretados como bordes verdaderos, y por lo tanto serán incluidos inmediatamente en la imagen final. Sin embargo, los bordes débiles solo serán incluidos si éstos están conectados a bordes fuertes, ya que es más probable que, si este no es el caso, estos bordes sean producto del ruido o de variaciones en el color de la imagen. El rastreo de los bordes puede ser implementado utilizando análisis de conjuntos de píxeles o BLOBs (Binary Large OBjects) en la imagen, de forma que si estos BLOBs contienen al menos un píxel fuerte, entonces estos conjuntos serán preservados. Figura 31. Rastreo de bordes y salida final La imagen del medio muestra los bordes fuertes en blanco, los bordes débiles conectados a los fuertes en azul, y el resto de bordes débiles que son descartados para la imagen final en rojo 4.3.2.2 Diálogo BorderDetectionDialog Volviendo al diálogo (QDialog) mostrado en la figura 19 de un apartado anterior, podemos distinguir una serie de parámetros de corrección con los que podemos interactuar para modificar ciertos valores que inciden en la detección de bordes, y que ya hemos comentado en el punto anterior. Son tres los parámetros que pueden ser modificados para este método de detección. ~ 83 ~ En primer lugar, el tamaño del kernel utilizado al aplicar el filtro Gaussiano en el primer paso del algoritmo de Canny. El elemento QComboBox nos permite seleccionar entre dos valores de tamaño de kernel: valor 3 y valor 5. Este tamaño de kernel es pasado como argumento tanto a la función blur() como a la función Canny() de OpenCV, de forma que tanto el filtro de caja normalizado como el filtro Gaussiano se realice utilizando el tamaño de kernel indicado. El efecto producido en la imagen resultante en función de si se establece uno u otro tamaño dependerá también de los valores de umbral, pero aunque pueda parecer que un valor más elevado de tamaño de kernel produciría mejores resultados en la detección de bordes, podemos comprobar en las siguientes capturas que en nuestro caso esto no ocurre así: Figura 32. Detección de bordes con un tamaño de Kernel igual a 5 ~ 84 ~ Figura 33. Detección de bordes con un tamaño de Kernel igual a 3 Esto es debido a que el filtro Gaussiano viene determinado por el valor de la desviación típica (σ) de la distribución obtenida para las primeras derivadas de x e y que establecen los valores del kernel sobre cada píxel de la imagen. Seleccionando valores bajos de desviación típica (valor bajo de tamaño de kernel), se filtrarán los cambios o transiciones de intensidad más agudas entre los píxeles. En cambio, con valores altos de desviación típica, estas transiciones serán más graduales. En ocasiones, el hecho de que las transiciones de intensidad entre píxeles sean graduales (gran suavizado), nos permitirá tener una imagen con menos ruido, pero por otro lado podremos perder definición, lo cual para el computo de los gradientes en la detección de bordes puede resultar contraproducente, generando muchos falsos positivos. Es por ello, que para cada imagen debe buscarse el tamaño de kernel más apropiado que permita que los cambios de intensidad entre los píxeles no sean ni muy bruscos ni muy graduales. También como ya hemos visto anteriormente, otro de los pasos a aplicar en el algoritmo de Canny es el de la utilización del doble umbral. En el método que hemos implementado, hemos utilizado un único valor de umbral (umbral bajo) como parámetro de corrección en el diálogo. El umbra alto sin embargo, es calculado utilizando un valor de ratio que establece una relación 1 a 2 o 1 a 3 con el umbral bajo. Es decir, podremos seleccionar que el umbral alto sea o bien el doble o el triple del valor del umbral bajo. De esta forma, modificando cualquiera de los dos parámetros de corrección del diálogo ~ 85 ~ relativos al umbral bajo y al ratio, podemos obtener diferentes resultados tal y como se puede apreciar en las siguientes capturas: Figura 34. Detección de bordes con ratio 1:2 y umbral bajo a 96 Figura 35. Detección de bordes con ratio 1:3 y umbral bajo a 19 ~ 86 ~ 4.3.3 Implementación de las funciones de brillo y contraste Las funciones de regulación de brillo y contraste que se han implementado pueden activarse a través de la acción “Brillo y Contraste” del menú Procesamiento de Video. De igual forma que ocurría con la detección de bordes, la señal triggered() asociada a esta acción del menú lanzará un Slot de la clase MainWindow llamado mostrarBrilloContraste(), que creará un nuevo diálogo para activar las funciones de brillo y contraste: Figura 36. Dialogo de control para las funciones de brillo y contraste Como en el método de detección de bordes, las funciones de brillo y contraste se activan a través del elemento QCheckBox del diálogo. Al clicar sobre este elemento, se lanzará el Slot activarBrilloYContraste() de la clase BrightContrastDialog (la clase donde está definido el diálogo). En este Slot, se habilitarán los parámetros de corrección para regular el brillo y contraste de la imagen, y se establecerá el valor de la variable de la clase principal brilloContrasteActivo al valor True, de forma que a partir de ese momento se puedan interceptar las imágenes recibidas desde la cámara para ser procesadas por estas funciones de brillo y contraste. Por lo tanto, entramos en el mismo mecanismo común a todos los métodos y que permite interceptar las imágenes, convertirlas al formato de OpenCV, aplicar el método deseado y volver a convertirlas de nuevo al componente QPixmap del monitor. Al poner a valor False el flag de activación del método (clicando de nuevo en el QCheckBox del diálogo) la aplicación volverá a su estado original mostrando la imagen de la cámara sin procesar. ~ 87 ~ 4.3.3.1 Descripción del método Al activar en el QDialog estas funciones, es lanzado el procedimiento calcularBrightContrast() definido en la clase FuncionesOpenCV. El ajuste de brillo y contraste es una utilidad disponible en la mayoría de aparatos de imagen digital, la cual permite ajustar la calidad de la imagen en función de dos parámetros que pueden aplicarse a cada uno de los píxeles. Estos parámetros son el nivel de luminosidad (brillo) y la diferencia de intensidades entre píxeles (contraste). Estos dos parámetros funcionan muy bien en consonancia, ya que la alteración del brillo en la imagen permite obtener diferenciaciones de intensidad en los píxeles de la imagen que hace que si estas variaciones son amplias, y el factor de contraste es superior a un determinado umbral, los objetos en la imagen puedan mostrarse más definidos. La aplicación de estas modificaciones a los píxeles de la imagen resulta en un cálculo fácil y sencillo, que consiste en operar cada píxel con un valor de ganancia (gain), que representa el factor de luminosidad de la imagen (brillo), y un valor discriminante (bias), que marca la diferenciación de la luminosidad entre los píxeles (contraste). Estos dos valores, también denotados como parámetro alpha (α) y parámetro beta (β) respectivamente, serán los utilizados para realizar el ajuste del brillo y contraste de la imagen en nuestra implementación. La operación a realizar en cada uno de los píxeles de la imagen Mat que se recibe como entrada en la función de cálculo de brillo y contraste es la siguiente: Donde la función f ( i, j ) es el valor de cada color del píxel. Si el formato es RGB por ejemplo, la función deberá ser aplicada tres veces por cada píxel, una por cada color del mismo. Los valores del parámetro α estarán definidos en el rango [1.0 – 3.0]. En cambio, el parámetro β podrá tener un valor entero definido entre 0 y 100. 4.3.3.2 Diálogo BrightContrastDialog Tal y como acabamos de ver, el proceso de cálculo sobre la imagen para modificar el brillo y el contraste es muy sencillo. Para alterar cualquiera de estas dos magnitudes en nuestra aplicación, simplemente tendremos que modificar los valores de corrección del diálogo de la figura 26. ~ 88 ~ Así, otorgando diferentes valores a los parámetros α y β en el diálogo, podemos obtener resultados como los que se muestran en las siguientes capturas: Figura 37. Operaciones de Brillo y Contraste sobre la imagen con diferentes niveles de corrección 4.3.4 Implementación del algoritmo de sustracción de fondo La sustracción de fondo consiste básicamente en la obtención de una máscara que contenga los píxeles de los objetos móviles en la imagen. Este método es interesante en ~ 89 ~ aplicaciones de videovigilancia para la detección de personas u objetos en movimiento, ya que con una regulación correcta de sus parámetros, es capaz de sustraer toda la información de la imagen en la que no haya habido variación entre fotograma y fotograma. De lo anterior se deduce que para este método será necesario tener en cuenta no solo la imagen actual, sino la imagen recibida en la petición anterior, con el objeto de obtener las diferencias entre ambas. Figura 38. Esquema que refleja la idea del método de sustracción de fondo El algoritmo de sustracción de fondo es activado a través de la acción “Sustracción de Fondo” del menú Procesamiento de Video. De igual forma que en los métodos ya explicados, esta acción lanza un diálogo a través del Slot mostrarSustraccionFondo(), el cual se muestra a continuación: Figura 39. Dialogo de control para el algoritmo de sustracción de fondo ~ 90 ~ Al clicar sobre el elemento QCheckbox se lanzará el Slot activarSustraccionFondo() de la clase BackgroudSubDialog, que realizará las mismas operaciones que los Slots de los diálogos del resto de métodos. El valor de la variable sustraccionFondoActivo se pondrá a True para comenzar a ejecutar el algoritmo. Aunque existen funciones del módulo de análisis de video de OpenCV (el cual no será tratado aquí) para realizar la sustracción de fondo, tales como createBackgroundSubstractorMOG2(), hemos preferido realizar la implementación basándonos en la idea que subyace en la definición del algoritmo, obteniendo de esta manera un método básico de comparación entre imágenes, que permite sustraer aquellos píxeles que se han mantenido con el mismo valor. 4.3.4.1 Descripción del método Para la implementación del algoritmo de sustracción de fondo se ha utilizado la estructura IplImage de C, teniendo en mente la posibilidad de portar esta implementación en otras plataformas que no soporten C++ o versiones de OpenCV más recientes. El mecanismo utilizado consiste en clonar la imagen Mat original convertida a escala de grises (función cvtColor() con el modificador CV_BGR2GRAY), en una estructura IplImage que contenga la referencia a los datos de la imagen (puntero imageData). Con la primera imagen recibida, realizamos una llamada al procedimiento algoritmoSustraccionFondo() definido en la clase FuncionesOpenCV, donde la estructura IplImage de entrada es copiada en la variable global imagenAnterior, que es otra imagen IplImage definida en la clase principal, y que será la encargada de ir guardando las imágenes sucesivamente anteriores a las imágenes que se van recibiendo. De esta forma, en la segunda imagen recibida, se clonarán dos estructuras IplImage a partir de la imagen actual y de la imagen anterior, almacenada previamente. Acto seguido, la imagen original es recorrida píxel a píxel, realizándose para cada dato correspondiente al valor de gris contenido en el píxel (número de canales igual a uno) la siguiente operación: Si: |DatoOrig[índice] – DatoAnt[índice]| >= sensibilidad Y Si: |DatoOrig[índice]| >= umbral Entonces: DatoSalida[índice] = 255 EnOtroCaso: DatoSalida[índice] = 0 ~ 91 ~ La máscara resultante visualizará en color blanco (255) el conjunto de píxeles (BLOBs) que se correspondan con el color especificado, y en negro (0) el resto de píxeles que no entren dentro de dicha clasificación. Finalmente, a la salida del método, y antes de convertir la imagen de nuevo de Mat a QPixmap, realizamos un filtro gaussiano utilizando la función GaussianBlur, con un tamaño de Kernel de valor 9, para suavizar la imagen de salida debido sobre todo a la existencia de ruido que puede haber en la imagen como consecuencia de las condiciones de luminosidad del entorno. 4.3.5.2 Diálogo BlobColorDialog En el diálogo de detección de BLOBs de color se permitirá seleccionar el color a detectar (rojo, azul y verde) utilizando el elemento QComboBox incluido en el mismo. Estos valores se almacenarán en una variable global llamada colorBlob que contendrá una cadena con el tipo de color existente actualmente en el ComboBox. Una vez en el procedimiento de detección, los píxeles serán filtrados en un rango de color determinado por el valor de esta variable. A continuación podemos apreciar algunas capturas del algoritmo en funcionamiento: Figura 44. Captura del algoritmo de BLOBs de color seleccionando la opción de tonos rojos ~ 98 ~ Figura 45. Captura del algoritmo de BLOBs de color seleccionando la opción de tonos azules 4.3.6 Implementación del método de detección de caras Finalmente, en este trabajo hemos incluido un método de detección de caras utilizando para ello el clasificador en cascada basado en características tipo Haar que ya explicamos al comienzo de este capítulo. Para lanzar la ejecución del método haremos clic en la última acción del menú Procesamiento de Video donde inicialmente aparece con el mensaje “Activar Detección de Caras”. A diferencia del resto del métodos, en este caso no existe un diálogo de parámetros de corrección ya que, si bien podríamos modificar algunos parámetros de la función detectMultiScale(), tales como el factor de escalado o el número mínimo de vecinos, hemos preferido establecer unos valores fijos con los que se obtiene una buena tasa de detección en relación y una minimización de falsos positivos. La creación de un diálogo que incremente por ejemplo el número de vecinos u otras técnicas que permitan reducir aún más la tasa de falsos positivos, queda pendiente para una posible ampliación de cara al futuro. Aunque también se plantea en este caso algún otro tipo de enfoque que permita no solo la detección, sino también el reconocimiento de patrones más complejos, o de detección de características más específicas en las ~ 99 ~ personas o en los objetos. En el capítulo dedicado a los trabajos futuros ahondaremos un poco más en esta cuestión. El método por tanto, se inicia en la aplicación directamente activando la acción del menú antes comentada. En ese momento, el Slot activarDeteccionCaras() es lanzado y cambia en primer lugar el texto de la acción del menú al mensaje “Desactivar Detección Caras”. Con este mecanismo, cuando se lance de nuevo la acción, se detectará que el método está activo, y por lo tanto volverá de nuevo a modificarse la acción con el texto original. Figura 46. Activando y desactivando el método de detección de caras 4.3.6.1 Descripción del método Previamente al lanzamiento del método detecciónCaras(), el cual está definido en la clase FuncionesOpenCV del paquete auxiliares, en el momento que activamos la detección de caras desde la acción de menú correspondiente, la clase principal (MainWindow), ya tiene inicializada una nueva variable global de tipo CascadeClassifier llamada faceCade, definida en el mismo momento en que se arranca la aplicación por primera vez. En esta inicialización se carga a través de la función load() un nuevo clasificador en cascada basado en características Haar a partir del fichero lbpcascade_frontalface.xml, que ya dispone de la información de un clasificador en cascada entrenado para la ~ 100 ~ detección de características Haar asociadas a las regiones en imágenes identificadas como “caras de personas”. Una vez cargado este clasificador, y la aplicación es iniciada, podemos entonces activar la detección de caras, permitiendo por tanto que se lance el método deteccionCaras() de la clase FuncionesOpenCV. Lo primero que hace este método es realizar una ecualización del histograma asociado a la imagen recibida desde la cámara en escala de grises. Esta operación, que como ya vimos se puede invocar haciendo uso de la función equalizeHist() del módulo imgProc de OpenCV, es importante de cara a evitar falsos positivos en la detección de caras debido ante todo a que la maximización que realiza sobre el contraste y a la normalización del brillo de la imagen en todos sus píxeles, hace que las características Haar, que son calculadas en base a la diferencia entre las sumas de intensidades de los píxeles de cada uno de sus regiones adyacentes, puedan ser más fácilmente detectadas y comparadas en las regiones de la imagen, por lo que la tasa de detección será mucho más eficiente. Previamente por tanto, habrá que convertir la imagen de entrada en escala de grises con la función cvtColor() de OpenCV. Tras ecualizar el histograma, la imagen resultante es pasada a la función detectMultiScale() con los siguientes valores en sus argumentos: <Arg1>: grayScale -> Imagen escala de grises ecualizada <Arg2>: faces -> Vector de ROIs con las detecciones <Arg3>: 1.1 -> Valor de factor de escalado <Arg4>: 3 -> Número de vecinos <Arg5>: CV_HAAR_SCALE_IMAGE -> Flag de escalado tipo HAAR <Arg4>: Size(30,30) -> Tamaño mínimo Los dos últimos argumentos hacen referencia por un lado a la heurística empleada para reducir el número de áreas analizadas, donde en este caso se utilizará una optimizada para la detección de características Haar (CV_HAAR_SCALE_IMAGE), aunque también se pueden utilizar otras funciones heurísticas tales como por ejemplo una poda Canny (CV_HAAR_DO_CANNY_PRUNING), basada en el algoritmo del mismo nombre. Por otro lado, el último argumento hace referencia al tamaño mínimo de objeto a analizar, por lo que nos abstendremos de analizar caras que en la imagen contengan menos de 900 píxeles cuadrados de área. ~ 101 ~ El segundo argumento (faces) es pasado como parámetro por referencia y en él, la función detectMultiScale() devuelve un vector de rectángulos (tipo Rect de OpenCV) con las regiones de interés (ROIs) de la imagen donde han existido coincidencias en la detección, es decir, devuelve las zonas de la imagen donde se han detectado “caras”. Para representar las detecciones sobre la imagen de salida, buscamos para ello el centro de cada uno de los rectángulos de la variable faces con la función center() y pasamos el mismo a la función ellipse() de OpenCV, la cual permitirá dibujar una forma circular con ese centro encerrada dentro del rectángulo. Figura 47. Detección de caras en la aplicación Control Camera IP Las funciones del módulo de dibujo de OpenCV no han sido explicadas en este trabajo, ya que la única que utilizaremos será la función ellipse() solo en este caso. No obstante, en el capítulo dedicado a los trabajos futuros, propondremos la utilización de algunas de estas funciones para mejorar la detección de los métodos desarrollados en este trabajo. ~ 102 ~ Capítulo 5 Conclusiones y Trabajos Futuros Con la elaboración de este Trabajo Fin de Grado hemos conseguido una mejora sustancial en la funcionalidad de la aplicación Control Cámara IP, introduciendo un conjunto de opciones en la interfaz gráfica que permiten aplicar algunas funciones de procesamiento sobre la imagen, incluyendo la detección de bordes y caras, así como la detección de objetos en movimiento gracias a un algoritmo de sustracción de fondo. La facilidad de integración de la biblioteca OpenCV en las distintas plataformas definidas en el proyecto Qt, ha permitido que estas nuevas funciones puedan ser utilizadas en dispositivos móviles con sistemas Android entre otros, produciendo unos resultados bastante satisfactorios. En este sentido, también ha sido de gran ayuda la facilidad de configuración de plataformas Android que ofrece ahora Qt en su nueva versión 5, liberándonos de la necesidad de utilizar versiones de Qt no oficiales, tales como Qt Necessitas for Android. Por último, también hemos conseguido en este trabajo encontrar una API estandarizada para la conexión de nuestra aplicación con cámaras de bajo coste de diversos fabricantes (Foscam, Conceptronic, HooToo, etc.), y se ha adaptado parte del código de la aplicación original, para poder utilizar algunas de las funciones básicas de las que este API dispone, sobre una cámara Conceptronic modelo Tilt & Pan Wireless, logrando por tanto incrementar en gran medida la capacidad de interconexión de nuestra aplicación con una gran variedad de cámaras existentes en el mercado. Gracias a los resultados obtenidos, podemos vislumbrar muchas posibilidades de cara a la mejora de la aplicación, como por ejemplo, la creación de sistemas de detección y reconocimiento de objetos más sofisticados, o de una solución integrada que permita utilizar las diferentes funciones de la aplicación en conjunción con sistemas empotrados en vehículos no tripulados, tales como drones o vehículos submarinos (UUV – Unmanned Underwater Vehicles), o en otro tipo de sistemas inteligentes de visión. A continuación, describiremos algunas de estas posibles mejoras que podrán ser aplicadas en un futuro para la ampliación de este Trabajo Fin de Grado. ~ 103 ~ 5.1 Mejoras en la detección de objetos en la imagen Los algoritmos de detección desarrollados en este trabajo haciendo uso de la biblioteca OpenCV, están realizados en base a procedimientos muy sencillos de tratamiento sobre la imagen, ya que la información que se obtiene de ellos solo implica la operación sobre una única característica de la imagen, como el color o la luminosidad de los píxeles (a excepción del método de detección de caras, que utiliza un conjunto de características Haar para buscar coincidencias en las zonas de la imagen). Sin embargo, en muchas ocasiones, es necesario para la detección de objetos de ciertas características determinadas, extraer otros elementos de información sobre la imagen, de forma que nos ofrezca la posibilidad de conjugar la combinación de todos los elementos para obtener una información más precisa sobre el objeto. Para no extendernos demasiado, propondremos por un lado la utilización del módulo Features2D de OpenCV para la detección de esquinas y de puntos característicos (key points) sobre la imagen, y por otro la inclusión de otros métodos de detección de BLOBs basados en la circularidad. 5.1.1 Detección de esquinas La idea de detección de características sobre la imagen (features detection), consiste básicamente en buscar coincidencias sobre frames extraídos del entorno, buscando zonas que son fácilmente identificables debido a que contienen características muy reconocibles, tales como esquinas, colores, luminosidad, etc. Las esquinas en una imagen son elementos que pueden aportar mucha información, ya que la mayoría de los objetos del mundo real están constituidos por zonas que, en una imagen digital sus pixeles experimentan un cambio brusco de gradiente (véase detección de bordes con el algoritmo Canny), sobre todo cuando dos de sus bordes confluyen en una esquina. ~ 104 ~ Figura 48. Aplicación de un algoritmo de detección de bordes sobre una imagen La detección de esquinas en imágenes suele ser utilizada por algunos métodos de detección de puntos característicos o puntos de interés (key points) sobre la imagen, normalmente invariables en caso de escalado de la imagen. 5.1.2 Blobs de circularidad Del mismo modo que se pueden detectar BLOBs de color en la imagen para detectar objetos que tienen un determinado color, también se pueden crear algoritmos que detecten otro tipo de BLOBs o conexiones de píxeles en las imágenes. Entre ellos podemos destacar los BLOBs de circularidad. La detección de circularidad consiste básicamente en saber cómo de “circular” es una región de una imagen, de forma que esta información pueda ser representada en la imagen de salida respondiendo a un cierto umbral, que usualmente suele estar determinado por la longitud de la región obtenida. La longitud de un BLOB es la distancia entre los dos píxeles del mismo más distantes entre sí. Así, la circularidad se define como el resultado de dividir el valor del área del BLOB, entre el área del círculo de diámetro la longitud del BLOB, que está definido dentro del mismo. Circularidad = (4 * AreaRegion) / (Pi * (longitud)^2) El resultado anterior, también llamado “factor de circularidad” puede ser aplicado en algún método similar al realizado en este trabajo para la detección de BLOBs de color, de forma que pueda representar en una imagen aquellas zonas o figuras que tengan una cierta circularidad. ~ 105 ~ 5.2 Mejoras en la detección de caras Se propone también en este capítulo la creación de un diálogo para la aplicación capaz de mejorar la detección de caras, modificando para ello los parámetros de corrección de la función detectMultiScale(), tales como el número de vecinos, o el heurístico de búsqueda de características Haar. Además también se sugiere el desarrollo o utilización de algún método existente de reconocimiento de caras, como por ejemplo la clase de reconocimiento de caras FaceRecognizer de OpenCV, incorporada a partir de su versión 2.4, y que dispone de una serie de funciones de detección basadas en eigenfaces y fisherfaces, utilizando fórmulas de transformación de vectores invariantes en transformaciones lineales (vectores eigen), o variaciones en la reflexión de la luz, para detectar rasgos característicos en las expresiones faciales. Existe un tutorial de OpenCV que puede ayudar a entender cómo funciona el reconocedor de caras, y poder utilizarlo así en un futuro en nuestra aplicación en conjunción con el método de detección ya implementado. 5.3 Integrar la aplicación en una solución para el análisis de información visual con cámaras instaladas en Drones El auge que cada vez más hoy día está habiendo en la utilización de vehículos aéreos no tripulados (drones), para la realización de tareas específicas relacionadas con la visión u otras áreas, en lugares donde el acceso a través de otros medios es complicado, hace que nos planteemos la posibilidad de integrar nuestra aplicación en un futuro, en algún tipo de solución que permita el análisis de la información visual capturada por este tipo de vehículos en movimiento. Figura 49. Dron con varios sensores entre los que se incluyen varias cámaras ~ 106 ~ En tal caso, podrían aplicarse todas las mejoras propuestas en los apartados anteriores, de forma que se pudiera extraer información variada del entorno donde el dron esté operando en ese momento, analizar dicha información, e incluso implementar mecanismos de control remotos que permitieran a la propia aplicación alertar al dron sobre elementos del entorno como obstáculos fijos, con el objetivo de poder evitarlos. 5.1.2 Técnicas de visión artificial para la navegación y análisis de información con drones Aprovechando la inclusión en este Trabajo Fin de Grado de capacidad de análisis y procesamiento de video a través de la biblioteca OpenCV, se podrían también añadir algunas técnicas de visión por computador para recoger la información visual de una o varias cámaras con conectividad IP instaladas en un dron, de forma que podamos realizar estimaciones de posicionamiento para la navegación y el análisis para la detección de elementos visuales en el entorno (como obstáculos por ejemplo). Muchas de estas técnicas están basadas en detectores de puntos de interés o key points. Detectores de key points y matching de características Los detectores de key points (más conocidos como features detectors), utilizan técnicas de detección en la variación de intensidad en los píxeles, entre las que se incluyen la detección de esquinas, para obtener un elevado número de puntos de interés en la imagen, que pueden ser comparados con otras imágenes para determinar coincidencias en las mismas. Algunos de estos algoritmos de detección de características más destacados son FAST, ORB, SIFT y SURF. Los dos primeros pertenecen a la librería Features2D de OpenCV, por lo que son de libre distribución. Sin embargo, los algoritmos SIFT y SURF están patentados, y por lo tanto su uso está más restringido (están ubicados en el módulo NonFree de OpenCV). Para el matching de características suele utilizarse la librería FLANN (Fast Library for Approximate Nearest Neighbors), que contiene un conjunto de algoritmos optimizados para la búsqueda de coincidencias en dos imágenes. Estas coincidencias podrán ayudar a obtener información precisa sobre ciertos entornos en tiempo real, o bien, en el caso de drones con cámaras incorporadas, se podrían aplicar técnicas de predicción entre frames consecutivos, pudiendo estimar la posición del dron en el espacio 3D, así como mapear los objetos en el espacio tridimensional (reconstrucción 3D). ~ 107 ~