Interfaz de control domótica basada en visión artificial
Abstract
El trabajo que se mostrará a continuación consistirá en una interfaz domótica basada en visión artificial con la cual se buscará facilitar la integración domótica a personas discapacitadas, pudiendo estas interactuar mediante gestos faciales con la vivienda. Para llevar a cabo este proyecto, se desarrollarán los códigos pertinentes que detecten los gestos faciales para posteriormente implementarlos en una vivienda virtual. Para ello, se utilizará el lenguaje de programación Python junto al software HOME I/O.
Full text
Equation Chapter 1 Section 1 Trabajo Fin de Grado Grado en Ingeniería de Tecnologías Industriales Interfaz de control domótica basada en visión artificial Autor: Ricardo Durán Viñuelas Tutores: Jose María Maestre Torreblanca Jesús Iván Maza Alcañiz Dpto. Ingeniería de Sistemas y Automática Escuela Técnica Superior de Ingeniería Universidad de Sevilla Sevilla, 2020
iii Trabajo Fin de Grado Grado en Ingeniería de Tecnologías Industriales Interfaz de control domótica basada en visión artificial Autor: Ricardo Durán Viñuelas Tutores: Jose María Maestre Torreblanca Profesor titular Jesús Iván Maza Alcañiz Profesor titular Dpto. de Ingeniría de Sistemas y Automática Escuela Técnica Superior de Ingeniería Universidad de Sevilla Sevilla, 2020
v Trabajo Fin de Grado: Interfaz de control domótica basada en visión artificial Autor: Ricardo Durán Viñuelas Tutore: Jose María Maestre Torreblanca Jesús Iván Maza Alcañiz El tribunal nombrado para juzgar el Proyecto arriba indicado, compuesto por los siguientes miembros: Presidente: Vocales: Secretario: Acuerdan otorgarle la calificación de: Sevilla, 2013 El Secretario del Tribunal
vii A mi familia A mis maestros
ix Agradecimientos Agradecer a Iván y a Pepe el tiempo que han dedicado en darme las indicaciones a seguir, así como la ayuda que me han brindado a lo largo de estos meses de trabajo. A mi familia y amigos, porque siempre me han acompañado y ayudado cuando los ánimos decaían. Y de igual forma, agradecer a todos los compañeros de la escuela y resto de profesores toda la dedicación aportada a lo largo de estos años de formación. Ha sido un placer ser parte de la escuela y participar en este trabajo. Ricardo Durán Viñuelas Sevilla, 2020
xvii ÍNDICE DE FIGURAS Figura 2-1. Propósitos de la domotica 4 Figura 3-1. Interfaz Home I/O 5 Figura 4-1. Puntos faciales 8 Figura 4-2. Reconocimiento de puntos faciales sobre el rostro 9 Figura 4-3. Detección abrir la boca 9 Figura 4-4. Detección levantar las cejas 10 Figura 5-1. Anaconda Prompt 12 Figura 5-2. Instalación OpenCV 12 Figura 5-3. Instalación Dlib 13 Figura 5-4. Contenido del archivo que se descarga de la web 13 Figura 5-5. Modos de los dispositivos 14 Figura 5-6. Mapa con las luces de la vivienda 15 Figura 5-7. Mapa con las persianas de la vivienda 16 Figura 5-8. Código funcionando 22
xix Notación TFG Enter Bool Trabajo Fin de Grado Tecla del teclado para entrar o ejecutar Dato tipo lógico o booleano : = Tal que Igual < <= Menor que Menor o igual que > >= Mayor que Mayor o igual que ⇔ fps Si y sólo si Frames por segundo
1 1 INTRODUCCIÓN l ser humano, en relación a la tecnología, está continuamente buscando la manera de superarse con el objetivo de avanzar hasta el punto de que estas puedan ayudar en sus propias necesidades. Gracias a los avances tecnológicos de hoy en día se cuentan con numerosas facilidades en el día a día de las personas que años atrás eran impensables, y, probablemente, dentro de unos años habrá otras tecnologías o avances que en la actualidad no son concebidos. 1.1 Motivaciones La domótica nos facilita ciertas acciones cotidianas dentro de nuestro hogar además de brindar a este de cierta inteligencia o seguridad. Encender las luces a distancia o que un motor se encargue de subir o bajar las persianas pueden hacer que la comodidad y productividad de los usuarios aumente. Pero no solo eso, y es que para personas discapacitadas o con dificultades en la movilidad estas acciones pueden ser de enorme importancia y la única forma de poder realizarlas por sí solas es gracias a estas aplicaciones de la domótica. Es por ello por lo que en este trabajo fin de grado se desea automatizar los procesos cotidianos del día a día en la vivienda a través de gestos faciales, como puede ser abrir la boca o parpadear varias veces, pensando en aquellas personas que tienen movilidad únicamente en la cara. Se tratará de hacer una interfaz general y a grandes rasgos, siendo lo ideal que a cada usuario se le haga una adaptación a sus características físicas o preferencias. 1.2 Planteamiento Para poder llevar a cabo este proyecto, se necesita hacer uso de la visión artificial. De acuerdo al blog de la empresa de automatización industrial Contaval, “La visión artificial es una disciplina científica que incluye métodos para adquirir, procesar y analizar imágenes del mundo real con el fin de producir información que pueda ser tratada por una máquina. La principal finalidad de la visión artificial es dotar a la máquina de “ojos” para ver lo que ocurre en el mundo real, y así poder tomar decisiones para automatizar cualquier proceso.” («¿Qué es la visión artificial y para qué sirve?», 2016) [1]. Por lo tanto, se pretende que el ordenador y los dispositivos domóticos, y haciendo uso de una webcam o una cámara, sean capaces de detectar y reconocer en la cara del usuario distintos gestos, para luego poder automatizar ciertas acciones a través de los mismos. Como lenguaje de programación se puede utilizar tanto C, como Matlab, Python o Java por poner algunos ejemplos. Pero, para llevar a cabo este proyecto, se ha tomado la decisión de utilizar Python como lenguaje principal de programación. Esta elección se debe a que en Python se pueden encontrar varias librerías dedicadas a la visión artificial que facilitarán la programación, además de ser un lenguaje cada vez más extendido en este y otros ámbitos. Debido a que no es del alcance del TFG, se tratarán de usar códigos de visión artificial ya creados por otras personas y de uso libre, o adaptaciones de los mismo a nuestras necesidades. Para las pruebas de los códigos se usará Anaconda debido a la facilidad que ofrece a la hora de instalar librerías o uso del programa, aunque de igual manera, se podría usar cualquier otro entorno. Una vez desarrollada la parte del reconocimiento de gestos, se implementarían dichos códigos en unos dispositivos domóticos. Sin embargo, y debido a la imposibilidad de disponer de estos, se usará un simulador de vivienda inteligente. Para ello, se hará uso del software HOME I/O, cuya licencia ha sido facilitada por los tutores de este trabajo. E
Introducción 2 1.3 Objetivos De acuerdo con lo mencionado en esta introducción, el objetivo es desarrollar, a grandes rasgos y sin llegar a especificar en casos concretos, una interfaz que permita la automatización de acciones en el hogar a partir de gestos faciales, facilitándole a las personas discapacitadas o con dificultades estas tareas. Por ejemplo, encender una luz parpadeando tres veces o abrir la persiana abriendo la boca. A su vez, se pretende abrir una vía de investigación para que posteriormente se pueda seguir mejorando y avanzando en esta tecnología, pudiéndose en un futuro usar de manera habitual y para cualquier persona en los hogares, facilitando así las acciones cotidianas.
3 2 LA DOMÓTICA n un primer lugar, es conveniente hacer una introducción a la domótica, ya que debido a ella tiene sentido este proyecto. En los últimos años la domótica está cobrando especial interés gracias a los nuevos avances a los que se están llegando, haciendo posible la implementación de las nuevas tecnologías en cualquier hogar de forma más sencilla, además de encontrando una oferta mejor y de mayor calidad, acorde a acualquier usuario final. 2.1 ¿Qué es la domótica? Accediendo a la RAE, se tiene que la palabra domótica está formada por la forma femenina del latín domus ‘casa’ y automática, y significa “Conjunto de sistemas que automatizan las diferentes instalaciones de una vivienda” [2]. Otros autores definen la domótica como la tecnología implementada en los hogares y que automatiza las funciones o acciones que se realizan en estos con el objetivo de aumentar la comodidad, la seguridad y el ahorro de energía, mejorando así el nivel de vida de los ocupantes de la vivienda. Estas funciones se conseguirían a través de dispositivos que pueden funcionar de manera independiente o conjunta. [3] En relación con esto último, en los primeros años estos dispositivos funcionaban de forma independiente, de modo que no era posible establecer interconexiones entre ellos. Hoy en día es posible automatizar el riego del jardín en función de si la luz está encendida o apagada, de forma que se riegue por la noche, por poner un ejemplo sencillo. Es por eso por lo que actualmente la domótica abarca un gran número de sistemas e interacciones entre ellos, siendo el propósito final el de tener todo el control de la vivienda únicamente haciendo uso de un dispositivo o aplicación. Sin embargo, actualmente, esto último sigue siendo difícil debido a la poca interoperabilidad entre distintas marcas o productos. El término inmótica hace referencia a la tecnología que se implementa en inmuebles de mayor envergadura como pueden ser los edificios u hoteles. Los dispositivos que se requieren en este caso suelen ser de mayores dimensiones que los utilizados en la vivienda. 2.2 Propósitos de la domótica De acuerdo al prunto anterior, la domótica debe de integrar las soluciones del hogar, proporcionando así una mayor calidad de vida, siendo este el objetivo del ser humano desde tiempos inmemoriables. Aún así, los propósitos de la domótica se pueden subdividir en: • La domótica aporta comodidad al usuario, haciendo del hogar un lugar más confortable y facilita las tareas repetitivas que se realizan en él incrementando así el bienestar. Gestiona los dispositivos y actividades domésticas como pueden ser las acciones de abrir, cerrar, encender, apagar o regular cada uno de los sistemas de la casa. • A su vez, ayuda a la gestión de la energía, favoreciendo un ahorro energético y económico. Esto se consigue regulando, programando y optimizando la energía y los dispositivos de nuestro hogar buscando así la eficiencia, por ejemplo, apagando los enchufes que no sean necesarios al salir de casa o programando el encendido de las luces solo cuando sea necesario. • Aportar seguridad a los usuarios, tanto como la propia seguridad como la de los bienes materiales del hogar, favoreciendo así la tranquilidad de estos ante incidencias o averías que puedan aparecer. El uso de cámaras de seguridad o detectores de fuga de gas o de inundación son algunos de los ejemplos de este ámbito. E
La Domótica 4 • Fomenta la accesibilidad, favoreciendo el manejo de los elementos del hogar a aquellas personas con dificultades, ya sea debido a las altas cargas de trabajo de la actividad en cuestión, o por motivos de lesiones o discapacidad de las personas, es decir, ayuda a las personas que así lo requieran. • Garantiza las comunicaciones mediante el control y supervisión remoto de la vivienda a través de su teléfono, PC..., permitiendo la recepción de avisos o incidencias e información del funcionamiento de equipos e instalaciones. Además, la instalación domótica permite el intercambio de información a través de ella, haciendo posible la transmisión de datos o imágenes entre distintos dispositivos, por ejemplo. [4] Figura 2-1. Propósitos de la domotica [4]
5 3 HOME I/O ebido a la imposibilidad de disponer de una casa inteligente o de dispositivos domóticos reales, no queda más remedio que hacer uso del software HOME I/O el cual es capaz de simular una casa inteligente en tiempo real. Gracias a este software, podemos controlar cualquier sistema domótico de los implementados en la vivienda representada en dicho software. 3.1 ¿Qué es HOME I/O? Home I/O es un software desarrollado por la empresa Real Games [5], dedicada al desarrollo de softwares de simulación. Factory I/O o ITS PLC completan algunos de los programas de esta empresa, la cual se encuentra extendida a lo largo de numerosos países y tiene la confianza de prestigiosas marcas a nivel mundial. En la pagina web de Home I/O podemos encontrar toda la información al respecto. Tal y como dice su web, ‘Home I/O es una simulación interactiva de una casa inteligente y el entorno circundante. Fue diseñado para cubrir una amplia gama de objetivos curriculares dentro de Ciencia, Tecnología, Ingeniería y Matemáticas (STEM). Con Home I/O, los estudiantes aprenderán sobre domótica, comportamiento térmico, eficiencia de consumo de energía y muchas otras materias que forman parte de la vida cotidiana.’ [6] siendo además ‘El objetivo principal de Home I/O es introducir conceptos de automatización del hogar utilizando una casa interactiva inteligente. Equipado con los dispositivos de automatización más comunes, Home I/O desafía a los estudiantes a diseñar soluciones de control y comprender el impacto de su implementación.’ [6]. Es por tanto, un software con fines educativos o para que los usuarios puedan recrear o similar ciertos aspectos de su vivienda. Figura 3-1. Interfaz Home I/O [6] En esa misma web anteriormente señalada, es posible descargar el programa el cual está disponible en una version gratuita de prueba, que consta de 30 días en la que se pueden usar todas las funciones, o comprando una licencia del producto. Los tutores de este trabajo han facilitado una licencia del programa, sin embargo, no ha sido necesaria el uso de ella ya que con la version de prueba del software ha sido posible realizar este trabajo al completo. D
12 Figura 5-1. Anaconda Prompt Una vez abierto Anaconda Prompt, se escriben lo siguientes comandos para instalar cada una de las librerías: • LibreríaOpenCV: Se escribe pip install opencv-python. Automáticamente comienza la descarga e instalación de la librería. Figura 5-2. Instalación OpenCV • Librería imutils: De igual forma, se escribe pip install imutils. • Librería Dlib: Para instalar esta librería basta con escribir conda install -c conda-forge dlib. En el caso que tuviéramos Python 3.7, a fecha de creación de este trabajo, sería necesario instalar Dlib de forma manual. Es por ello el motivo de usar una versión anterior de Python, para así poder instalar Dlib más fácilmente.
13 Interfaz de control domótica basada en visión artificial Figura 5-3. Instalación Dlib • Librería Pythonnet: Esta es necesaria para ejecutar el código que conecta con Home I/O. Para instalarla, basta con escribir pip install pythonnet. • Librería Engine IO: Por último, y también necesaria para usar Home I/O, se instala esta librería haciendo uso del comando pip install python-engineio. De esta forma, y llegados a este punto, se tendrán el entorno Anaconda y las librerías necesarias totalmente instaladas y listas para ejecutar los códigos. 5.3 Integración de Python con Home I/O De la página web de Home I/O, se tiene que ‘Home I/O se puede usar junto con Python 3. La integración de Python le permite escribir programas de Python para interactuar con dispositivos de E / S domésticos. Esto significa que puede leer y escribir en dispositivos de E / S desde programas Python.’ [12]. Para llevar a cabo esto, en esa misma web se puede descargar un archivo que incluye lo necesario para realizar este procedimiento. A su vez, viene un código de ejemplo en Python en el que se apaga y enciende una luz del salón 5 veces. El archivo que se descarga dispone de distintas carpetas, en función de la versión de Python que se vaya a utilizar. En mi caso, usaré los archivos correspondientes a Python 3.6. Figura 5-4. Contenido del archivo que se descarga de la web Es conveniente señalar que, en este aspecto, Real Games y Home I/O facilitan mucho el trabajo ya que en su web explcan todo a la perfección además de facilitar los archivos necesarios. Es por ello por lo que se recomienda leer la ayuda que se ofrece en la web.
14 5.4 Dispositivos Home I/O Antes de empezar a escribir el código sería conveniente presenter los distintos modos y dispositivos de los que consta la vivienda virtual para así poder interactuar con ellos correctamente. Como se viene diciendo a lo largo de este documento, toda la información se encuentra detallada en la web de ayuda de Real Games y Home I/O. [6] 5.4.1 Modos de los dispositivos Todos los dispositivos se pueden usar en tres modos diferentes: • Wired Mode: modo cableado (de color rojo). La casa no se encuentra automatizada, siendo la instalación eléctrica estándar. • Wireless Mode: modo inalámbrico (de color verde). Se utiliza con la consola de automatización del hogar pudiendose así programar para automatizar la casa. • External Mode: modo externo (de color azul). Permite acceder a los puntos de E / S de cada dispositivo con Connect I / O, a través del SDK o Python Figura 5-5. Modos de los dispositivos Por tanto, para hacer funcionar los dispositivos domóticos de la vivienda a través de Python es necesario que los dispositivos de la vivienda virtual sean puestos en modo externo. 5.4.2 Dispositivos En Home I/O hay disponibles un total de 174 dispositivos entre luces, interruptores de luz, persianas e interruptores de subida y bajada, calentadores y termostatos, distintos tipos de detectores y otros dispositivos como sirenas o la puerta del garaje. En este trabajo se tendrán en cuentas aquellos dispositivos que se consideran de uso imprescindible en una vivienda como pueden ser las luces o las persianas. Sin embargo, se podría realizar igualmente para automatizar la puerta del garaje, por ejemplo, sin ningún problema. De igual forma, se ha decidido interactuar con los dispositivos de forma Sí o No, por ejemplo con las luces, o encendidas o apagadas, a pesar de que el software permite la regulación de la intensidad de las mismas. Sin embargo, no se ha decidido hacer uso de ello ya que se considera que por el tipo de problema a resolver, controlar la intensidad de las luces no es del todo necesario o imprescindible. Es por ello que todos los datos sobre los que se actuan en Python son de tipo Bool, es decir, 0 o 1.
15 Interfaz de control domótica basada en visión artificial 5.4.2.1 Luces A continuación, se muestra un mapa con la posición de las luces de la vivienda, así como la dirección de memoria sobre las que hay que actuar en Python para poder tener el control de las mismas. Figura 5-6. Mapa con las luces de la vivienda [13] Siendo las direcciones de memoria de cada una de ellas las siguientes: Tabla 5-1. Direcciones de memoria de las luces [14] Nombre (Zona) Dirección Living Room (A) 0 Guests Restroom 1 (B) 19 Guests Restroom 2 (B) 20 Pantry (C) 30 Kitchen 1 (D) 40 Kitchen 2 (D) 41 Entrance Hall (E) Garage 1 (F) Garage 2 (F) Bedroom Corridor (G) Children Bedroom (H) Bathroom 1 (I) Bathroom 2 (I) Single Bedroom (J) Private Bathroom (K) Couple Bedroom (L) Laundry Room (M) Home Office 1 (N) Home Office 2 (N) 54 68 69 83 97 110 111 122 135 146 159 172 173
16 Home Office 1 (N) Exterior Porch 1 (O) Exterior Porch 2 (O) Exterior Pool (O) Exterior Garden (O) Exterior Entrance (O) 174 187 188 189 190 191 Se han escrito todas las direcciones de memoria de las luces ya que se usarán todas en el código. 5.4.2.2 Persianas De igual forma, se muestra el mapa de las persianas de la vivienda. En este caso, sin embargo, solo se harán uso de las persianas del salón ya que han sido las consideradas a tener en cuenta en el ejemplo que se está realizando. Si se quisieran utilizar otras persianas, bastaría con buscar las direcciones de memoria de cualquier otra persiana e incluirla al código. Y, de igual forma que se hizo con las luces, las direcciones de memoria de las persianas a usar (zona A): Tabla 5-2. Direcciones de memoria de las persianas [14] Nombre (zona) Dirección Roller Shades 1 Up (A) 1 Roller Shades 1 Down (A) 2 Roller Shades 2 Up (A) 3 Roller Shades 2 Down (A) 4 Roller Shades 3 Up (A) 5 Roller Shades 3 Down (A) 6 Roller Shades 4 Up (A) 7 Figura 5-7. Mapa con las persianas de la vivienda [13]
17 Interfaz de control domótica basada en visión artificial Roller Shades 4 Down (A) 8 En este caso, para cada persiana, hay dos direcciones, cada una de ellas correspondientes al motor de subida o de bajada de la persiana. 5.4.2.3 Otros dispositivos No se han tenido en cuenta en este trabajo otros dispositivos, sin embargo se podrían usar de igual manera. Por ejemplo, se podría leer la información de los sensores de las puertas para que el usuario, mediante un gesto, pudiera comprobar si todas las puertas de la vivienda están cerradas. O que se pudiera activar la alarma mediante alguna combinación de gestos si el usuario se encuentra en una situación de peligro. 5.5 Escribir el código Finalmente, y una vez introducido todo el proceso de instalación y la información acerca de los dispositivos a utilizar, bastaría con crear el código que controle los dispositivos domóticos de la vivienda virtual de Home I/O. Para ello, se utilizarán los códigos anteriormente presentados que detectan los gestos faciales. Sin embargo, estos códigos serán adaptados a las nuevas necesidades, como por ejemplo, que en vez de contar cuantas veces se parpadea, este se active cuando se parpadee 3 veces seguidas. Esto se debe a que anteriormente se presentaron los códigos de forma general y ahora se aprovecharán dichos códigos para nuestras necesidades. Además, añadir que a continuación se propondrá una alternativa de código a modo de ejemplo, sin embargo, este puede ser totalmente modificado y personalizado al gusto del usuario. 5.5.1 Código principal En este ejemplo, se propondrá un código con el que realizarán pequeñas tareas de la casa centradas en el salón, descritas a continuación: • Encender la luz del salón parpadenado 3 veces seguidas en un rango de 2 segundos. • Subir las cuatro persianas del salón abriendo la boca. Si mientras que se están subiendo las persianas abrimos de nuevo la boca, las persianas se quedarán paradas en el punto en el que se encuentren. • Bajar las cuatro persianas del salón levantando las cejas. Si mientras que se están bajando las persianas levantamos de nuevo las cejas, las persianas se quedarán paradas en el punto en el que se encuentren. • Apagar todas las luces de la vivienda manteniendo los ojos cerrados durante un segundo. Como se puede comprobar, la idea de este código es la de que el usuario tenga un control sobre los dispositivos del salón. La elección de esta parte de la casa se debe a que se ha supuesto que el salón es la zona más utilizada por el usuario. En caso, por ejemplo, de que el usuario no pueda salir de la cama y se encuentre siempre en su habitación pues se podría usar exactamente este código pero cambiando las direcciones de los dispositivos utilizados por las que fueran necesarias. El código completo se encuentra en el anexo de este documento, aunque aquí se explicarán las partes del mismo. En primer lugar, debemos importar todas las librerías necesarias: 1. import sys 2. import time 3. import clr 4. from scipy.spatial import distance as dist 5. from imutils.video import FileVideoStream 6. from imutils.video import VideoStream 7. from imutils import face_utils 8. import numpy as np 9. import imutils 10. import dlib
18 11. import cv2 12. 13. clr.AddReference('EngineIO') 14. 15. from EngineIO import * Alguna de ellas no se llegan a usar pero se han incluido porque son habituales en este tipo de códigos y quizás en una nueva actualización del código sean necesarias. Se definen las funciones que calculan la relación de aspecto, ya que gracias a este cálculo el código determinará cuando se ha producido un gesto: 16. def eye_aspect_ratio(eye): 17. # compute the euclidean distances between the two sets of 18. # vertical eye landmarks (x, y)-coordinates 19. A = dist.euclidean(eye[1], eye[5]) 20. B = dist.euclidean(eye[2], eye[4]) 21. 22. # compute the euclidean distance between the horizontal 23. # eye landmark (x, y)-coordinates 24. C = dist.euclidean(eye[0], eye[3]) 25. 26. # compute the eye aspect ratio 27. ear = (A + B) / (2.0 * C) 28. 29. # return the eye aspect ratio 30. return ear Esta función calcula la relación que hay entre la distancia vertical de los puntos del ojo y la distancia horizontal. De esta forma, esta relación se hará muy pequeña cuando la distancia vertical sea muy pequeña (cuando se cierren los ojos). Este mismo procedimiento se hace para detectar cuando se abre la boca pero al contrario, es decir, el código detectará que se ha abierto la boca cuando esta relación sea más grande de lo normal. Para detectar cuando se levantan las cejas se usa el mismo procedimiento, pero en este caso las relaciones se establecen entre los puntos de la ceja y los ojos. En el código incluido en el anexo se encuentran las otras dos funciones, que por simplicidad, aquí se han omitido ya que son similares. Posteriormente se deben definir las constantes que se deben usar en el código, las cuales corresponden a los valores de la relación de aspecto, así como los frames: 31. # define constants for the aspect ratio 32. EYE_AR_THRESH = 0.3 33. AR_CONSEC_FRAMES = 3 34. EYE_SECONDS_AR_CONSEC_FRAMES = 30 35. MOUTH_AR_THRESH = 0.6 36. EYEBROW_AR_THRESH = 0.6 Además de inicializar los contadores que serán usados: 37. # initialize the frame counters and the total number of open 38. COUNTER_EYE = 0 39. COUNTER_MOUTH = 0 40. COUNTER_EYEBROW = 0 41. TOTAL_EYE = 0 Se procede a inicializar el detector facial de Dlib, el cual detectará las caras en la imagen además de predecir las marcas faciales en las mismas. El archivo ‘shape_predictor_68_face_landmarks.dat’ es el archivo facilitado por la librería Dlib y el cual es el resultado de los procedimientos de inteligencia artificial resueltos por esta librería para poder obtener dichos puntos. Este archivo debe encontrarse en el mismo directorio donde se guarde el código de Python: 42. # initialize dlib's face detector (HOG-based) and then create
19 Interfaz de control domótica basada en visión artificial 43. # the facial landmark predictor 44. print("[INFO] loading facial landmark predictor...") 45. detector = dlib.get_frontal_face_detector() 46. predictor = dlib.shape_predictor('shape_predictor_68_face_landmarks.dat') Obtenemos la direcciones de los dispositivos de Home I/O: 47. #Recibo la dirección que quiero modificar en HOME I/O 48. # Luces zona A 49. livingRoomLight = MemoryMap.Instance.GetBit(0, MemoryType.Output) 50. # Luces zona B 51. GuestsRestroom1Light = MemoryMap.Instance.GetBit(19, MemoryType.Output) 52. GuestsRestroom2Light = MemoryMap.Instance.GetBit(20, MemoryType.Output) En el código del anexo aparece la obtención de todas las direcciones al completo, al igual que las direcciones de las persianas que se hacen de forma análoga. Guardamos los puntos de referencia de las zonas de la cara que interesan: 53. # grab the indexes of the facial landmarks for eyes, the mouth 54. # and the eyebrowns 55. (lStart, lEnd) = face_utils.FACIAL_LANDMARKS_IDXS["left_eye"] 56. (rStart, rEnd) = face_utils.FACIAL_LANDMARKS_IDXS["right_eye"] 57. (MStart, MEnd) = face_utils.FACIAL_LANDMARKS_IDXS["mouth"] 58. (lebStart, lebEnd) = face_utils.FACIAL_LANDMARKS_IDXS["left_eyebrow"] 59. (rebStart, rebEnd) = face_utils.FACIAL_LANDMARKS_IDXS["right_eyebrow"] La librería Dlib tiene descritos los puntos de cada parte de la cara, es por ello que escribiendo ‘mouth’, por ejemplos, obtenemos los puntos de la boca. Se pone en marcha la webcam. En caso de usar una cámara externa, se debería usar el código comentado: 60. # start the video stream thread 61. print("[INFO] starting video stream thread...") 62. #vs = VideoStream().start() 63. #fileStream = True 64. vs = VideoStream(src=0).start() 65. # vs = VideoStream(usePiCamera=True).start() 66. # fileStream = False Mientras que se esté usando la cámara, el código se mantendrá en este bucle. La webcam se lee frame a frame y se opera sobre cada uno de ellos: 67. # loop over frames from the video stream 68. while True: 69. # if this is a file video stream, then we need to check if 70. # there any more frames left in the buffer to process 71. #if fileStream and not vs.more(): 72. # break 73. 74. # grab the frame from the threaded video file stream, resize 75. # it, and convert it to grayscale 76. # channels) 77. frame = vs.read() 78. frame = imutils.resize(frame, width=450) 79. gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) En cada uno de dichos frames, se detectan los rostros gracias al detector antes definido de la librería Dlib: 80. # detect faces in the grayscale frame 81. rects = detector(gray, 0)
20 Y para cada uno de los rostros detectados, se hacen las operaciones que se encuentren dentro del siguiente bucle for. Es por ello, que si en la imagen aparecen dos personas, el código puede detectar los gestos de ambas personas. Para empezar, lo primero que se hace en este bucle for es detectar las marcas faciales de cada rostro encontrado en la imagen: 82. # loop over the face detections 83. for rect in rects: 84. # determine the facial landmarks for the face region, then 85. # convert the facial landmark (x, y)-coordinates to a NumPy 86. # array 87. shape = predictor(gray, rect) 88. shape = face_utils.shape_to_np(shape) Se establecen las coordenadas de cada punto que se necesita y, mediante las funciones arriba definidas, se calculan las relaciones de aspecto: 89. # extract the left and right eye coordinates, then use the 90. # coordinates to compute the eye aspect ratio for both eyes 91. leftEye = shape[lStart:lEnd] 92. rightEye = shape[rStart:rEnd] 93. leftEAR = eye_aspect_ratio(leftEye) 94. rightEAR = eye_aspect_ratio(rightEye) 95. # average the eye aspect ratio together for both eyes 96. ear = (leftEAR + rightEAR) / 2.0 De igual forma que antes, por simplicidad, aquí solo se ha escrito la parte correspondiente a los ojos. Para la boca y las cejas se haría de forma análoga. Se recuerda que el código completo aparece en el anexo de este documento. Se calcula el contorno de los ojos y se dibuja en cada frame del video que se mostrará por pantalla: 97. # compute the convex hull for the left and right eye, then 98. # visualize each of the eyes 99. leftEyeHull = cv2.convexHull(leftEye) 100. rightEyeHull = cv2.convexHull(rightEye) 101. cv2.drawContours(frame, [leftEyeHull], -1, (0, 255, 0), 1) 102. cv2.drawContours(frame, [rightEyeHull], -1, (0, 255, 0), 1) De forma similar se realizaría para la boca y cejas. Llegado a este punto, se comenzarían a calcular la detección de cada uno de los gestos. En primer lugar, se calculan los gestos de parpadear tres veces seguidas en un rango de dos segundos y mantener los ojos cerrados durante un segundo: 103. # Detección parpadear 104. # check to see if the eye aspect ratio is below the blink 105. # threshold, and if so, increment the blink frame counter 106. if ear < EYE_AR_THRESH: 107. COUNTER_EYE += 1 108. 109. # otherwise, the eye aspect ratio is not below the blink 110. # threshold 111. else: 112. # if the eyes were closed for a sufficient number of 113. # then increment the total number of blinks 114. if COUNTER_EYE >= AR_CONSEC_FRAMES and COUNTER_EYE <= EYE_SECONDS_AR _CONSEC_FRAMES: 115. TOTAL_EYE += 1 116. if TOTAL_EYE == 1: 117. tiempo_EYE = time.time() + 2 118. if TOTAL_EYE >= 3 and time.time() <= tiempo_EYE: 119. livingRoomLight.Value = not livingRoomLight.Value
21 Interfaz de control domótica basada en visión artificial 120. # When using a memory value before calling the Update method we are using a cached value. 121. print("Light is on? " + str(livingRoomLight.Value)) 122. TOTAL_EYE = 0 123. # Calling the Update method will write the livingRoomLight.V alue to the memory map. 124. MemoryMap.Instance.Update() 125. elif time.time() >= tiempo_EYE: 126. TOTAL_EYE = 1 127. tiempo_EYE = time.time() + 2 128. elif COUNTER_EYE >= EYE_SECONDS_AR_CONSEC_FRAMES: 129. # Se apagan todas las luces 130. livingRoomLight.Value = 0 131. GuestsRestroom1Light.Value = 0 132. GuestsRestroom2Light.Value = 0 133. # Se incluyen el resto de variables 134. # When using a memory value before calling the Update method we are using a cached value. 135. print("Light is on? " + str(livingRoomLight.Value)) 136. # Calling the Update method will write to the memory map. 137. MemoryMap.Instance.Update() 138. 139. 140. # reset the eye frame counter 141. COUNTER_EYE = 0 Cuando en un frame se detecta que la relación de aspecto es más pequeña que el valor de 0.3 propuesto, se cuenta un frame. Cuando este valor vuelve a aumentar, se comprueba durante cuantos frames ha ocurrido y si ha sido en al menos 3 frames consecutivos y durante menos de 30 frames (que se corresponde a un segundo, ya que la webcam graba a 30 fps), se detecta que el usuario ha parpadeado. Si en los próximos 2 segundos, se detecta que el usuario ha parpadeado 3 veces, el código detecta el gesto y cambia el valor que tenga la variable de la luz del salón. Si la luz estaba apagada, la enciende, y si estaba encendida, la apaga. Es necesario actualizar las variables para que Home I/O reconozca este cambio, acción que se realiza en la línea número 124. Por el contrario, si el código detecta que se ha tenido los ojos cerrados durante 30 frames o más, apaga todas las luces de la casa poniendo todas las variables a 0. En el código completo aparecen el resto de variables que aquí se han omitido. La detección de los gestos de abrir la boca y levantar las cejas se realiza de forma similar y análoga a este procedimiento. Ya llegando al final del código, se muestra por pantalla el video y se establece la forma de apagar la cámara y salir del bucle while: 142. # show the frame 143. cv2.imshow("Frame", frame) 144. key = cv2.waitKey(1) & 0xFF 145. 146. # if the `q` key was pressed, break from the loop 147. if key == ord("q"): 148. break Y para concluir, se cierran corecctamente todos los procesos abiertos: 149. # When we no longer need the MemoryMap we should call the Dispose method to rele ase all the allocated resources. 150. MemoryMap.Instance.Dispose() 151. 152. print("Bye!") 153. 154. # do a bit of cleanup 155. cv2.destroyAllWindows() 156. vs.stop()
28 7 ANEXOS 7.1 Código principal 1. import sys 2. import time 3. import clr 4. from scipy.spatial import distance as dist 5. from imutils.video import FileVideoStream 6. from imutils.video import VideoStream 7. from imutils import face_utils 8. import numpy as np 9. import argparse 10. import imutils 11. import dlib 12. import cv2 13. 14. clr.AddReference('EngineIO') 15. 16. from EngineIO import * 17. 18. def eye_aspect_ratio(eye): 19. # compute the euclidean distances between the two sets of 20. # vertical eye landmarks (x, y)-coordinates 21. A = dist.euclidean(eye[1], eye[5]) 22. B = dist.euclidean(eye[2], eye[4]) 23. 24. # compute the euclidean distance between the horizontal 25. # eye landmark (x, y)-coordinates 26. C = dist.euclidean(eye[0], eye[3]) 27. 28. # compute the eye aspect ratio 29. ear = (A + B) / (2.0 * C) 30. 31. # return the eye aspect ratio 32. return ear 33. 34. def mouth_aspect_ratio(mouth): 35. # compute the euclidean distances between the two sets of 36. # vertical mouth landmarks (x, y)-coordinates 37. A = dist.euclidean(mouth[13], mouth[19]) 38. B = dist.euclidean(mouth[14], mouth[18]) 39. C = dist.euclidean(mouth[15], mouth[17]) 40. 41. # compute the euclidean distance between the horizontal 42. # mouth landmark (x, y)-coordinates 43. D = dist.euclidean(mouth[12], mouth[16]) 44. 45. # compute the mouth aspect ratio 46. mar = (A + B + C) / (2.0 * D) 47. 48. # return the mouth aspect ratio 49. return mar 50. 51. def eyebrow_aspect_ratio(eye,eyebrow): 52. # compute the euclidean distances between the two sets of 53. # vertical eyebrow and eyes landmarks (x, y)-coordinates 54. A = dist.euclidean(eyebrow[1], eye[0]) 55. B = dist.euclidean(eyebrow[2], eye[3])
29 Interfaz de control domótica basada en visión artificial 56. C = dist.euclidean(eyebrow[3], eye[4]) 57. 58. # compute the euclidean distance between the horizontal 59. # eyebrow landmark (x, y)-coordinates 60. D = dist.euclidean(eyebrow[0], eyebrow[4]) 61. 62. # compute the eye aspect ratio 63. ebar = (A + B + C) / (3.0 * D) 64. 65. # return the eyebrown aspect ratio 66. return ebar 67. 68. # define constants for the aspect ratio 69. EYE_AR_THRESH = 0.3 70. AR_CONSEC_FRAMES = 3 71. EYE_SECONDS_AR_CONSEC_FRAMES = 30 72. MOUTH_AR_THRESH = 0.6 73. EYEBROW_AR_THRESH = 0.6 74. 75. # initialize the frame counters and the total number of open 76. COUNTER_EYE = 0 77. COUNTER_MOUTH = 0 78. COUNTER_EYEBROW = 0 79. TOTAL_EYE = 0 80. 81. # initialize dlib's face detector (HOG-based) and then create 82. # the facial landmark predictor 83. print("[INFO] loading facial landmark predictor...") 84. detector = dlib.get_frontal_face_detector() 85. predictor = dlib.shape_predictor('shape_predictor_68_face_landmarks.dat') 86. 87. #Recibo la dirección que quiero modificar en HOME I/O 88. # Luces zona A 89. livingRoomLight = MemoryMap.Instance.GetBit(0, MemoryType.Output) 90. # Luces zona B 91. GuestsRestroom1Light = MemoryMap.Instance.GetBit(19, MemoryType.Output) 92. GuestsRestroom2Light = MemoryMap.Instance.GetBit(20, MemoryType.Output) 93. # Luces zona C 94. PantryLight = MemoryMap.Instance.GetBit(30, MemoryType.Output) 95. # Luces zona D 96. Kitchen1Light = MemoryMap.Instance.GetBit(40, MemoryType.Output) 97. Kitchen2Light = MemoryMap.Instance.GetBit(41, MemoryType.Output) 98. # Luces zona E 99. EntranceHallLight = MemoryMap.Instance.GetBit(54, MemoryType.Output) 100. # Luces zona F 101. Garage1Light = MemoryMap.Instance.GetBit(68, MemoryType.Output) 102. Garage2Light = MemoryMap.Instance.GetBit(69, MemoryType.Output) 103. # Luces zona G 104. BedroomCorridorLight = MemoryMap.Instance.GetBit(83, MemoryType.Output) 105. # Luces zona H 106. ChildrenBedroomLight = MemoryMap.Instance.GetBit(97, MemoryType.Output) 107. # Luces zona I 108. Bathroom1Light = MemoryMap.Instance.GetBit(110, MemoryType.Output) 109. Bathroom2Light = MemoryMap.Instance.GetBit(111, MemoryType.Output) 110. # Luces zona J 111. SingleBedroomLight = MemoryMap.Instance.GetBit(122, MemoryType.Output) 112. # Luces zona K 113. PrivateBathroomLight = MemoryMap.Instance.GetBit(135, MemoryType.Output) 114. # Luces zona L 115. CoupleBedroomLight = MemoryMap.Instance.GetBit(146, MemoryType.Output) 116. # Luces zona M 117. LaundryRoomLight = MemoryMap.Instance.GetBit(159, MemoryType.Output) 118. # Luces zona N 119. HomeOffice1Light = MemoryMap.Instance.GetBit(172, MemoryType.Output) 120. HomeOffice2Light = MemoryMap.Instance.GetBit(173, MemoryType.Output) 121. HomeOffice3Light = MemoryMap.Instance.GetBit(174, MemoryType.Output) 122. # Luces zona O
30 123. ExteriorPorch1Light = MemoryMap.Instance.GetBit(187, MemoryType.Output) 124. ExteriorPorch2Light = MemoryMap.Instance.GetBit(188, MemoryType.Output) 125. ExteriorPoolLight = MemoryMap.Instance.GetBit(189, MemoryType.Output) 126. ExteriorGardenLight = MemoryMap.Instance.GetBit(190, MemoryType.Output) 127. ExteriorEntranceLight = MemoryMap.Instance.GetBit(191, MemoryType.Output) 128. 129. # Persianas zona A 130. livingRoomRollerShades1Up = MemoryMap.Instance.GetBit(1, MemoryType.Output) 131. livingRoomRollerShades1Down = MemoryMap.Instance.GetBit(2, MemoryType.Output) 132. livingRoomRollerShades2Up = MemoryMap.Instance.GetBit(3, MemoryType.Output) 133. livingRoomRollerShades2Down = MemoryMap.Instance.GetBit(4, MemoryType.Output) 134. livingRoomRollerShades3Up = MemoryMap.Instance.GetBit(5, MemoryType.Output) 135. livingRoomRollerShades3Down = MemoryMap.Instance.GetBit(6, MemoryType.Output) 136. livingRoomRollerShades4Up = MemoryMap.Instance.GetBit(7, MemoryType.Output) 137. livingRoomRollerShades4Down = MemoryMap.Instance.GetBit(8, MemoryType.Output) 138. 139. # grab the indexes of the facial landmarks for eyes, the mouth 140. # and the eyebrowns 141. (lStart, lEnd) = face_utils.FACIAL_LANDMARKS_IDXS["left_eye"] 142. (rStart, rEnd) = face_utils.FACIAL_LANDMARKS_IDXS["right_eye"] 143. (MStart, MEnd) = face_utils.FACIAL_LANDMARKS_IDXS["mouth"] 144. (lebStart, lebEnd) = face_utils.FACIAL_LANDMARKS_IDXS["left_eyebrow"] 145. (rebStart, rebEnd) = face_utils.FACIAL_LANDMARKS_IDXS["right_eyebrow"] 146. 147. 148. # start the video stream thread 149. print("[INFO] starting video stream thread...") 150. #vs = VideoStream().start() 151. #fileStream = True 152. vs = VideoStream(src=0).start() 153. # vs = VideoStream(usePiCamera=True).start() 154. # fileStream = False 155. time.sleep(1.0) 156. 157. # loop over frames from the video stream 158. while True: 159. # if this is a file video stream, then we need to check if 160. # there any more frames left in the buffer to process 161. #if fileStream and not vs.more(): 162. # break 163. 164. # grab the frame from the threaded video file stream, resize 165. # it, and convert it to grayscale 166. # channels) 167. frame = vs.read() 168. frame = imutils.resize(frame, width=450) 169. gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) 170. 171. # detect faces in the grayscale frame 172. rects = detector(gray, 0) 173. 174. # loop over the face detections 175. for rect in rects: 176. # determine the facial landmarks for the face region, then 177. # convert the facial landmark (x, y)-coordinates to a NumPy 178. # array 179. shape = predictor(gray, rect) 180. shape = face_utils.shape_to_np(shape) 181. 182. # extract the left and right eye coordinates, then use the 183. # coordinates to compute the eye aspect ratio for both eyes 184. leftEye = shape[lStart:lEnd] 185. rightEye = shape[rStart:rEnd] 186. leftEAR = eye_aspect_ratio(leftEye) 187. rightEAR = eye_aspect_ratio(rightEye) 188.
31 Interfaz de control domótica basada en visión artificial 189. # extract the mouth coordinates, then use the 190. # coordinates to compute the mouth aspect ratio 191. Mouth = shape[MStart:MEnd] 192. MAR = mouth_aspect_ratio(Mouth) 193. 194. # extract the left and right eye and eyebrow coordinates, then use the 195. # coordinates to compute the eyebrow aspect ratio for both eyebrows 196. leftEyebrow = shape[lebStart:lebEnd] 197. rightEyebrow = shape[rebStart:rebEnd] 198. leftEBAR = eyebrow_aspect_ratio(leftEye, leftEyebrow) 199. rightEBAR = eyebrow_aspect_ratio(rightEye, rightEyebrow) 200. 201. # average the eye aspect ratio together for both eyes 202. ear = (leftEAR + rightEAR) / 2.0 203. 204. # average the mouth aspect ratio 205. mar = MAR 206. 207. # average the eyebrow aspect ratio together for both eyebrows 208. ebar = (leftEBAR + rightEBAR) / 2.0 209. 210. # compute the convex hull for the left and right eye, then 211. # visualize each of the eyes 212. leftEyeHull = cv2.convexHull(leftEye) 213. rightEyeHull = cv2.convexHull(rightEye) 214. cv2.drawContours(frame, [leftEyeHull], -1, (0, 255, 0), 1) 215. cv2.drawContours(frame, [rightEyeHull], -1, (0, 255, 0), 1) 216. 217. # compute the convex hull for the mouth, then 218. # visualize 219. MouthHull = cv2.convexHull(Mouth) 220. cv2.drawContours(frame, [MouthHull], -1, (0, 255, 0), 1) 221. 222. # compute the convex hull for the left and right eyebrow, then 223. # visualize each of the eyebrows 224. leftEyebrowHull = cv2.convexHull(leftEyebrow) 225. rightEyebrowHull = cv2.convexHull(rightEyebrow) 226. cv2.drawContours(frame, [leftEyebrowHull], -1, (0, 255, 0), 1) 227. cv2.drawContours(frame, [rightEyebrowHull], -1, (0, 255, 0), 1) 228. 229. # Detección parpadear 230. # check to see if the eye aspect ratio is below the blink 231. # threshold, and if so, increment the blink frame counter 232. if ear < EYE_AR_THRESH: 233. COUNTER_EYE += 1 234. 235. # otherwise, the eye aspect ratio is not below the blink 236. # threshold 237. else: 238. # if the eyes were closed for a sufficient number of 239. # then increment the total number of blinks 240. if COUNTER_EYE >= AR_CONSEC_FRAMES and COUNTER_EYE <= EYE_SECONDS_AR _CONSEC_FRAMES: 241. TOTAL_EYE += 1 242. if TOTAL_EYE == 1: 243. tiempo_EYE = time.time() + 2 244. if TOTAL_EYE >= 3 and time.time() <= tiempo_EYE: 245. livingRoomLight.Value = not livingRoomLight.Value 246. # When using a memory value before calling the Update method we are using a cached value. 247. print("Light is on? " + str(livingRoomLight.Value)) 248. TOTAL_EYE = 0 249. # Calling the Update method will write the livingRoomLight.V alue to the memory map. 250. MemoryMap.Instance.Update() 251. elif time.time() >= tiempo_EYE: 252. TOTAL_EYE = 1
32 253. tiempo_EYE = time.time() + 2 254. elif COUNTER_EYE >= EYE_SECONDS_AR_CONSEC_FRAMES: 255. # Se apagan todas las luces 256. livingRoomLight.Value = 0 257. GuestsRestroom1Light.Value = 0 258. GuestsRestroom2Light.Value = 0 259. PantryLight.Value = 0 260. Kitchen1Light.Value = 0 261. Kitchen2Light.Value = 0 262. EntranceHallLight.Value = 0 263. Garage1Light.Value = 0 264. Garage2Light.Value = 0 265. BedroomCorridorLight.Value = 0 266. ChildrenBedroomLight.Value = 0 267. Bathroom1Light.Value = 0 268. Bathroom2Light.Value = 0 269. SingleBedroomLight.Value = 0 270. PrivateBathroomLight.Value = 0 271. CoupleBedroomLight.Value = 0 272. LaundryRoomLight.Value = 0 273. HomeOffice1Light.Value = 0 274. HomeOffice2Light.Value = 0 275. HomeOffice3Light.Value = 0 276. ExteriorPorch1Light.Value = 0 277. ExteriorPorch2Light.Value = 0 278. ExteriorPoolLight.Value = 0 279. ExteriorGardenLight.Value = 0 280. ExteriorEntranceLight.Value = 0 281. 282. # When using a memory value before calling the Update method we are using a cached value. 283. print("Light is on? " + str(livingRoomLight.Value)) 284. # Calling the Update method will write the livingRoomLight.Value to the memory map. 285. MemoryMap.Instance.Update() 286. 287. 288. # reset the eye frame counter 289. COUNTER_EYE = 0 290. 291. # check to see if the mouth aspect ratio is below the open 292. # threshold, and if so, increment the open frame counter 293. if mar > MOUTH_AR_THRESH: 294. COUNTER_MOUTH += 1 295. 296. # otherwise, the mouth aspect ratio is not below the open 297. # threshold 298. else: 299. # if the mouth were opened for a sufficient number of 300. # then increment the total number of open 301. if COUNTER_MOUTH >= AR_CONSEC_FRAMES: 302. livingRoomRollerShades1Up.Value = not livingRoomRollerShades1Up. Value 303. livingRoomRollerShades2Up.Value = not livingRoomRollerShades2Up. Value 304. livingRoomRollerShades3Up.Value = not livingRoomRollerShades3Up. Value 305. livingRoomRollerShades4Up.Value = not livingRoomRollerShades4Up. Value 306. livingRoomRollerShades1Down.Value = 0 307. livingRoomRollerShades2Down.Value = 0 308. livingRoomRollerShades3Down.Value = 0 309. livingRoomRollerShades4Down.Value = 0 310. 311. # Calling the Update method will write to the memory map.
33 Interfaz de control domótica basada en visión artificial 312. MemoryMap.Instance.Update() 313. 314. # reset the mouth frame counter 315. COUNTER_MOUTH = 0 316. 317. # check to see if the eyebrow aspect ratio is below the open 318. # threshold, and if so, increment the open frame counter 319. if ebar > EYEBROW_AR_THRESH and ear > EYE_AR_THRESH: 320. COUNTER_EYEBROW += 1 321. 322. # otherwise, the eyebrow aspect ratio is not below the open 323. # threshold 324. else: 325. # if the eyebrow were uped for a sufficient number of 326. # then increment the total number of open 327. if COUNTER_EYEBROW >= AR_CONSEC_FRAMES: 328. livingRoomRollerShades1Down.Value = not livingRoomRollerShades1D own.Value 329. livingRoomRollerShades2Down.Value = not livingRoomRollerShades2D own.Value 330. livingRoomRollerShades3Down.Value = not livingRoomRollerShades3D own.Value 331. livingRoomRollerShades4Down.Value = not livingRoomRollerShades4D own.Value 332. livingRoomRollerShades1Up.Value = 0 333. livingRoomRollerShades2Up.Value = 0 334. livingRoomRollerShades3Up.Value = 0 335. livingRoomRollerShades4Up.Value = 0 336. 337. # Calling the Update method will write to the memory map. 338. MemoryMap.Instance.Update() 339. 340. # reset the eyebrow frame counter 341. COUNTER_EYEBROW = 0 342. 343. 344. # show the frame 345. cv2.imshow("Frame", frame) 346. key = cv2.waitKey(1) & 0xFF 347. 348. # if the `q` key was pressed, break from the loop 349. if key == ord("q"): 350. break 351. 352. # When we no longer need the MemoryMap we should call the Dispose method to rele ase all the allocated resources. 353. MemoryMap.Instance.Dispose() 354. 355. print("Bye!") 356. 357. # do a bit of cleanup 358. cv2.destroyAllWindows() 359. vs.stop()
34
35 Interfaz de control domótica basada en visión artificial GLOSARIO Python: lenguaje de programación 1 Anaconda: Python: lenguaje de programación 1 Home I/O: software de im simulador de vivienda inteligente 1 Real Games: empresa desarrolladora del software Home I/O 5 STEM: Science, Technology, Engineering and Mathematics 5 PLC: controlador lógico programable 6 Modbus: protocolo de comunicaciones 6 Tracking: seguimiento 8 Conda: gestor de paquetes 11 Pip: gestor de paquetes 11