Está en la página 1de 89

UNIVERSIDAD NACIONAL DEL CENTRO DE LA PROVINCIA DE BUENOS AIRES

Diseño e implementación
de aplicaciones interactivas
para exposiciones y paseos
Proyecto de tesis de grado de la carrera Ingeniería en Sistemas

Alumna: Solange Marquez Figueroa


mfsolange@gmail.com

Director: Dr. Cristian García Bauza

Mayo de 2016
Tabla de contenido
Tabla de contenido ........................................................................................................... 1
Índice de figuras ............................................................................................................ 2
Índice de diagramas...................................................................................................... 4
Índice de code snippets ................................................................................................ 5
Agradecimientos ............................................................................................................... 6
Resumen........................................................................................................................... 7
Capítulo 1 Introducción .................................................................................................... 8
1.1 Motivación ............................................................................................................... 9
1.2 Solución propuesta ................................................................................................. 9
1.3 Organización del informe ...................................................................................... 10
Capítulo 2 Interactividad ................................................................................................. 12
2.1 Evolución de la Interfaz de usuario ...................................................................... 12
2.1.1 Kinect.............................................................................................................. 15
2.2 Interactividad en paseos y museos ...................................................................... 19
2.3 Tecnologías utilizadas .......................................................................................... 24
Capítulo 3 Diseño e Implementación ............................................................................. 25
3.1 Arquitectura propuesta ......................................................................................... 25
3.1.1 Controlador..................................................................................................... 25
3.1.2 Modelo ............................................................................................................ 35
3.1.3 Vista................................................................................................................ 38
3.2 Diseño de cada aplicación .................................................................................... 41
3.2.1 Reproductor de video ..................................................................................... 41
3.2.1.1 Reproducción normal y hacia atrás ........................................................ 43
3.2.1.1 Reproducción cámara lenta y acelerada ................................................ 49
3.2.1.3 Unificación de estados de reproducción ................................................. 50
3.2.2 Hinchada ........................................................................................................ 55
3.2.2.1 Reproducción de un sonido .................................................................... 57
3.2.2.2 Reproducción múltiple ............................................................................. 58
3.2.2.3 Reproducción dinámica ........................................................................... 61
3.2.2.4 Carga de sonidos .................................................................................... 64
3.2.2.5 Interfaz gráfica ......................................................................................... 64
3.2.3 Descubrir la imagen ....................................................................................... 69
3.2.3.1 Descubrimiento sin memoria................................................................... 70
3.2.3.2 Descubrimiento con memoria ................................................................. 73

1
3.2.3.3 Recubrimiento de la imagen ................................................................... 74
Capítulo 4 Pruebas ......................................................................................................... 76
4.1 Contexto ................................................................................................................ 76
4.2 Aplicaciones .......................................................................................................... 77
4.2.1 Reproductor de video ..................................................................................... 77
4.2.2 Hinchada ........................................................................................................ 79
4.2.3 Descubrir la imagen ....................................................................................... 80
Capítulo 5 Conclusiones ................................................................................................ 83
5.1 Resultados obtenidos ........................................................................................... 83
5.2 Trabajos futuros .................................................................................................... 84
Referencias ..................................................................................................................... 86

Índice de figuras

Figura 2.1 - Evolución de las interfaces de usuario. ............................................................. 12


Figura 2.2 - Interfaces de usuario (CLI, GUI y NUI respectivamente) .................................... 13
Figura 2.3 - Dispositivo WiiMote ......................................................................................... 14
Figura 2.4 - Dispositivo Leap Motion ................................................................................... 14
Figura 2.5 - Dispositivo Kinect ............................................................................................ 15
Figura 2.6 - Componentes del dispositivo Kinect ................................................................. 15
Figura 2.7 - Rango de inclinación ....................................................................................... 16
Figura 2.8 - Arreglo de micrófonos del dispositivo Kinect marcados en violeta. ...................... 17
Figura 2.9 - Frames de profundidad. ................................................................................... 17
Figura 2.10 - Frames de esqueletos. .................................................................................. 18
Figura 2.11 - Veinte articulaciones rastreadas en un esqueleto. ........................................... 18
Figura 2.12 - Interacción en el Museo de Louvre con el uso de Nintendo 3DS y códigos QR. . 20
Figura 2.13 - Juego en Museon con la utilización de PuppyIR. ............................................. 20
Figura 2.14 - Live Projection Mapping - EVA 2013 ............................................................... 21
Figura 2.15 - Pisos interactivos en eventos. ........................................................................ 21
Figura 2.16 - „Play Work Build‟ en el National Building Museum. ........................................... 22
Figura 2.17 - „Strike a pose‟ en Cleveland Museum of Art. ................................................... 22
Figura 2.18 - Juego interactivo relacionado al Básquet en Chicago Sports Museum. ............. 23
Figura 2.19 - Avatares en Sedena. ..................................................................................... 23
Figura 3.1 - Interacción del dispositivo Kinect con la aplicación a través del Kinect SDK ........ 26
Figura 3.2 - Secuencia de llamados para la inicialización ..................................................... 30
Figura 3.3 - Secuencia de llamados para terminar la aplicación. ........................................... 30

2
Figura 3.4 - Secuencia de llamados para la actualización del modelo. .................................. 31
Figura 3.5 - Comunicación necesaria entre el controlador y gestor de Kinect......................... 31
Figura 3.6 - Transformación de los datos por el método getTotalSkeletons. .......................... 32
Figura 3.7 - Diferentes estados de rastreo: PositionOnly (izquierda) y Tracked (derecha) ....... 32
Figura 3.8 - Transformación de los datos por el método isSkeletonAvailable. ........................ 33
Figura 3.9 - Transformación de los datos por el método getFirstSkeletonPosition. ................. 33
Figura 3.10 - Espacio del esqueleto (izquierda) comparado con los valores de profundidad
(derecha). ........................................................................................................ 33
Figura 3.11 - Transformación de los datos por el método getSkeletonPositions. .................... 34
Figura 3.12 - Transformación de los datos por el método getPlayersId. ................................. 34
Figura 3.13 - Transformación de los datos por el método isPlayerOnPixel. ............................ 34
Figura 3.14 - Comunicación entre los componentes del sistema. .......................................... 36
Figura 3.15 - Posibles usos de los datos por el modelo ........................................................ 37
Figura 3.16 - Comunicación necesaria entre la vista y el modelo. ......................................... 38
Figura 3.17 - Secuencia de llamados para la inicialización ................................................... 39
Figura 3.18 - Secuencia de llamados para la actualización de la vista. .................................. 39
Figura 3.19 - Secuencia de llamados para terminar la aplicación. ......................................... 40
Figura 3.20 - Idea básica sobre el funcionamiento del Reproductor de Video ........................ 42
Figura 3.21 - Acción de los movimientos ............................................................................. 42
Figura 3.22 - Etapa 0 - Modos de reproducción de video de normal a hacia atrás. ................. 43
Figura 3.23 - Modo de reproducción normal. ....................................................................... 44
Figura 3.24 - Flujo de actividad para la reproducción del video con control de movimiento. .... 47
Figura 3.25 - Modo de reproducción hacia atrás .................................................................. 48
Figura 3.26 - Etapa 1 - Modos de reproducción de video...................................................... 49
Figura 3.27 - Modo de reproducción acelerado. ................................................................... 50
Figura 3.28 - Intensidad de sonidos de acuerdo a la cantidad de personas y sus
movimientos. .................................................................................................... 56
Figura 3.29 - Parte visual de la aplicación Hinchada. ........................................................... 56
Figura 3.30 - Reproducción sin fin de un audio. ................................................................... 57
Figura 3.31 - Reproducción sin fin de múltiples audios. ........................................................ 58
Figura 3.32 - Secuencia de llamados para gestionar audios. ................................................ 60
Figura 3.33 - Representación de sonidos reproducidos en verde, y no reproducidos en rojo.
Variación en crecimiento de sonidos a reproducir................................................ 63
Figura 3.34 - Representación de sonidos reproducidos en verde, y no reproducidos en rojo.
Variación en disminución de sonidos a reproducir. .............................................. 63
Figura 3.35 - Representación de sonidos reproducidos en verde, y no reproducidos en rojo.
Sin variación de sonidos a reproducir. ................................................................ 64

3
Figura 3.36 - Establecimiento de colores con respecto a los identificadores de los jugadores. 67
Figura 3.37 - Idea básica sobre el funcionamiento de „Descubrir la imagen‟ .......................... 69
Figura 3.38 - Establecimiento de transparencias con respecto a la existencia de los
jugadores. ........................................................................................................ 73
Figura 3.39 - Establecimiento de niveles transparencias con respecto a la existencia de los
jugadores. ........................................................................................................ 74
Figura 4.1 - Contexto de las pruebas realizadas. ................................................................. 76
Figura 4.2 - Prueba del reproductor del video con una sola persona moviéndose hacia la
derecha............................................................................................................ 77
Figura 4.3 - Prueba del reproductor del video con varias personas en fila hacia la izquierda. . 78
Figura 4.4 - Pruebas realizadas sobre la „Hinchada‟ con todas las personas a la vez. ............ 79
Figura 4.5 - Dos personas detectadas como una sola cuando sus esqueletos se tocan. ........ 80
Figura 4.6 - Proceso inicial de „Descubrir la imagen‟ con una sola persona. .......................... 81
Figura 4.7 - Descubriendo la imagen con muchas personas. ................................................ 81
Figura 4.8 - Personas jugando con sus poses y eligiendo qué partes de la imagen descubrir. 82

Índice de diagramas

Diagrama 3.1 - Clase KinectDevice en la etapa de inicialización ........................................... 26


Diagrama 3.2 - Clase KinectDevice luego de la etapa de comunicación con el dispositivo
físico. .......................................................................................................... 29
Diagrama 3.3 - Estructura de los controladores. .................................................................. 35
Diagrama 3.4 - Interfaz IModel con dos modelos de ejemplo. ............................................... 36
Diagrama 3.5 - Incorporación de la vista al controlador y modelo.......................................... 40
Diagrama 3.6 - Incorporación del video a la vista ................................................................. 44
Diagrama 3.7 - Clase VideoModel - Incorporación de atributos y métodos. ........................... 45
Diagrama 3.8 - Comunicación del controlador con el Singleton Configuration. ....................... 46
Diagrama 3.9 - Incorporación de nuevos atributos a Configuration y nueva comunicación con
la vista......................................................................................................... 49
Diagrama 3.10 - Etapa 2 - Interacción entre los modos de reproducción. .............................. 51
Diagrama 3.11 - Diagrama de clases de la aplicación del reproductor de video. .................... 55
Diagrama 3.12 - Relación entre PlayersModel y AudioManager. ........................................... 59
Diagrama 3.13 - Clase AudioManager incorporando atributos específicos a la biblioteca
FMOD ......................................................................................................... 59
Diagrama 3.14 - Clase PlayersModel que mantiene el último contador con el que fue
actualizado. ................................................................................................. 63
Diagrama 3.15 - Clase PlayersModel - Incorporación de atributos y métodos. ....................... 66
Diagrama 3.16 - Clase ColorManager utilizada por PlayersController ................................... 67

4
Diagrama 3.17 - Clase DiscoveryModel con sus atributos iniciales. ...................................... 71
Diagrama 3.18 - Clase ColorManager actualizado para retornar color sin controlar su uso. .... 72

Índice de code snippets

Code snippet 3.1 - Incorporación de métodos para atrapar los eventos de flujos de datos. ......27
Code snippet 3.2 - Captura de evento de nuevo frame de esqueletos. ...................................28
Code snippet 3.3 - Captura de evento de nuevo frame de profundidad. .................................28
Code snippet 3.4 - Interfaz IController..................................................................................29
Code snippet 3.5 - Métodos de VideoController load y unload. ..............................................43
Code snippet 3.6 - Código correspondiente al método update de VideoController. .................46
Code snippet 3.7 - Cuerpo del método draw de la vista. ........................................................47
Code snippet 3.8 - Implementación de update como una máquina de estados. ......................51
Code snippet 3.9 - Implementación del método updateActualFrame() utilizado por update(). ...52
Code snippet 3.10 - Método updateState(). ..........................................................................53
Code snippet 3.11 - Versión final del archivo configuration.xml ..............................................54
Code snippet 3.12 - Cuerpo del método play utilizando la biblioteca FMOD. ...........................61
Code snippet 3.13 - Cuerpo del método stop utilizando la biblioteca FMOD. ..........................61
Code snippet 3.14 - Cuerpo del método update de PlayersController junto al transformador
privado getAudioCounter. .........................................................................62
Code snippet 3.15 - Ruta de los archivos de audio dentro de Audios.xml ...............................64
Code snippet 3.16 - Porción del cuerpo del método load de la vista relacionado a la
reproducción de video de fondo.................................................................65
Code snippet 3.17 - Cuerpo del método draw al dibujar siluetas sobre el video. .....................65
Code snippet 3.18 - Cuerpo del método load del controlador. ................................................68
Code snippet 3.19 - Cuerpo del método update del controlador actualizado. ..........................68
Code snippet 3.20 - Cuerpo del método draw de la vista al dibujar textura sobre imagen de
fondo. ......................................................................................................70
Code snippet 3.21 - Cuerpo método update del modelo. .......................................................71
Code snippet 3.22 - Cuerpo del método load del controlador. ................................................72
Code snippet 3.23 - Cuerpo del método update del controlador. ............................................72

5
Agradecimientos
A mis papás principalmente, por apoyarme cada día a lo largo de toda mi
carrera incondicionalmente. Por darme todas las posibilidades de llegar a este
punto, y aguantarme en esos días más complicados.

A mi hermanita Antonia, por levantarme el ánimo y darme una sonrisa cada


minuto compartido.

Al resto de mi familia, abuelos, tías y primos, por preocuparse y preguntar


siempre con buena onda.

A Giuli, Marian, Franco, Santi, Jorge, y amigos de la facultad, todos, que se


bancaron mis explicaciones de la tesis, y gracias a ellos realicé las pruebas
de la mejor manera, siempre con su apoyo y su empuje.

6
Resumen
La aparición de nueva tecnología capaz de reconocer los movimientos del cuerpo,
revolucionó las interfaces de usuario. Se encuentra en pleno crecimiento la creación
de aplicaciones interactivas que explotan estas tecnologías para ser usadas, luego, en
diversos ambientes como la medicina, el deporte y exposiciones, entre otros.

Si bien existen herramientas que facilitan el acceso a los datos brindados por los
dispositivos, no se logra simplificar su uso. Para la creación de aplicaciones es
necesario tener un conocimiento previo para lograr la manipulación de los datos, y
luego realizar acciones que respondan a los mismos.

En este trabajo se presenta una plataforma para facilitar la creación de diversas


aplicaciones interactivas que responden a movimientos del cuerpo. El desarrollo se
basó particularmente en el dispositivo Kinect. Esto permite que una persona con
conocimiento limitado en lo que respecta a la detección de los cuerpos, pueda crear su
propia aplicación.

Para la creación de esta plataforma, se investigaron diferentes paseos turísticos


alrededor del mundo que incorporan interactividad. Se consideraron algunas
posibilidades para luego desarrollarlas en la forma de tres aplicaciones interactivas
relacionadas al tenis. El interés demostrado hacia este deporte y en focalizar parte de
la interacción en él, se basó en la impronta que tiene esta disciplina en la ciudad de
Tandil, cuna de tenistas, y la posibilidad de brindar soporte virtual en la posible
creación de un museo interactivo. El desarrollo finalizó con las pruebas
correspondientes para comprobar la usabilidad de las aplicaciones creadas.

7
Capítulo 1
Capítulo 1 Introducción
El avance tecnológico en estos últimos años, hizo que la interacción entre el humano y
cualquier dispositivo sea mucho más intuitiva. Las pantallas táctiles hicieron posible
este acercamiento, eliminando la necesidad de un teclado y mouse, haciendo posible
la dominación de un dispositivo sólo con el tacto. Pero eso no es todo, la incorporación
de reconocimiento de movimientos del cuerpo, revolucionó la manera de interactuar
con una máquina.

Wii Remote[1], Leap Motion[2] y Kinect[3] son una serie de controladores de juegos y
entretenimiento capaces de reconocer los movimientos del cuerpo, para luego realizar
acciones con su análisis. El dispositivo Kinect se destaca por la utilización de
diferentes sensores para la detección completa del cuerpo humano. Fue desarrollado
por Microsoft para la videoconsola Xbox 360 y es capaz de reconocer gestos,
comandos de voz, objetos e imágenes.

La aparición en el mercado de estas innovaciones provocó una revolución en la


creación de aplicaciones altamente interactivas. Se pueden apreciar en diferentes
disciplinas, por ejemplo en la medicina [4], con el uso del dispositivo Kinect, para el
desarrollo de habilidades en personas con necesidades especiales derivadas de la
discapacidad así como también en diferentes tipos de rehabilitación; en campo del
deporte[5] hay sistemas para mejorar distintas técnicas de juego; y en el
entretenimiento[6], se puede ver la utilización de Video Mapping [7] en diversos eventos
como recitales y desfiles.

Más aún, su alcance no termina ahí: la interactividad se puede ver en crecimiento en


muchos aspectos de la vida cotidiana, abriendo una cantidad infinita de posibilidades
en donde la interactividad todavía está por darse.

8
1.1 Motivación

Si bien existen varias herramientas [8], para el desarrollo de aplicaciones interactivas,


como el SDK para Kinect, se necesita de un conocimiento previo para la manipulación
de los datos y las diferentes acciones que se quieran realizar. Así, se presentó el
desafío de desarrollar una serie de aplicaciones que utilicen el dispositivo Kinect y
manipulen los datos de diversas maneras probándolo en un escenario específico.

Hoy en día existe en el mundo un crecimiento de museos interactivos. Se llaman así a


aquellos museos que rompen la barrera del „No tocar‟ y en donde lo prohibido es
quedarse quieto. Con el objetivo de transformar un simple paseo por el museo, en un
paso más allá, con rasgos aún más interesantes y atrapantes. De esta forma un
recorrido silencioso y cauteloso puede transformarse en una experiencia divertida e
innovadora.

Con la incorporación de nuevas tecnologías, los museos permiten aprender jugando.


La unión del arte y la tecnología abre un gran camino de posibilidades. La
interactividad se lleva a cabo a través de dispositivos como los celulares y tabletas,
como así también el Kinect previamente mencionado.

En la ciudad de Tandil, Buenos Aires, se encuentra el proyecto de inaugurar un museo


de tenis. Pero este museo no pretende ser uno más: será el primer museo interactivo
de la ciudad, en donde las personas que lo visiten puedan participar de diferentes
actividades divertidas y atrapantes, donde adultos y niños puedan disfrutarlo de una
manera diferente. Esto generaría un encanto superior a la ciudad, atrayendo así a una
mayor cantidad de turistas.

La principal motivación en desarrollar una serie de aplicaciones que puedan ser


utilizadas en este museo, es la de evaluar qué tan reutilizables pueden ser, para qué
público son adaptables y la facilidad de que en un futuro una persona ajena al
proyecto pueda crear una aplicación.

1.2 Solución propuesta

El objetivo de este trabajo, es el de incorporar la parte interactiva a dicho museo de


tenis a través de la implementación de una serie de aplicaciones que utilizan Kinect.
Estas aplicaciones tendrán su foco en el museo, pero su alcance no será limitado. Se
busca que puedan ser reutilizadas para un abanico de situaciones.

9
Se pretende propiciar un ambiente en el que los adultos puedan divertirse como niños,
y que los niños disfruten del recorrido por un museo sin las limitaciones que
usualmente se deben tener. Considerando este objetivo, se desarrollarán algunas
aplicaciones que involucren la manipulación de video, audio y también imágenes.

Las aplicaciones van a tener el fin de mantener al público en continuo movimiento. En


todo momento, se mantendrá el enfoque en el objetivo principal que es la de no tener
limitaciones en el alcance del uso de las aplicaciones y la facilidad de la creación de
una nueva.

1.3 Organización del informe

El presente informe se divide en 5 capítulos. El Capítulo 1 es el actual, donde se


encuentra una introducción general al proyecto.

El Capítulo 2 llamado Interactividad, contiene el contexto actual y antecedentes


relacionados al trabajo. Se introducen conceptos de interactividad con el usuario y se
muestra la evolución de las tecnologías relacionadas. Se hace especial hincapié en el
dispositivo Kinect el cual se utiliza a lo largo de todo el proyecto. También se muestra
un relevamiento de algunos museos y paseos existentes que utilizan algún tipo de
tecnología para incluir interactividad. Por último, se proporciona un panorama general
de las tecnologías usadas para la creación de las aplicaciones.

El Capítulo 3, Diseño e Implementación, es específico y central al proyecto. Se


encuentra dividido en dos secciones: en primer lugar se expone la arquitectura
propuesta en donde se explican todos sus componentes y luego, se detalla la
instanciación de la arquitectura en tres diferentes aplicaciones.

El Capítulo 4 se basa en los resultados de las pruebas realizadas sobre las


aplicaciones que fueron explicadas en el Capítulo 3. Comienza detallando el contexto
de las pruebas, los elementos utilizados y la cantidad de personas que asistieron.
Luego se pasa a describir los resultados de las pruebas, aplicación por aplicación,
indicando aquellos aspectos positivos, y también aquellos que deben corregirse.

El Capítulo 5, engloba las conclusiones del trabajo en dos secciones: en primer lugar
se detallan los resultados obtenidos con respecto a los objetivos propuestos; luego se
proponen posibles trabajos futuros sobre la plataforma y las aplicaciones
desarrolladas.

10
Al finalizar se encuentra la sección de Bibliografía, en donde se listan todas aquellas
fuentes que fueron utilizadas para completar el informe actual.

11
Capítulo 2
Capítulo 2 Interactividad
En este capítulo se introducen los conceptos de interactividad con el usuario. Se hará
un recorrido sobre la evolución de la tecnología. Como la plataforma creada en este
proyecto se basa en el dispositivo Kinect, se incluirán las especificaciones necesarias
relacionadas a su uso. Luego se mostrará la forma en que se utiliza la interactividad
específicamente en el contexto de paseos y museos. Por último, se dará un panorama
general de las tecnologías usadas para la creación de las aplicaciones.

2.1 Evolución de la Interfaz de usuario

La interfaz de usuario es el medio con que el usuario puede comunicarse con una
máquina. Éstas fueron evolucionando a través del tiempo, siendo cada vez más
intuitivas. Se pueden clasificar según la forma de interacción con el usuario, CLI, GUI o
NUI (Figura 2.1).

Figura 2.1 - Evolución de las interfaces de usuario.

Las CLI[9], command-line interface o también interfaz de líneas de comando, permiten


a los usuarios dar instrucciones a algún programa informático por medio de una línea
de texto simple. Como se basa únicamente en la entrada y salida de texto, toda la
pantalla de visualización sólo muestra caracteres, nada de imágenes, y la entrada se

12
realiza generalmente en su totalidad con un teclado. Esta interfaz existe casi desde los
comienzos de la computación.

Las GUI[10], graphical user interface, en español interfaz gráfica de usuario, surgen
como evolución de las interfaces de línea de comandos. Éstas cuentan con el uso de
imágenes gráficas, incluyendo ventanas, íconos y menús. Estos objetos son
manipulados por un mouse y por lo general se pueden operar de forma limitada por un
teclado también. Su principal uso, consiste en proporcionar un entorno visual sencillo
que permita la comunicación con el sistema operativo de una máquina.

Las NUI[11], natural user interface, es el tipo de interfaz de usuario en las que se
interactúa con un sistema sin utilizar dispositivos de entrada. La idea general es que
en lugar de tener medios artificiales de entrada, el usuario interactúa con la máquina
de una manera más similar a la que utiliza para interactuar con las personas y objetos
en el mundo real, y de una manera más directa. Esto quiere decir, interactuar a través
del tacto, los gestos del cuerpo, las expresiones faciales, y el lenguaje.

Figura 2.2 - Interfaces de usuario (CLI, GUI y NUI respectivamente)

Hoy nos encontramos en el inicio de la próxima revolución, pasando de interfaces


gráficas de usuario (GUI) a interfaces naturales de usuario. La sociedad está en
constante movimiento, llena de información y muy comunicativa. Es por esto que la
computadora de escritorio ya no cumple con las necesidades y demandas requeridas
por una sociedad en continua evolución. En la actualidad, se usan los teléfonos
móviles, tabletas y pantallas táctiles de variados tamaños, incluso hasta del tamaño de
una mesa de conferencia para permanecer conectados, satisfacer necesidades y
lograr objetivos. Sin embargo, NUI es más que tocar algo con el dedo en lugar de
hacer clic con un mouse. Wii Remote (WiiMote)[1], Leap Motion[2] y Kinect[3] son
ejemplos de una serie de controladores de juegos y entretenimiento que son capaces
de reconocer los movimientos del cuerpo (o partes de ellos), y realizar acciones con su
análisis.

13
Figura 2.3 - Dispositivo WiiMote

WiiMote[1] (Figura 2.3) es un dispositivo que tiene la capacidad de detección de


movimiento. Permite al usuario manipular e interactuar con elementos en pantalla a
través de reconocimiento de gestos y señalando a través del uso de tecnología de
acelerómetro ADXL330 y sensor óptico PixArt. Es el controlador principal para
Nintendo Wii, que gracias al sensor óptico, le permite determinar el lugar al que el
Wiimote está apuntando, independientemente del tipo o tamaño de la televisión.

Figura 2.4 - Dispositivo Leap Motion

Leap Motion[2] (Figura 2.4) es un dispositivo sensor que soporta movimientos de la


mano y de los dedos como entrada, análogo a un mouse, pero no requiere contacto
con las manos. El corazón del dispositivo consta de dos cámaras y tres LEDs
infrarrojos. Cuenta con un gran espacio de interacción que toma la forma de una
pirámide invertida. Anteriormente, el rango de visión se limitaba a 60 cm, luego de
actualizar el software llegó a 80 cm.

14
Figura 2.5 - Dispositivo Kinect

Kinect[3] (Figura 2.5) es una línea de sensores de movimiento de entrada para


Microsoft Xbox 360 y Xbox One como también para PCs. El uso de cámaras y otros
complementos periféricos, permite a los usuarios controlar e interactuar con su
consola/computadora sin la necesidad de un controlador de juego, a través de una
interfaz natural de usuario usando gestos y comandos de voz. Como el proyecto
desarrollado se basa exclusivamente en el dispositivo Kinect, a continuación se
incluyen detalles del dispositivo:

2.1.1 Kinect

Figura 2.6 - Componentes del dispositivo Kinect

El dispositivo Kinect tiene una serie de componentes que hacen a su funcionamiento [12]
que se muestran en la Figura 2.6. Una cámara RGB con una resolución de 1280x960
permite la captura de imágenes de colores. Un emitidor infrarrojo (IR) se encarga de
emitir rayos de luz infrarroja y luego el sensor de profundidad IR captura aquellos

15
rayos que vuelven reflejados. Estos rayos luego son convertidos en información de
profundidad midiendo la distancia entre un objeto y el sensor.

Un arreglo de cuatro micrófonos captura sonidos. Por la cantidad de micrófonos es


posible grabar audio, como así también encontrar la ubicación de la fuente de sonido y
la dirección de la onda de audio. Por último, un acelerómetro de 3 dimensiones con un
rango de 2G, donde G es la aceleración correspondiente a la gravedad, permite
determinar la orientación del Kinect.

Figura 2.7 - Rango de inclinación

El ángulo de visibilidad del dispositivo Kinect es de 43° en el espacio vertical, y de 57°


en horizontal. Debido a la inclinación motorizada, el espacio vertical puede moverse
27° hacia arriba o hacia abajo como se puede ver en la Figura 2.7.

Si están habilitados, el Kinect puede capturar audio, color y datos de profundidad, y


procesar los datos de profundidad para generar datos de esqueletos. Estos datos son
presentados en la forma de flujos de datos que se pueden controlar y acceder desde
las aplicaciones a través del SDK del dispositivo Kinect. Las aplicaciones
desarrolladas para este proyecto en particular, sólo utilizan los flujos de datos de
profundidad y de esqueletos.

El arreglo de micrófonos captura datos de audio a una resolución de 24 bits. Se


pueden ver en color lila en la Figura 2.8. Esto permite una precisión en un rango
dinámico de datos de voz, desde un habla normal a tres o más metros de distancia,
hasta una persona gritando. Además de capturar audio en alta definición, permite
focalizar en un audio proveniente de un lugar en particular, identificar la dirección del
audio detectado y hasta detectar palabras.

16
Figura 2.8 - Arreglo de micrófonos del dispositivo Kinect marcados en violeta.

El flujo de datos de color es simplemente la imagen obtenida como si fuera a través de


una cámara web. Está disponible en diferentes resoluciones y formatos. El formato
determina si el flujo está codificado como RGB, YUV o Bayer. Sólo se pueden utilizar
una resolución y un formato a la vez. El sensor utiliza una conexión a través del puerto
USB lo que provee un determinado ancho de banda. La elección de la resolución
determina cómo es usado ese ancho de banda. Las imágenes en alta definición
utilizan más datos, pero se actualizan menos frecuentemente. Al bajar la resolución, se
actualizan más frecuentemente pero se pierde la calidad de la imagen debido a la
compresión.

Figura 2.9 - Frames de profundidad.

Cada frame del flujo de profundidad está formado por píxeles que contienen la
distancia en milímetros desde la cámara hasta el objeto más cercano. Este flujo une
dos tipos de datos distintos. Por un lado se encuentra la distancia, pero también se
toma en cuenta los datos de los jugadores segmentados. Cada dato es un entero
indicando el índice de un único jugador detectado (Figura 2.9).

El dispositivo Kinect procesa el flujo de profundidad para identificar hasta seis figuras
humanas. Los datos de la segmentación de jugadores sólo están disponibles si está
habilitado el rastreo de esqueletos. El valor „0‟ indica que no se encontró ninguna
persona en esa posición, mientras que los valores del „1‟ al „6‟ identifican a los

17
jugadores. Un uso muy común de esta segmentación es para separar un usuario
específico de una imagen de color o de profundidad.

Figura 2.10 - Frames de esqueletos.

El rastreo de esqueletos permite al dispositivo Kinect reconocer personas y seguir sus


movimientos. Utilizando la cámara infrarroja, Kinect puede reconocer hasta 6 personas
en el área de visibilidad del sensor. De estos, sólo dos son rastreados en detalle, esto
es, se pueden detectar sus articulaciones en el espacio y rastrearlas en el tiempo
(Figura 2.10).

Los esqueletos en un frame pueden tener un estado de seguimiento de „rastreado‟ o


„sólo posición‟. Aquellos „rastreados‟ proveen información detallada sobre la posición
de veinte articulaciones del cuerpo del usuario (Figura 2.11). En cambio, cuando un
esqueleto tiene un estado de „sólo posición‟, se tiene la información sobre la posición
del usuario, pero ningún detalle con respecto a las articulaciones.

Figura 2.11 - Veinte articulaciones rastreadas en un esqueleto.

18
Las aplicaciones pueden utilizar cada articulación para realizar acciones. Por ejemplo,
se puede utilizar la mano para guiar un cursor o simplemente dibujar la posición de las
articulaciones en pantalla. Una articulación también se puede clasificar en tres
estados: „rastreada‟ para una articulación claramente visible, „inferida‟ cuando no está
claramente visible y se infiere su posición, o „no rastreada‟.

En octubre de 2014, surgió una nueva versión del SDK del dispositivo Kinect[13]. Se
amplió el campo de visión horizontal y vertical para la captura de profundidad y de
color. La captura de color es HD, los infrarrojos son independientes de la luz y hubo
mejoras con los micrófonos. La cantidad de esqueletos rastreados en detalle aumenta
de 2 a 6, y la cantidad de articulaciones rastreadas pasan de 20 a 25 cada uno,
incluyendo los pulgares. También es posible utilizar el dispositivo desde múltiples
aplicaciones.

2.2 Interactividad en paseos y museos

En la actualidad existe en el mundo un crecimiento de museos interactivos. Se llaman


así a aquellos museos que rompen la barrera del „No tocar‟ y en donde lo prohibido es
quedarse quieto. Con el objetivo de transformar un simple paseo por el museo, en un
paso más allá, con rasgos aún más interesantes y atrapantes. De esta forma un
recorrido silencioso y cauteloso puede transformarse en una experiencia divertida e
innovadora.

Con la incorporación de nuevas tecnologías, los museos nos permiten aprender


jugando. La unión del arte y la ciencia abre un gran camino de posibilidades. La
interactividad se lleva a cabo a través de dispositivos como los celulares y tabletas,
como así también el Kinect previamente mencionado.

El Museo del Louvre[14] incluyó la interactividad a sus recorridos utilizando códigos QR


y un dispositivo portátil Nintendo 3DS, ideal para descubrir el museo parisino (Figura
2.12). Este dispositivo pasó a ser el audio-guía oficial, sustituyendo a los modelos
tradicionales. Incluye mapas interactivos, recreaciones en 3D de obras e información
adicional sobre las mismas. La información brindada permite ser traducida a los
principales idiomas como el español, francés, alemán, japonés, coreano, italiano o
inglés.

19
Figura 2.12 - Interacción en el Museo de Louvre con el uso de Nintendo 3DS y códigos QR.

Museon[15] es un museo de cultura y ciencia que incorpora interactividad en todas sus


exposiciones. Cree firmemente en la idea de que se aprende más rápido si se puede
poner en práctica la teoría que se aprendió. Repartidos por todo el museo se
encuentran unos terminales que permiten a las personas identificarse con un código
de barras y formula preguntas para comprobar la significatividad educativa de la visita.

Figura 2.13 - Juego en Museon con la utilización de PuppyIR.

A través de la tecnología del proyecto PuppyIR [16], el museo permite crear recorridos
interactivos en equipos, comenzando y terminando en terminales multi-táctiles (Figura
2.13). Durante el recorrido, el equipo debe recolectar elementos para luego llevarlos a
una terminal al finalizar. Aquí, el equipo deberá unir los elementos recolectados con
conceptos relevantes.

20
Figura 2.14 - Live Projection Mapping - EVA 2013

EVA[17] es la conferencia de desarrollo de videojuegos más importante de


Latinoamérica. Se realiza anualmente desde 2003 y cuenta con talleres y conferencias
especialmente pensadas para presentar las últimas novedades en áreas como
Programación, Arte, Publishing y Game Design. En la edición 2013 se realizó una
proyección en vivo sobre un grupo de bailarines utilizando Kinect[18]. Se debió ajustar
manualmente su posición para que su punto de vista coincida con el punto de vista del
proyector (Figura 2.14).

Figura 2.15 - Pisos interactivos en eventos.

La empresa Piso Interactivo[19] está ubicada en Guadalajara, México. Son creadores


de software e instalaciones interactivas para museos, diseño de interiores,
ambientación, eventos sociales y exposiciones. La Figura 2.15 muestra el uso de una
proyección sobre pisos.

21
Figura 2.16 - ‘Play Work Build’ en el National Building Museum.

National Building Museum[20], de Washington DC, es un museo de arquitectura, diseño,


ingeniería, construcción y planeamiento urbano. Incorporó a sus visitas una aplicación
interactiva para los niños llamada „Play Work Build‟ [21] que usa el cuerpo para construir
paredes virtuales al mantenerse quietos y destruirlas con los movimientos. Esto se
desarrolló gracias a la utilización del dispositivo Kinect (Figura 2.16).

Figura 2.17 - ‘Strike a pose’ en Cleveland Museum of Art.

Cleveland Museum of Art[22] [23]


, ubicado en Ohio, se especializa en arte Asiático y
Egipcio. Su recorrido ofrece al espectador una serie de aplicaciones que permiten
interactuar con el arte, como „Strike a pose‟ que reta a imitar las poses de diferentes
esculturas. Como se puede ver en la Figura 2.17, al igual que „Play Work Build‟, utiliza
el dispositivo Kinect.

22
Figura 2.18 - Juego interactivo relacionado al Básquet en Chicago Sports Museum.

Chicago Sports Museum [24] es un museo que fue diseñado con un foco en la
interactividad y entretenimiento. Una de las actividades más interesantes que este
museo brinda, es la de imitar alguna jugada específica de Básquet, Fútbol, Baseball, o
Jockey. En la imagen se puede ver un juego de Básquet en un contexto similar al real,
que gracias al Kinect, un avatar de un jugador profesional sigue los movimientos de la
persona que lo juega (Figura 2.18).

Figura 2.19 - Avatares en Sedena.

En el museo creado en honor a las Fuerzas Armadas de México[25] se incluyó una


exhibición digital multi sensorial. Para ello, se realizaron instalaciones electrónicas que
permiten navegar y conocer la historia con facilidad. A través del uso de Kinect, se

23
logró incorporar modelos en 3D que al detectar la presencia de una persona cobran
vida y simulan los movimientos que realizan los visitantes (Figura 2.19).

2.3 Tecnologías utilizadas

El próximo capítulo se centra en el diseño e implementación de una serie de


aplicaciones interactivas. Estas aplicaciones utilizan video y audio para su
comunicación con el usuario. Existen diversas tecnologías que permiten la
manipulación de estos elementos.

Con respecto a la reproducción de video, se utilizó una biblioteca que permite


manipular los videos frame a frame. Emgu CV [26] es un wrapper para la biblioteca de
procesamiento de imágenes OpenCV. De esta manera se permite acceder a las
funciones de OpenCV[27] desde cualquier lenguaje .NET.

Luego, para la reproducción de audio se utilizó la biblioteca FMOD [28] que puede
manejar a los sonidos en un alto nivel, incorporando diferentes efectos. El uso de esta
biblioteca permite una mayor extensibilidad a la hora de incorporar nuevas
aplicaciones de audio. Reproduce y mezcla archivos de sonido de diversos formatos
en muchos sistemas operativos.

Para manipular la vista a nivel de píxel, o simplemente mostrar imágenes o videos sin
la necesidad de dinámicamente manipularlos, la vista XNA[29] es ideal. Brinda en un
alto nivel la interacción de la aplicación con la vista. Permite mostrar imágenes y
videos en diferentes capas superpuestas, y la creación de una nueva textura a mostrar
es muy sencilla.

A continuación se muestra el diseño de una plataforma para la creación de


aplicaciones interactivas. Luego, junto al uso de las tecnologías, se realiza la
instanciación de la arquitectura.

24
Capítulo 3
Capítulo 3 Diseño e Implementación

El capítulo de implementación está dividido en dos partes. En primer lugar se describe


la arquitectura de software de la plataforma desarrollada. En esta sección se
presentan los componentes (y relaciones entre ellos) de las aplicaciones realizadas a
modo de ejemplo de utilización de la plataforma, como el funcionamiento de cada
aplicación. En segundo lugar se muestran también diagramas y partes de código
necesarios para ayudar a describir el funcionamiento de la plataforma descripta.

3.1 Arquitectura propuesta

Tal como se describió en el Capítulo 2, el desarrollo se centra en poder capturar y


distribuir información brindada por el Kinect, de una forma estandarizada y eficiente.
La plataforma está inclinada hacia la creación de aplicaciones para el entretenimiento,
interactuando con el público a través de la vista y el oído.

En las siguientes secciones se explicarán los componentes que forman parte de la


plataforma, para llevar a cabo cualquier aplicación deseada. El patrón de la
arquitectura está basado en Model-View-Controller[30]. Cada sección detallará en
manera progresiva la creación del modelo, del controlador y de la vista, para llegar por
último a sus versiones finales.

3.1.1 Controlador

Al inicio del proyecto, se tenía en claro que se iban a desarrollar una serie de
aplicaciones las cuales serían controladas por las personas, a través del dispositivo de
Kinect. Para este fin, se debía crear un gestor que sea el encargado de la
comunicación con el aparato físico. Toda comunicación entre el gestor y el dispositivo
físico se realiza a través del Kinect SDK, que brinda diversas posibilidades para el
acceso (Figura 3.1).

25
Figura 3.1 - Interacción del dispositivo Kinect con la aplicación a través del Kinect SDK

El gestor, llamado KinectDevice, se fue implementando progresivamente. A lo largo de


los siguientes párrafos se explicará el camino tomado para su desarrollo, hasta llegar a
la versión final con todos sus métodos y atributos. Sus datos son crudos, y el
controlador es el encargado de tomar estos datos, transformarlos y actualizar el
modelo de datos.

La funcionalidad indispensable para comenzar a utilizar el gestor, es la inicialización.


Dentro de initializeKinect se conecta al dispositivo físico, y devuelve un dato para
indicar si la conexión fue exitosa o no. Internamente, busca el primer sensor conectado
y lo guarda como un atributo de la clase para ser usado en cualquier momento. Por
último, ejecuta la acción Start sobre el sensor.

Una vez inicializado, es fundamental la liberación del recurso físico. Por tal motivo, se
incorporó stopKinect. Aquí, a través del sensor guardado, le indica al Kinect que frene
el flujo de datos.

En el curso de esta primera etapa, se incluyeron sólo aquellos métodos primitivos. En


el Diagrama 3.1 se pueden ver aquellos que permiten la inicialización y la liberación
del dispositivo. También se incluye el método privado que es utilizado internamente
para obtener el primer sensor conectado, y el atributo privado que es fijado por el
mismo.

Diagrama 3.1 - Clase KinectDevice en la etapa de inicialización

26
Como se mencionó en el capítulo anterior, para poder utilizar los datos brindados por
el dispositivo Kinect, se deben habilitar los diferentes flujos que se vayan a utilizar.
Cada flujo de datos dispara un evento indicando un nuevo frame. Se debe tener un
método asociado a cada uno de ellos para poder atraparlos y así guardar los datos
necesarios. Para el propósito actual sólo se van a utilizar dos: Skeleton Stream y
Depth Stream. Como fue descripto anteriormente, el Skeleton Stream brinda
información sobre los esqueletos encontrados, y el Depth Stream sobre la profundidad
de estos esqueletos, identificando a cada jugador. Su necesidad se verá especificada
en las próximas secciones.

Se debió modificar initializeKinect para incorporar los eventos de Kinect. En el caso


de que se encuentre un sensor disponible, se establecen aquellos métodos
encargados de atrapar el evento (Code snippet 3.1). Entonces, si el flujo de datos está
habilitado, en cada momento en el que kinect tiene un nuevo frame disponible, activa
el evento y KinectDevice puede tomar los datos deseados y los mantiene actualizados
para tenerlos disponibles cuando sean solicitados por algún controlador. En el caso en
que en el futuro se quiera incorporar un nuevo flujo de datos, es aquí donde se debe
incluir el nuevo evento especificando la funcionalidad determinada.

if (null != sensor)
{
// Agrega controlador de evento para cuando haya nuevo frame de esqueleto
sensor.SkeletonFrameReady += skeletonFrameReady;

// Agrega controlador de evento para cuando haya nuevo frame de profundidad


sensor.DepthFrameReady += depthFrameReady;
}
Code snippet 3.1 - Incorporación de métodos para atrapar los eventos de flujos de datos.

El evento disparado cuando un frame de esqueleto está listo, emite sus argumentos
del tipo SkeletonFrameReadyEventArgs. Dentro de los argumentos se encuentra un
SkeletonFrame el cual el gestor utiliza para tomar los datos de los esqueletos en forma
de un arreglo de tipo Skeleton, que luego podrá ser consultado (Code snippet 3.2).

27
private void skeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e)
{
using (SkeletonFrame skeletonFrame = e.OpenSkeletonFrame())
{
if (skeletonFrame != null)
{
if (skeletons == null)
skeletons = new Skeleton[skeletonFrame.SkeletonArrayLength];

skeletonFrame.CopySkeletonDataTo(skeletons);
}
}
}
Code snippet 3.2 - Captura de evento de nuevo frame de esqueletos.

El evento disparado cuando un frame de profundidad está listo, es similar al anterior.


Sus argumentos contienen un DepthImageFrame dentro de
DepthImageFrameReadyEventArgs. El DepthImageFrame es utilizado para tomar los
datos de los píxeles de profundidad, y guardarlos en un arreglo de tipo
DepthImagePixel (Code snippet 3.3).

private void depthFrameReady(object sender, DepthImageFrameReadyEventArgs e)


{
using (DepthImageFrame depthImageFrame = e.OpenDepthImageFrame())
{
if (depthImageFrame != null)
{
if (depthPixels == null)
depthPixels = new Skeleton[depthImageFrame.PixelDataLength];

depthImageFrame.CopyDepthImagePixelDataTo(depthPixels);
}
}
}
Code snippet 3.3 - Captura de evento de nuevo frame de profundidad.

Se debe permitir a cada aplicación habilitar el o los flujos de datos que se utilicen, para
no estar recibiendo frames que son totalmente innecesarios. Se provee este servicio a
través de enableSkeletonStrem e enableDepthStream para habilitar cada uno de los
flujos previamente mencionados.

Durante el desarrollo de la primera aplicación se vio necesario borrar aquellos


esqueletos obtenidos del SkeletonFrame. En efecto, también se incorporó esta nueva
posibilidad implementando resetSkeletons, el cual tiene como única funcionalidad
eliminar el arreglo de esqueletos.

Resumiendo, en esta etapa se agregó funcionalidad relacionada a los flujos de datos.


Se permite habilitar el Skeleton Stream y/o el Depth Stream. También se incorporaron

28
como métodos privados, aquellos que se encargan de atrapar los eventos y mantener
actualizados los datos: depthPixels y skeletons. Los getters son indispensables para
obtener aquellos datos actualizados. Por último, se permite borrar datos. En el
Diagrama 3.2 se pueden ver resaltadas aquellas actualizaciones de la clase.

Diagrama 3.2 - Clase KinectDevice luego de la etapa de comunicación con el dispositivo físico.

El próximo paso es crear un controlador que utilice el gestor de Kinect como un


recurso. Tal como se mencionó anteriormente, el controlador se encarga de inicializar
el dispositivo Kinect, y luego tomará los datos crudos de KinectDevice, los
transformará y actualizará al modelo. Para mejorar la abstracción, y permitir así en un
futuro la incorporación de cualquier tipo de controlador de una manera sencilla, se
formalizó una estructura.

Es así que se llegó al diseño de los controladores. Cada controlador creado debe
implementar una interfaz IController. Sus métodos se pueden dividir fácilmente en tres:
load, update y unload, estandarizando la división de funcionalidad (Code snippet 3.4).

interface IController
{
//Inicialización de cualquier recurso necesario
bool load();

//Transformación de datos
//Actualización del modelo
void update();

//Liberación de los recursos


void unload();
}
Code snippet 3.4 - Interfaz IController

Dentro del load, el controlador debe inicializar cualquier recurso que vaya a ser
necesario, además del modelo. El recurso que será común a todas las aplicaciones

29
específicas de este proyecto, es el KinectDevice. Otros recursos utilizados también en
esta ocasión pueden ser un gestor de colores y/o un gestor de audio. Estos se verán
explicados a lo largo de las secciones 3.2.2 y 3.2.3, junto con las últimas dos
aplicaciones que los utilizan.

Si se produjo algún problema dentro de la inicialización, el método se encarga de


indicar la situación a través de un booleano de retorno (Figura 3.2). De esta manera, la
vista es capaz de reaccionar. Sus acciones se verán en la sección correspondiente al
explicar el componente de la vista.

Figura 3.2 - Secuencia de llamados para la inicialización

El método unload debe contener la funcionalidad para liberar los recursos. Cada
controlador tendrá que liberar dentro de este método, todos sus recursos utilizados
(Figura 3.3). En este proyecto en particular, todos los controladores utilizan Kinect, por
lo tanto deberán liberarlo a través de kinectDevice.stopKinect().

Figura 3.3 - Secuencia de llamados para terminar la aplicación.

El update se ejecuta constantemente. En su cuerpo, el controlador debe realizar un


análisis de los datos y actualizar el modelo con los datos necesarios (Figura 3.4). Esta
parte es muy específica de cada controlador.

30
Figura 3.4 - Secuencia de llamados para la actualización del modelo.

En este proyecto en particular, dentro del método update se debe encontrar la


comunicación con el gestor de Kinect. Previo a la actualización del modelo, se deben
transformar los datos. La transformación de los datos es la misma para cualquier
controlador que utilice la clase KinectDevice.

Por este motivo, se decidió crear una clase abstracta, KinectController, que sea un tipo
de IController. En ella se encontrarán todos los métodos necesarios para evitar la
repetición de código, y así facilitar la creación de un nuevo controlador dependiente de
Kinect. En la Figura 3.5 se puede ver su comunicación con KinectDevice.

Figura 3.5 - Comunicación necesaria entre el controlador y gestor de Kinect.

En las siguientes secciones se verá la forma en que cada aplicación desarrollada


permitió incorporar nuevos métodos y modificar la estructura básica de la plataforma
planteada, explicando también el uso de cada uno. A continuación se pasará a
mencionar aquellos que fueron agregados a KinectController a lo largo de todo el
desarrollo.

Como se nombró anteriormente, a través del SkeletonFrame, se mantiene un arreglo


de tipo Skeleton. Esta información brinda al controlador un conjunto amplio de datos y
en diversas formas. En este caso se puede determinar si hay algún esqueleto
traqueado, acceder a la cantidad de esqueletos encontrados, o también a sus
posiciones.

31
Figura 3.6 - Transformación de los datos por el método getTotalSkeletons.

La cantidad de esqueletos encontrados se obtiene a través de getTotalSkeletons()


(Figura 3.6). Como se mencionó en las especificaciones del Kinect dentro del capítulo
2, cada esqueleto tiene la propiedad TrackingState. Sus posibles valores son
PositionOnly, Tracked, o NotTracked. El estado Tracked indica que el esqueleto tiene
sus articulaciones rastreadas. Un esqueleto con PositionOnly sólo contiene su posición
general. NotTracked significa que no se rastreó el esqueleto. Este método en particular
cuenta aquellos esqueletos que como TrackingState tengan PositionOnly o Tracked
(Figura 3.7).

Figura 3.7 - Diferentes estados de rastreo: PositionOnly (izquierda) y Tracked (derecha)

Para consultar si un hay un esqueleto disponible, se puede utilizar el método


isSkeletonAvailable(). Se encarga de devolver un boolean indicando si existe en aquel
arreglo de esqueletos, algún esqueleto con TrackingState igual a Tracked (Figura 3.8).
Este método internamente consulta por el primer esqueleto traqueado.

32
Figura 3.8 - Transformación de los datos por el método isSkeletonAvailable.

A través del método getFirstSkeletonPosition(), se obtiene la posición del primer


esqueleto rastreado, es decir, con TrackingState igual a Tracked (Figura 3.9).
Nuevamente, este método consulta internamente por el primer esqueleto rastreado. La
posición de retorno es de tipo Point, pero la posición del esqueleto es de tipo
SkeletonPoint. Por lo tanto fue necesaria la incorporación de la funcionalidad para
solucionar la diferencia. Se incorporó un nuevo método a KinectDevice.

Figura 3.9 - Transformación de los datos por el método getFirstSkeletonPosition.

El método skeletonPointToScreen se encarga de mapear un SkeletonPoint a un


punto de pantalla. Los puntos de esqueletos están expresados en metros mapeados a
la habitación (Figura 3.10). El sensor del Kinect tiene un CoordinateMapper que tiene
la capacidad de traducir estos puntos a un DepthPoint a través del método
MapSkeletonPointToDepthPoint y la resolución de pantalla. Un DepthPoint se mide
en milímetros, y por lo contrario al punto de esqueleto, representa la posición dentro
del frame. Entonces, puede devolver un Point inicializado con los valores X e Y del
DepthPoint obtenido.

Figura 3.10 - Espacio del esqueleto (izquierda) comparado con los valores de
profundidad (derecha).

Más adelante se verá que también fue necesario consultar por todas las posiciones de
todos los esqueletos. Para ello existe también la transformación de

33
getSkeletonPositions(), que devuelve un arreglo de Point de la longitud del arreglo de
esqueletos (Figura 3.11). En cada elemento guarda la posición mapeada a pantalla de
cada Skeleton.Position que se encuentra con un TrackingState de PositionOnly o
Tracked. En el caso de que el esqueleto no está traqueado, se inicializa un Point con
valores negativos indicando la situación.

Figura 3.11 - Transformación de los datos por el método getSkeletonPositions.

Volviendo a los diferentes tipos de frames, a través del DepthFrame se mantiene un


arreglo de tipo DepthImagePixel. El gestor de Kinect sólo brinda un método,
getDepthPixels(), para que cualquier controlador lo pueda acceder. KinectController se
encarga de recorrer este arreglo para quedarse sólo son los datos necesarios. Así se
forma un arreglo de enteros indicando el id de cada jugador en cada píxel (Figura
3.12). El método encargado de la transformación es getPlayersId().

Figura 3.12 - Transformación de los datos por el método getPlayersId.

También es posible convertirlo en un arreglo de booleanos. De esta manera, en cada


posición del arreglo se indica si hay o no algún jugador (Figura 3.13).

Figura 3.13 - Transformación de los datos por el método isPlayerOnPixel.

Entonces, a lo largo de esta etapa, se obtuvo una interfaz que debe implementar todo
controlador. Esta interfaz incluye métodos para la inicialización, actualización y
finalización. Como todo controlador dependiente de Kinect debe transformar los datos
de KinectDevice, se pensó en una clase abstracta que contenga a los
transformadores. Luego, cada controlador específico para cada aplicación deberá
extenderlo. A continuación se muestra la relación entre la interfaz IController, la clase
abstracta KinectController y el gestor KinectDevice (Diagrama 3.3). El método
incorporado sobre el gestor en esta última etapa se encuentra resaltado.

34
Diagrama 3.3 - Estructura de los controladores.

El gestor de Kinect no tiene ningún conocimiento de su entorno. Éste es simplemente


un proveedor de servicios a los controladores que lo necesiten. En una mirada
general, se puede decir que los controladores son los encargados de inicializar el
gestor, transformar los datos, y, una vez finalizada la ejecución, liberarlo.

Cada método de los controladores, heredados de IController, son en algún momento


llamados desde alguna vista. Previo a actualizar la interfaz de usuario, se recuperarán
los datos del modelo. La vista será desarrollada más adelante. A continuación se
procederá a explicar el modelo de datos.

3.1.2 Modelo

El modelo es el encargado de generar un objeto basado en las actualizaciones del


controlador que luego la vista pueda utilizar para actualizarse. En la Figura 3.14 se
muestra la comunicación necesaria entre los distintos componentes del sistema. En
esta sección se procederá a explicar sólo las relaciones que se encuentran resaltadas,
esto es, la relación con el controlador explicado en la sección anterior y la
comunicación general con cualquier tipo de vista.

35
Figura 3.14 - Comunicación entre los componentes del sistema.

Cualquier modelo creado deberá brindar a la vista un método que le devuelva un


objeto específico. Como el tipo de datos que necesita la vista depende de cada vista
específica y del contexto de la aplicación, el tipo devuelto por el modelo debe ser
genérico.

Para abstraer todo tipo de modelo, se creó la interfaz IModel que sólo contiene dos
métodos, update y getData. El primero se encarga de crear un objeto a partir de los
atributos actualizados por el controlador, para que luego pueda ser devuelto en el
segundo. getData devuelve un objeto de tipo object, que luego la vista sabrá entender.
Entonces, cada modelo creado deberá implementar a esta interfaz, e instanciar un
objeto específico a una vista y a un determinado contexto (Diagrama 3.4).

Diagrama 3.4 - Interfaz IModel con dos modelos de ejemplo.

Cada implementación de un modelo es específica a la funcionalidad deseada de cada


aplicación. Previo a poder crear el objeto de devolución, el modelo deberá tener todos
sus atributos actualizados por el controlador. Dependiendo del objetivo del modelo, se
encontrarán más o menos atributos a actualizar. Es posible que un modelo sólo

36
contenga un entero que indique la cantidad de personas, un punto indicando la
posición de una persona en específico, o también puede necesitar un arreglo de
posiciones. Las implementaciones de tres modelos diferentes se verán en la sección
3.2.

Por último, el controlador ejecuta el método update, en donde se crea el objeto


específico a la vista, o se realiza alguna otra acción según los datos previamente
establecidos. Este objeto será creado de diferentes maneras dependiendo del objetivo
final de cada aplicación.

El método getData se ejecuta constantemente por una vista. Cuando es llamado,


significa que el controlador ya actualizó el modelo. Es aquí donde se devuelve el
objeto específico que fue creado previamente en la actualización.

Los modelos tienen infinitas posibilidades sobre lo que se puede mostrar utilizando los
datos disponibles. En las siguientes secciones se mostrará cómo funcionan algunos
modelos, y los resultados obtenidos en el desarrollo de aplicaciones. La creación de
nuevos modelos para ser actualizados por un controlador de tipo KinectController es
muy sencilla.

En las imágenes que se muestran en la Figura 3.15, se ven 3 posibles


representaciones de los objetos que crean los modelos. En la primera imagen se ve el
uso de la posición general de cada esqueleto para mostrar una calavera por cada
jugador. Esto se puede lograr obteniendo las posiciones de todos los esqueletos.
También se puede generar un contador, por ejemplo, jugando con la cantidad de
esqueletos rastreados. Utilizando las posiciones de un esqueleto, se pueden mostrar
todas sus articulaciones. Y de esta manera, con el uso de la imaginación, se pueden
crear una cantidad infinita de aplicaciones.

Figura 3.15 - Posibles usos de los datos por el modelo

Como es el caso de los controladores y los modelos, las vistas también deben seguir
un formato. Afortunadamente, el diseño de la vista se dio de forma natural.

37
3.1.3 Vista

La vista es la encargada de mostrar a través de la interfaz gráfica lo que el usuario


debe ver, creando una representación del modelo con el que se interactúa mediante
un controlador. Su funcionalidad principal es la de recibir un objeto, como por ejemplo
un arreglo de colores, o simplemente un valor entero, crear un frame de acuerdo a
estos datos, y mostrarlo por pantalla (Figura 3.16). Pero eso no es todo. Para llegar a
ello, es necesaria cierta configuración y comunicación con los demás componentes.
Previo a obtener los datos del modelo, la vista debe indicar al controlador que lo
actualice. Por ende, es indispensable que contenga un atributo de tipo IController y
otro de tipo IModel.

Figura 3.16 - Comunicación necesaria entre la vista y el modelo.

Al iniciarse la aplicación, es necesario inicializar todos aquellos componentes de la


vista. Es posible establecer una imagen o un video de fondo, la resolución de la
pantalla, si se quiere o no en pantalla completa, o si se quiere mostrar o no el mouse,
entre otras opciones. Todas estas aplicaciones, en particular, son pantalla completa y
el mouse no está visible.

Una vez que se inicializó a ella misma, debe instanciar el controlador y el modelo con
tipos no abstractos de cada uno de ellos. Y ahora sí, debe inicializar el controlador a
través del load. Este método devuelve a la vista un boolean indicando si la carga se
realizó correctamente. Es posible que se intente inicializar y por ejemplo el dispositivo
Kinect no esté conectado. En estos casos, la vista se encarga de avisarle al usuario de
la situación y cerrar la aplicación (Figura 3.17).

38
Figura 3.17 - Secuencia de llamados para la inicialización

Hasta esta instancia se tiene una vista recientemente inicializada, que contiene un
controlador inicializado y un modelo de datos. Los recursos necesarios se encuentran
inicializados por el controlador. Queda un paso importante a realizar por la vista para
comenzar con la visualización.

El siguiente paso es dar comienzo a un evento que se produce constantemente en el


tiempo, un timer que su función es actualizar la vista. Dentro de este método disparado
en cada momento del tiempo, draw, la vista debe llamar al update del controlador.
Este método, como se mencionó en la sección anterior, transforma los datos crudos
para seguidamente actualizar al modelo. Luego, la vista debe llamar al método
getData del modelo. Dependiendo de la vista, la manera de crear el frame a mostrar y
la manera en dibujar sobre la pantalla varía (Figura 3.18).

Figura 3.18 - Secuencia de llamados para la actualización de la vista.

El método getData del modelo, devuelve un objeto genérico que la vista utilizará para
crear el objeto a mostrar. Como se verá en la sección de la instanciación de la
arquitectura, se utilizaron dos tipos de vistas, XNA y Windows Forms.

39
Estas vistas difieren en el tipo del objeto que muestran. Las vistas de XNA, por
ejemplo, utilizan una Texture2D que dibujan sobre pantalla. Windows Forms, con el
uso de la biblioteca Emgu CV, necesita de un Image<Bgr,byte>. Los datos recibidos
por el modelo pueden variar, por ejemplo entre un arreglo de colores para inicializar
una Texture2D, o un entero indicando la posición de un video para obtener un
Image<Bgr,byte>.

En algún momento, después de haber utilizado la aplicación el tiempo necesario, se va


a querer detenerla. La vista debe atrapar un evento que le permita identificar cuándo el
usuario desea cerrarla. En este caso en particular se usa la tecla escape. El método
llamado cuando se produce ese evento, es el que llama al último método del
controlador, unload. Recordando, el unload se encarga de liberar todos los recursos
utilizados (Figura 3.19).

Figura 3.19 - Secuencia de llamados para terminar la aplicación.

Concluyendo con el diseño de la vista, se puede poner un nombre formal a sus


métodos, dividiendo así correctamente su funcionalidad. El método de inicialización es
un load, que además de inicializar la vista, inicializa el controlador. A partir de ese
momento se dispara un evento constantemente, que llama al método draw de la vista,
dentro del cual se encuentra el update del controlador, el getData del modelo y la
creación del objeto que actualiza la pantalla. Por último, el evento de una tecla ejecuta
el método close, y justo antes de cerrar la aplicación, ejecuta el unload del controlador
(Diagrama 3.5).

Diagrama 3.5 - Incorporación de la vista al controlador y modelo.

40
En la siguiente sección se procederá a explicar la creación de las aplicaciones. Desde
el pensamiento que llevó a implementarlas, se las recorrerá a través de los primeros
pasos, y luego cómo fueron evolucionando hacia las versiones finales. No se dejará de
lado las diferencias y similitudes que hay entre todas ellas.

3.2 Diseño de cada aplicación

Como se mencionó en el capítulo de introducción, la idea es generar una plataforma


para el desarrollo de aplicaciones en el entretenimiento, específicamente para su uso
en museos. Para poder cumplir con el objetivo se fueron pensando aplicaciones para
ser implementadas y así instanciar la arquitectura que se explicó en la sección
anterior.

La instanciación de las aplicaciones se realizó con un fin específico, éstas serían


usadas en un museo de tenis. Se realizó un relevamiento de aplicaciones interactivas
en el contexto de museos y paseos. También se hizo una investigación sobre el uso
de la interactividad en el deporte. Los resultados obtenidos se encuentran a lo largo de
los capítulos uno, „Introducción‟ y 2, „Interactividad‟. Luego de observar diferentes
aplicaciones y de diferentes contextos se comenzó a pensar en aplicaciones
concretas.

A continuación se explicará el proceso que tuvo el desarrollo de cada aplicación. Se


podrán observar desde los primeros pasos y cómo fueron evolucionando para llegar al
objetivo. Se mostrará cómo fueron instanciados cada uno de los componentes de la
arquitectura y los detalles técnicos específicos de cada aplicación.

3.2.1 Reproductor de video

Para comenzar, se quería realizar algo que atraiga al público, dando un efecto
sorpresa. Es así que se pensó en la reproducción de un video. Con la incorporación de
Kinect generaría ese efecto sorpresa que se buscaba. Una persona de lejos, ve la
reproducción de un video en cámara lenta. Al acercarse, es decir, al entrar en el área
de captura del Kinect, el video comienza a responder a sus movimientos (Figura 3.20).

41
Figura 3.20 - Idea básica sobre el funcionamiento del Reproductor de Video

El objetivo final es implementar un reproductor de video que reproduzca de manera


constante un video en cámara lenta, y al pasar una persona por el frente de la
instalación, (dependiendo de la dirección) avance a una velocidad mayor o retroceda.
En la Figura 3.21 se intenta mostrar la idea en una secuencia de salto cuando no hay
movimientos y cuando hay movimientos hacia derecha e izquierda respectivamente.

Figura 3.21 - Acción de los movimientos


(a) Cámara lenta (b) Movimiento hacia derecha (c) Movimiento hacia izquierda

Durante su desarrollo, se pasó por varias etapas antes de llegar a la versión final.
Cada etapa incorpora algo de funcionalidad nueva. A lo largo de esta sección se
explicarán cada una de ellas. Lo que es común a todas las versiones, es el uso de los
datos.

42
Cómo sólo se va a utilizar la posición de una persona, es necesario habilitar los frames
de esqueletos, pero no los frames de profundidad. Para esta aplicación se va a utilizar
la funcionalidad para verificar si hay algún esqueleto rastreado para luego preguntar
por su posición.

3.2.1.1 Reproducción normal y hacia atrás

Al comenzar con el desarrollo se decidió implementar un caso sencillo para luego ir


profundizando sobre la reproducción. En este primer paso, se quiso reproducir el video
normalmente, y al detectar cualquier tipo de movimiento, comenzar con la
reproducción hacia atrás (Figura 3.22). Se decidió el uso de Windows Forms para la
vista y el uso de la biblioteca Emgu CV, para manipular el video a nivel de frames.

Figura 3.22 - Etapa 0 - Modos de reproducción de video de normal a hacia atrás.

VideoController es la clase que va a heredar de KinectController. El controlador, dentro


de sus métodos load() y unload(), sólo tendrá que inicializar y parar el gestor de Kinect
(Code snippet 3.5). Mientras que para actualizar en el método update(), se deberá
incorporar un modelo de datos como atributo privado.

public override bool load()


{
myModel = new VideoModel();
bool connected = kinect.initializeKinect();
if (connected)
{
kinect.enableSkeletonStream();
}
return connected;
}

public override bool unload()


{
kinect.stopKinect();
}
Code snippet 3.5 - Métodos de VideoController load y unload.

VideoModel es el modelo de datos que implementa a IModel. Por lo que corresponde a


esta fase primitiva de reproducción normal, el modelo no va a tomar acción. Luego, su

43
método update es el que va a ir variando a lo largo de las diferentes etapas, y es en
donde se va a ir inyectando de a poco la funcionalidad.

Al iniciar la aplicación se ejecuta su método load(). Se inicializa así la pantalla y a


todos sus componentes con los tamaños correspondientes, indicando que debe ser
pantalla completa y que el mouse no debe estar visible. Este tipo de pantallas no tiene
un timer previamente incluido, por lo que se le debe incorporar uno. Dentro del método
load(), se debe habilitar el timer para que se comience a ejecutar su propio método
draw().

Se va a comenzar por la reproducción del video normalmente. A través de la biblioteca


Emgu CV, se crea un objeto de tipo Emgu.CV.Capture dentro de la vista (Diagrama
3.6). Este objeto permite ir obteniendo el siguiente frame a reproducir a través de
video.QueryFrame() que devuelve el frame en formato Image< Bgr, Byte>.

Diagrama 3.6 - Incorporación del video a la vista

Como se mencionó, la vista que se utilizó es basada en Windows Forms. Por el


momento, el draw() de la vista crea el próximo frame a mostrar a través de
video.QueryFrame() (Figura 3.23). El componente que debe tener la vista para poder
reproducir el objeto obtenido por Emgu CV, es un ImageBox, también otorgado por la
misma biblioteca.

Figura 3.23 - Modo de reproducción normal.

44
Para incorporar la reproducción hacia atrás, primero hay que incorporar nuevos datos
al modelo: lastPosition y newPosition. El valor indicando la nueva posición es la que
será actualizada por el controlador y lastPosition será actualizado constantemente por
el modelo. Los valores de posiciones serán los determinantes del próximo frame a
reproducir. Un valor indicando la posición del video, actualFrame, es el que recibirá la
vista de getData de VideoModel (Diagrama 3.7).

Diagrama 3.7 - Clase VideoModel - Incorporación de atributos y métodos.

Para poder utilizar las variables recientemente incorporadas, se debió actualizar el


controlador. Dentro del método update, se consulta internamente si hay algún
esqueleto disponible. Esta información se obtiene a través del transformador
isSkeletonAvailable() que se encuentra implementado en KinectController.

Si este transformador devuelve falso, se debe establecer el valor de newPosition del


modelo con uno significativo, indicando la situación. Se decidió por un valor negativo, -
1. En el caso de que sea verdadero, entonces se accede al transformador
getFirstSkeletonPosition(). Teniendo en mente el objetivo final, el movimiento que se
toma en cuenta, es el horizontal, por lo tanto el valor seteado en newPosition es el
componente „X‟ del punto obtenido (Code snippet 3.6).

45
public override bool update()
{
if (isSkeletonAvailable())
{
Point newPosition = getFirstSkeletonPosition();
myModel.setNewPosition(newPosition.X);
}
else
{
myModel.setNewPosition(-1);
}
myModel.update();
}
Code snippet 3.6 - Código correspondiente al método update de VideoController.

Una vez actualizados los datos, se incorpora funcionalidad al método update de


VideoModel. Aquí se consulta por el valor newPosition. Si es un valor negativo,
significa que no hubo esqueleto rastreado, entonces se debe continuar con la
reproducción normal del video.

Si hay un esqueleto rastreado, entonces se debe consultar movimiento. El modelo


incorpora el método moved():boolean para controlarlo. Se toma en cuenta un valor
constante chico, y controla que el valor absoluto de la diferencia entre las dos
posiciones sea mayor que esa constante, en este caso fue usado el valor 5. Esto se
utiliza para eliminar ruido en los datos recibidos, y no interpretar que un esqueleto se
movió cuando en realidad estaba quieto.

| |
El dato es extraído de un archivo de configuración en XML [31] para facilitar su
modificación rápida sin la necesidad de recompilar el código. Como se verá más
adelante, se van a levantar algunos valores más, por lo tanto se creó una clase
singleton[32], Configuration, que está al alcance de cualquier elemento de la aplicación
(Diagrama 3.8).

Diagrama 3.8 - Comunicación del controlador con el Singleton Configuration.

46
El flujo de la actividad para este caso se puede ver en la Figura 3.24. Más adelante se
verá la necesidad de incorporar otro control más, ya que con el simple hecho de saber
si un esqueleto se movió no será suficiente.

Figura 3.24 - Flujo de actividad para la reproducción del video con control de movimiento.

Sólo queda determinar el próximo frame a mostrar una vez que se aseguró que existe
un esqueleto y que éste se movió. Para generar una reproducción hacia atrás se
utilizará otra funcionalidad brindada por Emgu CV. A través de
video.SetCaptureProperty(property, newValue), la biblioteca permite modificar los
valores de cualquier propiedad del video. El parámetro property debe ser un tipo de
CvEnum.CAP_PROP. Para poder manipular la posición del frame actual,
específicamente CV_CAP_PROP_POS_FRAMES. El segundo parámetro newValue
debe ser fijado con el valor del frame anterior al que se debe reproducir a
continuación.

public void draw()


{
myController.update();

double newPosition = (double)myModel.getData();

video.setCaptureProperty(CV_CAP_PROP_POS_FRAMES, newPosition);

imageBox.Image = video.QueryFrame();
}
Code snippet 3.7 - Cuerpo del método draw de la vista.

La vista por su parte, debe incorporar funcionalidad. Dentro de draw, se llama a


myController.update() e inmediatamente después se llama a myModel.getData(). Este

47
último método devuelve la nueva posición del video. A través de setCaptureProperty
explicado anteriormente, se establece la nueva propiedad obtenida. Al instante, la vista
ejecuta video.QueryFrame() para setear la imagen del ImageBox (Code snippet 3.7).

El cálculo del siguiente frame se computa a partir del frame actual. El atributo utilizado
es actualFrame, que comienza en 0 y se va actualizando a medida que se va
reproduciendo el video. FRAME es una constante inicializada con el número que
equivale a un frame, también extraída del archivo de configuración.

Hay que prestar atención al valor que multiplica a FRAME. Es necesario que
mínimamente sea un 2 ya que hay que tener en cuenta que el valor resultante es
utilizado para establecer la posición actual del video. Entonces, cuando se llame a
video.QueryFrame(), se va a obtener el frame que le sigue al actual (Figura 3.25). Más
adelante, en la versión final, se verá el uso de otros valores.

Figura 3.25 - Modo de reproducción hacia atrás

Cabe aclarar que el frame rate de la vista no es el mismo que el de Kinect. Es por eso
que el controlador será llamado algunas veces en los que los datos siguen siendo los
mismos. Es aquí en donde se utiliza la funcionalidad brindada por el gestor de Kinect
de reiniciar los datos guardados. Al comienzo del método se hace una consulta, así el
controlador sólo analiza los datos si, y sólo si, hay un nuevo frame para analizar.

La etapa 0 concluye con la reproducción del video normal, y en el caso de haber


movimiento la reproducción hacia atrás. Es momento de incorporar nuevos modos de
reproducción. Ahora, mientras no haya movimiento se quiere reproducir en cámara
lenta, y en caso contrario, reproducir a una velocidad mayor a la normal (Figura 3.26).

48
3.2.1.1 Reproducción cámara lenta y acelerada

Figura 3.26 - Etapa 1 - Modos de reproducción de video.

Para comenzar con la reproducción en cámara lenta se puede utilizar el timer de la


vista. Recordando, este timer es el encargado de llamar al método update(). En un
primer momento el timer está inicializado con su menor valor que es 1 ms. Si este
valor aumenta, la vista se va a actualizar más lento. Se debe encontrar un valor que
permita mostrar el video en cámara lenta sin que el usuario lo note y que también
funcione para la reproducción rápida. Luego de un par de pruebas, 50 ms parece ser
un tiempo correcto, invisible al usuario. Para que este valor pueda ser modificado en
cualquier momento, se incluyó en el archivo de configuración para luego ser
consultado en Configuration (Diagrama 3.9).

Diagrama 3.9 - Incorporación de nuevos atributos a Configuration y nueva comunicación con la


vista.

Con la manipulación del ritmo del timer, la reproducción en cámara lenta es


exactamente igual a la reproducción en modo normal. Del caso anterior, ya se tiene el
control del movimiento. Lo que se debe cambiar en este caso es el valor utilizado para
establecer la posición actual del video. De similar manera a la reproducción hacia
atrás, la idea para reproducir a una velocidad mayor es saltearse frames, avanzar
como se muestra en la imagen a continuación. La posición 2 no se muestra, y se pasa
directamente a la siguiente (Figura 3.27).

49
Figura 3.27 - Modo de reproducción acelerado.

La cantidad de frames que se avanzan determinan la velocidad de reproducción.


Como se viene de una reproducción en cámara lenta, con aumentar un sólo frame no
es suficiente. En este punto se decidió calcular el próximo frame salteándose dos en el
medio, es decir aumentar de a tres frames como se puede ver en la siguiente función.
En el último caso se muestra el uso de otros valores para este modo de reproducción.

3.2.1.3 Unificación de estados de reproducción

Para generar una aproximación al objetivo final, el próximo paso fue unificar los dos
casos anteriores en uno, así se da la posibilidad de manipular un video de tres
maneras diferentes: hacia atrás, en cámara lenta, o acelerado. Evitando tener
complejidad en el análisis de la posición del jugador, se optó por dividir el área del
juego a la mitad. En efecto, si el jugador se mueve del lado derecho, el video se
reproduce en modo acelerado; si el jugador se mueve del lado izquierdo, el video se
reproduce en reversa; y, por último, si el jugador no se mueve, el video se reproduce
en cámara lenta (Diagrama 3.10).

50
Diagrama 3.10 - Etapa 2 - Interacción entre los modos de reproducción.

En esta etapa previa a la final, se debe incorporar una nueva condición. Luego de
determinar si la persona se movió, se consulta por la posición. Primero se toma un
valor que determina la mitad del área de juego. Si la posición horizontal (X) actual del
esqueleto es menor a éste valor, significa que se movió del lado izquierdo,
estableciendo como nuevo estado BACKWARDS. En caso contrario, se produjo un
movimiento del lado derecho, pasando al estado FAST FORWARD. Según los
distintos estados se utiliza el cálculo del próximo frame como se utilizó en las etapas
anteriores del desarrollo.

Este pensamiento llevó a implementar la clase VideoModel como una máquina de


estados[33], actualizando el siguiente frame a mostrar según el frame actual y el estado
actual del movimiento del jugador. De esta manera, cuando se decidió incorporar una
lógica más compleja, la reproducción del video era la misma, sólo debía cambiar la
lógica de la transición de estados. El método update se dividió en 2 métodos
separados (Code snippet 3.8).

public void update()


{
updateState();
updateActualFrame();
}
Code snippet 3.8 - Implementación de update como una máquina de estados.

Por un lado se debe actualizar el estado. El método updateState es el que debe variar
cuando se quiere cambiar la lógica del cambio de estados. Más adelante se mostrará
su versión final en Code snippet 3.10.

51
Una vez que se conoce el estado actual, el cálculo del próximo frame es el mismo. La
funcionalidad se engloba dentro de updateActualFrame (Code snippet 3.9). Durante
el desarrollo del reproductor del video, se encontró con un problema. Al estar en el
estado BACKWARDS, y en el frame 0, era imposible recuperar el próximo frame. Lo
mismo pasaba cuando el estado era SLOW_MOTION o FASTFORWARD y se
encontraba en el último frame. Este problema se solucionó incorporando un control
que se puede ver reflejado en este método.

Hay dos casos posibles, querer acceder a un frame negativo, o acceder a un frame
mayor a finalFrame. finalFrame es un atributo que se incorporó al modelo con el
objetivo de este control. Si se trata del caso de un frame negativo, habría que
establecer un número de frame anterior a finalFrame. Por el contrario, si ya se llegó al
final, es necesario volver al comienzo del video, estableciendo el frame actual a 0.

public void updateActualFrame()


{
//Actualización de actualFrame
if (state != SLOW_MOTION)
{
if (state == BACKWARDS)
{
actualFrame -= FRAME * 2;
}
else
{
actualFrame += FRAME * 3;
}
}
else
{
actualFrame += FRAME;
}

//Ajuste de actualFrame en caso de fuera de rango


if (actualFrame < 0)
{
actualFrame = finalFrame - FRAME * 5;
}
if (actualFrame > finalFrame)
{
actualFrame = 0;
}
}
Code snippet 3.9 - Implementación del método updateActualFrame() utilizado por update().

Finalmente se puede llegar al objetivo final sin mayores cambios. Inicialmente estando
en el estado SLOW MOTION, el siguiente estado va a depender de la dirección en la
cual se mueva. La dirección se determina haciendo una comparación entre la posición
horizontal recientemente actualizada por el controlador, y la posición anterior guardada

52
por el modelo. Si la nueva posición es menor que la posición guardada, significa que la
persona se movió hacia la izquierda, en cambio si la posición nueva es mayor que la
posición guardada, la persona se movió hacia la derecha.

En el Code snippet 3.10 se puede ver la lógica del cambio de estados final. Si no hay
esqueleto disponible traqueado o si hay un esqueleto pero éste no se movió, el estado
pasa a SLOW_MOTION.

public void updateState()


{
if (newPosition > 0)
{
if (moved())
{
if (newPosition < lastPosition)
{
state = VideoModel.BACKWARDS;
}
else
{
state = VideoModel.FAST_FORWARD;
}

setVideoSpeed(Math.Abs(lastPosition - newPosition));

lastPosition = newPosition;
}
}
else
{
state = VideoModel.SLOW_MOTION;
}
}
Code snippet 3.10 - Método updateState().

En el Code snippet 3.10 se puede ver el uso de una función interna setVideoSpeed().
Una vez que la máquina de estados funcionó como se esperaba, se incorporó también
la velocidad como un dato adicional a tener en cuenta a la hora de calcular el próximo
frame a mostrar. Entonces, el jugador no sólo maneja la dirección del video, sino que
también la velocidad. Este efecto hace que pareciera que el video está siguiendo a la
persona. Esta vez, el cálculo de velocidad se realiza con la diferencia entre la posición
actual y la posición anterior del jugador, sólo que el valor que se toma en cuenta es el
valor absoluto. Cuanta más grande sea la diferencia, más grande será la velocidad.

Es aquí en donde entra en juego la cantidad de frames a adelantar o atrasar. Los


cálculos utilizados para computar el próximo frame en las etapas anteriores deben
comenzar a tomar en cuenta la velocidad. La reproducción hacia atrás, además de

53
multiplicar por 2 el frame, también multiplicará por la velocidad. La reproducción
acelerada no multiplicará más por una constante, y sólo multiplicará por la velocidad.
De esta manera, si la persona se mueve lo suficientemente lento, la reproducción es
en modo normal.

Backwards:

Fast forward:

Para controlar la velocidad se utilizaron valores máximos y mínimos. Luego de varias


pruebas se detectó que la velocidad no superaba el valor 10. Y por límite mínimo se
puso 2 porque dio mejores resultados que permitir que la velocidad fuera simplemente
1, por las razones explicadas en los párrafos anteriores. De cualquier manera, estos
valores también fueron incorporados a configuration.xml para ser modificados en
cualquier momento.

El Code snippet 3.11 muestra una versión del documento de configuración.

<Configuration>
<!--Velocidad mínima-->
<MinSpeed>2</MinSpeed>

<!--Velocidad máxima-->
<MaxSpeed>10</MaxSpeed>

<!--Valor que determina el próximo frame-->


<NextFrame>2002</NextFrame>

<!--Movimiento insignificante
Al disminuir, aumenta la sensibilidad de movimiento-->
<InsignificantMovement>5</InsignificantMovement>

<!--Intervalo para actualizar la pantalla.


Cuando más alto, más lento se reproduce el video-->
<TimerInterval>50</TimerInterval>
</Configuration>
Code snippet 3.11 - Versión final del archivo configuration.xml

Habiendo logrado toda esta funcionalidad, se puede decir que se terminó con la etapa
final. El video responde a la dirección de los jugadores, y también a la velocidad en la
que se movieron. Se utilizó la arquitectura explicada previamente, utilizando el
controlador abstracto KinectController y la interfaz de modelo IModel. De todos los
transformadores implementados, sólo se utilizaron unos pocos, que fueron los
necesarios para este desarrollo.

El Diagrama 3.11 muestra el diagrama de clases de la aplicación en cuestión,


mostrando claramente la división entre Model-View-Controller. En éste se puede ver

54
cómo la vista que contiene un modelo y un controlador, no tiene ningún conocimiento
de la fuente del controlador, en este caso KinectDevice, y el controlador que tiene un
modelo, no necesita saber nada de la vista. El modelo sólo necesita conocer el objeto
que necesita la vista para poder instanciarlo y devolverlo cuando es pedido.

Diagrama 3.11 - Diagrama de clases de la aplicación del reproductor de video.

3.2.2 Hinchada

Luego de finalizada la primera aplicación, se comenzó con una nueva idea,


alcanzando al público desde otro ángulo. Teniendo en mente la especificación del
deporte, se decidió realizar una hinchada virtual. Para ello, se pensó en generar la
sensación de aliento en el público. Como ocurre en la vida real, en cualquier ambiente
deportivo, cuanta más gente haya, mayor es la hinchada. Y entonces, para simular la
realidad, se optó por estimular el sentido auditivo al reproducir sonidos.

El efecto que se busca es que a medida que se sume gente, se reproduzcan más
sonidos y se genere una gran hinchada. Si sólo hay una persona, se reproduce, por
ejemplo, una multitud hablando. Al sumarse otra persona, se reproducen palmas, y

55
luego gritos, bombos, etc. En la Figura 3.28 se intenta demostrar la intensidad de los
sonidos reproducidos con respecto a la cantidad de gente y sus movimientos.

Figura 3.28 - Intensidad de sonidos de acuerdo a la cantidad de personas y sus movimientos.

No se debe dejar de lado la generalidad. El fin de este proyecto es la interactividad en


cualquier tipo de museo o paseo. En consecuencia, los sonidos reproducidos deben
ser modificados fácilmente y así adecuar la aplicación para su uso en cualquier otro
contexto.

Figura 3.29 - Parte visual de la aplicación Hinchada.

Para complementar la reproducción de audio, es necesario que se reproduzca un


soporte visual. Las personas que lo utilizan deben apreciarlo también a través de los
ojos. Lo que se pensó fue reproducir un video, sin audio para no interferir con el
objetivo, y sobre el video dibujar a las personas en colores sólidos, replicando así sus
figuras y poses (Figura 3.29). Para continuar con la temática, se eligió un video en

56
donde se muestra una hinchada de un partido de tenis. Nuevamente, este video debe
ser modificado fácilmente para mantener la usabilidad y el alcance.

Esta sección contiene la explicación del desarrollo de la segunda aplicación. El ciclo se


dividió en 3 pequeñas etapas. En un principio, se trata de la reproducción de un sonido
en loop, esto es, que una vez que comience a reproducir, nunca pare hasta obtener
una orden indicando lo contrario. Una vez que se logró reproducir un audio, el
siguiente paso fue incorporar varios sonidos a la vez, también en loop. Por último, sólo
quedó incorporar el dinamismo de la cantidad de sonidos reproducidos.

3.2.2.1 Reproducción de un sonido

Figura 3.30 - Reproducción sin fin de un audio.

La reproducción de un único audio en loop (Figura 3.30), resultó trivial en un principio.


El sistema provee un namespace, System.Media, que contiene clases para la
reproducción de archivos de sonido. Sólo fue necesario crear un objeto
System.Media.SoundPlayer[34] en el modelo, indicándole por parámetro el path del
audio que se quiere reproducir. Luego, a través del método
soundPlayer.PlayLooping(), se reproduce automáticamente. También contiene el
método Stop() para poder finalizar la reproducción. Más adelante se verá cómo se
incorporó un archivo XML para levantar cualquier audio.

Teniendo en mente el objetivo visual de la aplicación, se decidió utilizar una vista XNA.
Durante esta fase, no es necesaria la recepción de datos del modelo de datos, ya que
no se va a mostrar ningún objeto. Sin embargo, la reproducción del sonido se realiza
dentro del método update del modelo, PlayersModel. Al finalizar, antes de cerrar la
aplicación se llama al método Stop() del reproductor de audio, cuando
PlayersController se lo indica al modelo desde el unload.

57
3.2.2.2 Reproducción múltiple

Figura 3.31 - Reproducción sin fin de múltiples audios.

La siguiente etapa involucra varios sonidos (Figura 3.31). Por este motivo se decidió
crear una clase singleton AudioManager, que contenga una lista de audios, y que se
encargue de la comunicación directa con los objetos de audio. Esta clase se basa en
sólo 3 métodos, load(), play(int track) y stop(int track).

Dentro del método load se carga una lista de sonidos. Luego, a través de los métodos
play y stop, reproduce y para de reproducir el sonido dependiendo del número que
recibe por parámetro. Este número indica la posición en la lista, que siempre mantiene
el mismo orden.

La cantidad de sonidos a reproducir está determinada por un contador. Se incorporó


una nueva funcionalidad a PlayersModel que se encargue de la reproducción de
audios a través de AudioManager. El modelo mantiene ahora un contador, que irá
aumentando en uno cada una determinada cantidad de tiempo, y una vez que se
llegue al máximo de sonidos, disminuirá hasta llegar a 0. Se podría decir que esto es
una demo de la reproducción en simultáneo. La verdadera funcionalidad se verá en la
siguiente etapa.

Para la manipulación de los sonidos, fue necesario incorporar nuevos métodos al


modelo. El primero es el de inicialización, loadAudio, en donde se encarga de
inicializar a AudioManager. Luego, tiene el método de actualización, updateAudio,
que será llamado desde su propio update. Llegado este punto, todos los audios están
cargados, por lo tanto, el modelo debe recorrer todos los valores del 0 al contador,

58
ejecutando play, y desde el contador hasta que se llegue a la cantidad de sonidos
disponibles, ejecutar stop (Diagrama 3.12).

Diagrama 3.12 - Relación entre PlayersModel y AudioManager.

En este momento se presentó un inconveniente. La reproducción a través de la clase


SoundPlayer que brinda el namespace System.Media es a muy bajo nivel y no permite
la reproducción de más de un sonido a la vez. Lo próximo que se encontró, fue otro
namespace del sistema, System.Windows.Media, que brinda una clase
MediaPlayer[35]. Este objeto, permite la reproducción de varios sonidos a la vez, pero
no tiene la funcionalidad de reproducir en modo loop. Nuevamente, la manipulación de
los audios es a muy bajo nivel, por lo que se decidió buscar una biblioteca externa que
tenga la funcionalidad necesaria para alcanzar el objetivo.

Luego de investigar sobre diferentes bibliotecas, se decidió por FMOD. Es un motor de


efectos de sonido para videojuegos y aplicaciones, que reproduce y mezcla archivos
de sonido de diversos formatos en muchos sistemas operativos. Esta biblioteca está
hecha en c++, pero existe un wrapper hecho especialmente para c#. Se modificó la
clase AudioManager para incorporar ahora el uso de esta biblioteca.

Diagrama 3.13 - Clase AudioManager incorporando atributos específicos a la biblioteca FMOD

AudioManager ya contenía una lista de sonidos, pero ahora cambiará el tipo a


FMOD.Sound. La biblioteca en cuestión, brinda un objeto de tipo Channel, que permite
la manipulación de un sonido en tiempo de ejecución. Se debe crear un Channel por
cada sonido que se quiere reproducir. Se incorpora una Hashtable que guarda este

59
tipo de objetos y como clave se utiliza un entero que indica la posición de un sonido en
la lista (Diagrama 3.13). A través de los canales se puede incorporar también los
efectos de fade in y fade out.

El tipo de vista utilizado ya contiene un timer que se encarga de ejecutar el método


draw() de la vista. Más adelante se entrará en detalle sobre la elección de la vista y su
funcionamiento. Como en cualquier vista, dentro de draw, se llama al update del
controlador y luego al getData del modelo. A lo largo de esta etapa, este último
método no devuelve datos para mostrar, la aplicación se centra sólo en la
reproducción de audio.

Figura 3.32 - Secuencia de llamados para gestionar audios.

En la Figura 3.32 se puede ver la secuencia de llamados entre el controlador, el


modelo y el gestor de audios. Recordando la etapa presente, PlayersModel mantiene
un contador, que va actualizando cada un determinado tiempo, para luego llamar a los
métodos play y stop de AudioManager.

Dentro de play, se controla que la canción no se esté reproduciendo. Una vez


obtenido el sonido, se crea un canal por el cual se reproduce. La reproducción
comienza pausada, para luego realizar un efecto fade in, es decir, llevar de volumen 0
a máximo en una cantidad determinada de segundos. El canal es guardado en
channels con su clave correspondiente al número de sonido para luego poder
accederlo (Code snippet 3.12).

60
public void play(int track)
{
if (!channels.ContainsKey(track))
{
Sound sound = sounds.ElementAt(track);

Channel channel;
//Reproducción comienza en pausa = true
system.playSound(sound, true, channel);

channels.Add(track, channel);

fadeIn(channel);
}
}
Code snippet 3.12 - Cuerpo del método play utilizando la biblioteca FMOD.

Al ejecutarse el método stop, se obtiene el canal correspondiente. Se busca en


channels a través del número de sonido. Si el canal existe, realiza un fade out para
parar con la reproducción. El efecto utilizado lleva el volumen de máximo a 0 en una
determinada cantidad de segundos. Por último, se elimina el canal de la estructura
(Code snippet 3.13).

public void stop(int track)


{
Channel channel = (Channel)channels[track];
if (channel != null)
{
fadeOut(channel);
channels.Remove(track);
}
}
Code snippet 3.13 - Cuerpo del método stop utilizando la biblioteca FMOD.

3.2.2.3 Reproducción dinámica

El siguiente paso natural, es manipular este contador dependiendo de los datos


obtenidos del gestor de Kinect. Por tal motivo, es necesario modificar el update de
PlayersController. El controlador va a utilizar el transformador para saber la cantidad
de personas que se encuentran en el área de juego, getTotalSkeletons(), previamente
habilitando el flujo de datos para los frames de esqueletos.

En esta etapa se encontró una limitación, ya que el dispositivo Kinect sólo puede
llevarle el rastro a 6 esqueletos. Este número es muy pequeño para poder apreciar el
crecimiento de los sonidos, ya que sólo 6 pistas podrían ser reproducidas, y limita las
opciones de entretenimiento. Para poder incorporar más sonidos, se decidió tomar en
cuenta el movimiento vertical de las personas, para incentivar movimientos de los

61
brazos hacia arriba y saltos. Ahora, la hinchada, es decir, la reproducción de sonidos,
crece también por el movimiento, y no sólo por la cantidad. Un público inquieto hace
que la hinchada aumente y es una manera entretenida de alentar.

public override void update()


{
myModel.setAudioCounter(getAudioCounter());

myModel.update();
}

private int getAudioCounter()


{
//Cantidad de esqueletos detectados
int count = getTotalSkeletons();

//Cantidad de esqueletos en movimiento


Point[] positions = getSkeletonPositions();
for (int i = 0; i < positions.Length; i++)
{
if (validPosition(positions[i]))
{
if (moved(positions[i], lastPositions[i]))
count++;
}
}

return count;
}
Code snippet 3.14 - Cuerpo del método update de PlayersController junto al transformador
privado getAudioCounter.

PlayersController deberá incorporar un nuevo transformador para determinar la


cantidad de esqueletos sumado a la cantidad de esqueletos en movimiento (Diagrama
3.14). Para ello, no sólo es necesario saber la cantidad de esqueletos traqueados, sino
que también se debe saber sus posiciones, las cuales se obtienen a través del método
getSkeletonPositions(). A partir de esos datos se desprende la cantidad de sonidos
que se deben reproducir y se lo establece al modelo previo a realizar myModel.update
(Code snippet 3.14).

Por su parte, el modelo se comunica con AudioManager de la manera más eficiente.


Tomando en cuenta el valor anterior con el que fue llamado, PlayersModel puede
saber qué sonidos se están reproduciendo en el momento. Por lo tanto, al ejecutarse
updateAudio con un nuevo valor, se pueden dar 3 opciones.

62
Diagrama 3.14 - Clase PlayersModel que mantiene el último contador con el que fue
actualizado.

En un primer lugar, el nuevo valor de cantidad de personas puede ser mayor que el
valor anterior. En este caso que se ve reflejado en la Figura 3.33, se debe ejecutar el
método play para todos aquellos audios que se encuentren en una posición entre el
contador mantenido por el modelo, y la cantidad de personas que le indica
PlayersController.

Figura 3.33 - Representación de sonidos reproducidos en verde, y no reproducidos en rojo.


Variación en crecimiento de sonidos a reproducir.

Luego, se puede dar que el nuevo valor sea menor que la cantidad de sonidos
reproducidos, como se ve en la Figura 3.34. Por lo tanto se deben parar de reproducir
aquellos sonidos que se encuentran en el rango correspondiente.

Figura 3.34 - Representación de sonidos reproducidos en verde, y no reproducidos en rojo.


Variación en disminución de sonidos a reproducir.

63
Por último, los valores pueden ser iguales (Figura 3.35). De esta manera, no se
produce ningún cambio, y se evita la comunicación innecesaria con AudioManager.

Figura 3.35 - Representación de sonidos reproducidos en verde, y no reproducidos en rojo. Sin


variación de sonidos a reproducir.

3.2.2.4 Carga de sonidos

Para mantener la generalidad del proyecto, es necesario que los archivos de audio
sean levantados dinámicamente. Desde el comienzo se decidió utilizar un archivo
XML, Audios.xml (Code snippet 3.15), que contenga una lista de audios que luego
serán levantados desde AudioManager dentro de load.

<Table>
<Audio>/Audio/1.Aplausos.wav</Audio>
<Audio>/Audio/2.Animos.wav</Audio>
<Audio>/Audio/3.Publico.wav</Audio>
<Audio>/Audio/4.GranAplauso.wav</Audio>
<Audio>/Audio/5.Rebelion.wav</Audio>
<Audio>/Audio/6.MarchaMilitar.wav</Audio>
</Table>
Code snippet 3.15 - Ruta de los archivos de audio dentro de Audios.xml

A la hora de reproducir, el orden de los sonidos es importante. Los distintos sonidos


mantienen el orden con el cual fueron levantados del archivo XML. Por eso, el modelo
tiene la capacidad de manipular la reproducción sólo con la posición. En este caso en
particular de una hinchada, es ideal que los audios se ordenen de más suaves a más
intensos, para potenciar el efecto.

3.2.2.5 Interfaz gráfica

Tal como se nombró anteriormente, para el desarrollo de la interfaz gráfica se decidió


realizar un proyecto XNA. Éste es un conjunto de herramientas de software gratuito
proporcionado por Microsoft que facilita el desarrollo y la gestión de los videojuegos.
De esta manera, la manipulación de la vista es muy sencilla.

64
Al comienzo de la aplicación, la vista, además de inicializar el controlador, comienza a
reproducir el video en loop y sin audio. XNA brinda este servicio sin más dificultades
como se puede ver en el Code snippet 3.16[36].

private void load()


{

Video myVideoFile = Content.Load<Video>(“Videos\\” + videoName);

videoPlayer.IsLooped = true;
videoPlayer.IsMuted = true;

videoPlayer.Play(myVideoFile);
...
}
Code snippet 3.16 - Porción del cuerpo del método load de la vista relacionado a la
reproducción de video de fondo.

Luego, en cada momento del tiempo, ejecuta el método update del controlador e
inmediatamente el getData del modelo. En esta ocasión, el tipo de datos obtenido es
un arreglo de colores. Por lo tanto, el siguiente paso es crear una Texture2D, y
establecerle los colores que se recibieron (Code snippet 3.17).

Una vez creada la textura, la vista la debe mostrar. Como se desea mostrar las
siluetas de las personas por encima, primero se dibuja el siguiente frame del video, y
luego la textura recientemente creada. En aquellos píxeles que tienen un color
transparente, se podrá percibir el video de fondo.

private void draw()


{
spriteBatch.Begin();

//Dibujo del video


spriteBatch.Draw(videoPlayer.GetTexture(), fullscreen);

//Dibujo de las siluetas


if (connected)
{
myController.update();
Color[] colors = (Color[])myModel.getData();
if (colors != null)
{
Texture2D texture = new Texture2D(graphics);
texture.SetData(colors);
spriteBatch.Draw(texture, fullscreen);
}
}
spriteBatch.End();
}
Code snippet 3.17 - Cuerpo del método draw al dibujar siluetas sobre el video.

65
Para llevar a cabo el dibujo de las personas en la pantalla, es necesario incluir datos al
modelo que se destacan en el Diagrama 3.15. Un arreglo de enteros, que representa
un frame, indica los id de los jugadores. También es necesario incluir un color por cada
id de jugador, con el fin de poder colorear a cada uno de ellos con un color diferente.
colors es una estructura Hash que como clave contiene los id de los jugadores y como
valor un objeto de tipo Color. Como se mencionó anteriormente, el máximo de
jugadores es 6. Esto limita los valores que pueden tomar los id, donde sus valores
posibles son del 1 al 6.

Diagrama 3.15 - Clase PlayersModel - Incorporación de atributos y métodos.

La creación del arreglo de colores es muy sencilla. Se recorre el arreglo de id de


jugadores, donde un valor mayor a 0 indica la identificación de un jugador. En caso en
el que el valor sea 0, significa que en esa posición no se encuentra ninguna persona.
Al inicializar un arreglo de objetos de tipo Color, los valores iniciales indican un color
transparente, por lo tanto sólo es necesario modificar aquellas posiciones en donde se
encuentre algún jugador. El color establecido se obtiene de la estructura colors a
través de su identificador (Ver representación en Figura 3.36).

66
Figura 3.36 - Establecimiento de colores con respecto a los identificadores de los jugadores.

El controlador deberá ser actualizado para su comunicación con PlayersModel. Dentro


del load se incorporará la habilitación de los frames de profundidad, para poder
acceder a los datos luego. Como el atributo colors del modelo no es dinámico, sus
valores se establecen junto con la inicialización. Para determinar los colores utilizados,
es conveniente crear un gestor de colores.

ColorManager es un recurso singleton que entra en juego a la hora de dibujar a las


personas (Diagrama 3.16). Se compone de dos métodos: load y getNewColor. El
controlador es el encargado de la inicialización. Aquí, el gestor de colores levanta de
un archivo XML una cantidad de colores. Es indispensable que la cantidad cargada en
ese archivo sea mayor o igual a 6, así quedan cubiertos todos los jugadores.

Diagrama 3.16 - Clase ColorManager utilizada por PlayersController

PlayersController, luego de ejecutar el load sobre ColorManager, comienza a


seleccionar colores. Dentro de getNewColor, el gestor de colores selecciona un color

67
al azar de su lista, y previamente a retornarlo, controla que no esté siendo usado a
través una lista de booleanos. Una vez obtenidos los colores necesarios, actualiza al
modelo a través de setColors (Code snippet 3.18).

public override bool load()


{
myModel = new PlayersModel();
bool connected = kinect.initializeKinect();
if (connected)
{
//Habilitación de flujo de datos
kinect.enableSkeletonStream();
kinect.enableDepthStream();

//Inicialización de gestor de colores


ColorManager.getInstance().load();

//Inicialización del modelo


myModel.setColors(getColors());
myModel.loadAudio();
}
return connected;
}
Code snippet 3.18 - Cuerpo del método load del controlador.

Por último, el método update del controlador debe incorporar el establecimiento de


playersId del modelo. Como se ve en el Code snippet 3.19, el transformador que se
encarga de obtener los id de los jugadores es getPlayersId implementado en
KinectController.

public override void update()


{
myModel.setAudioCounter(getAudioCounter());
myModel.setPlayersId(getPlayersId());

myModel.update();
}
Code snippet 3.19 - Cuerpo del método update del controlador actualizado.

La arquitectura final de la aplicación sigue la estructura general. El modelo implementa


IModel, y a diferencia del reproductor de video, genera un arreglo de colores para
devolver a la vista. El controlador hereda de KinectController, se encarga de inicializar
a todos los recursos, los cuales son KinectDevice, ColorManager y los audios del
modelo. La actualización llevada a cabo por el controlador en cada momento del
tiempo hace efecto sobre el modelo. Ésta involucra algunos transformadores
implementados en KinectController, y se incorporó uno nuevo para contar esqueletos
en movimiento.

68
3.2.3 Descubrir la imagen

Para finalizar el desarrollo, se pensó necesaria la demostración de la simplicidad de


uso de la plataforma, creando una nueva aplicación, teniendo la estructura ya armada
y aplicaciones de ejemplo. Sin embargo, es necesario que la funcionalidad sea
distinta. Se quiso realizar algún tipo de interacción pensando más en el público infantil.
Algo que pueda sostener la atención de los más pequeños por un período de tiempo
más prolongado.

Utilizando el cuerpo y sus movimientos, se debe descubrir una imagen. Inicialmente


tapada, de fondo se encuentra una imagen relacionada al tema en cuestión.
Específicamente para el museo de tenis se optó por una imagen del jugador Del Potro
en el medio de una jugada. Se debe poder modificar esta imagen fácilmente, para
poder utilizar la aplicación en cualquier otro tipo de museo o paseo.

Figura 3.37 - Idea básica sobre el funcionamiento de ‘Descubrir la imagen’

Cada niño va a ayudar a destapar la imagen. Los movimientos de sus cuerpos irán
despintando el cobertor, con la necesidad de moverse por el espacio y saltar para
llegar a aquellos lugares inalcanzables de otra manera. Pero para mantener
incentivados a los más pequeños, la imagen se irá volviendo a tapar cuando no haya
movimientos (Figura 3.37).

69
De manera contraria a la aplicación anterior en donde la imagen de la persona tapaba
el video, ahora el jugador con su cuerpo tiene la función de despintar. El desarrollo se
realizó en 3 etapas. En primer lugar, se buscó mostrar la imagen de fondo sólo en
aquellos lugares en donde se encuentren las personas modificándose en cada
momento del tiempo. Luego, se incorpora la memoria, es decir, mantener despintados
aquellos píxeles que fueron tocados alguna vez por algún jugador. Por último se
incorporó el recubrimiento de la imagen junto con un pequeño efecto visual.

3.2.3.1 Descubrimiento sin memoria

La primera etapa se puede decir que es exactamente contraria al dibujo de siluetas de


la aplicación anterior. La vista dibuja una imagen y por encima una textura en donde
los píxeles transparentes representan a los jugadores y dejan ver la imagen de fondo
(Code snippet 3.20).

private void draw()


{
spriteBatch.Begin();

//Dibujo de la imagen de fondo


spriteBatch.Draw(background, fullscreen);

//Dibujo de siluetas transparentes


if (connected)
{
myController.update();
Color[] colors = (Color[])myModel.getData();
if (colors != null)
{
Texture2D texture = new Texture2D(graphics);
texture.SetData(colors);
spriteBatch.Draw(texture, fullscreen);
}
}

spriteBatch.End();
}
Code snippet 3.20 - Cuerpo del método draw de la vista al dibujar textura sobre imagen de
fondo.

El modelo de datos que se puede ver en el Diagrama 3.17, DiscoveryModel, no


necesita saber los identificadores de los jugadores. Con sólo saber si hay o no un
jugador en cada píxel específico, es suficiente. Por lo tanto, mantiene un arreglo de
booleanos que el controlador deberá actualizar a través de setPlayersOnPixels. Otro
dato necesario es un color para pintar aquellos píxeles en donde no hay jugador. Este
dato no es dinámico, por lo que el controlador lo inicializa una única vez.

70
Diagrama 3.17 - Clase DiscoveryModel con sus atributos iniciales.

El objeto de retorno, como en el caso anterior, es un arreglo de colores. El modelo


recorre el arreglo playersOnPixels, y en el caso de contener un valor verdadero,
significa que hay un jugador, y establece ese color como transparente. En caso
contrario, cuando el valor es falso, el color del píxel es el color que fue establecido por
el controlador, color. Esta lógica se puede encontrar en el Code snippet 3.21.

public void update()


{
for (int x = 0; x < playersOnPixels.Length; x++)
{
if (playersOnPixels[x])
{
//Hay jugador, despinto
discoveryArray[x] = Color.Transparent;
}
else
{
//No hay jugador, pinto
discoveryArray[x] = color;
}
}
}
Code snippet 3.21 - Cuerpo método update del modelo.

El controlador, DiscoveryController, por su cuenta debe actualizar todos los datos


necesitados por el modelo. Dentro de su inicialización, da comienzo al recurso Kinect,
y al momento habilita los frames de esqueletos y de profundidad. Como se nombró
anteriormente, el modelo necesita un color, por lo que también es necesaria la
inicialización de un gestor de colores previamente a establecerle uno al modelo (Code
snippet 3.22).

71
public override bool load()
{
myModel = new DiscoveryModel();
bool connected = kinect.initializeKinect();
if (connected)
{
//Habilitación de flujo de datos
kinect.enableSkeletonStream();
kinect.enableDepthStream();

//Inicialización de gestor de colores


ColorManager.getInstance().load();

//Inicialización del modelo


Color color = ColorManager.getInstance().getColor();
myModel.setColor(color);
}
return connected;
}
Code snippet 3.22 - Cuerpo del método load del controlador.

En la aplicación anterior ya se utilizó ColorManager. En este caso en particular, no es


necesario controlar si el color fue usado o no, por lo tanto se incorporó un nuevo
método a su clase (Diagrama 3.18). getColor devuelve un color al azar sin tener en
cuenta el arreglo de booleanos. Como se mantiene la misma clase, la inicialización
continúa siendo la misma, levantando los colores de un archivo XML dentro de su
método load.

Diagrama 3.18 - Clase ColorManager actualizado para retornar color sin controlar su uso.

A la hora de la actualización, se debe actualizar el arreglo playersOnPixels del modelo.


DiscoveryController utiliza el transformador isPlayerOnPixel implementado en
KinectController, el cual fue explicado en la sección 3.1.1 (Code snippet 3.23).

public override void update()


{
myModel.setPlayersOnPixels(isPlayerOnPixel());

myModel.update();
}
Code snippet 3.23 - Cuerpo del método update del controlador.

72
El resultado obtenido logró mostrar la imagen de fondo sólo en aquellos lugares en
donde se encuentren las personas. El siguiente paso involucra mantener en memoria
todos aquellos píxeles que alguna vez fueron tocados.

3.2.3.2 Descubrimiento con memoria

Como se puede ver en el Code snippet 3.21, el método update del modelo, en cada
momento del tiempo se inicializan todos los píxeles. Aquellos que tienen un jugador en
transparente, y aquellos que no, con un color predeterminado. La solución tomada en
esta segunda etapa fue inicializar el arreglo discoveryArray desde un principio todo de
un sólo color. Luego, cuando update es llamado por el controlador, sólo se consulta
por los píxeles en donde hay jugadores, en ese caso poniendo el color transparente
(Figura 3.38).

Figura 3.38 - Establecimiento de transparencias con respecto a la existencia de los jugadores.

Esta solución simplifica el método de actualización, pasando un poco de funcionalidad


a la inicialización. En el gráfico anterior se puede ver que una vez que la posición del
arreglo tuvo un ‘true’, es decir, que fue tocado por un jugador, sin importar los valores
futuros, el arreglo de colores sigue manteniendo „Transparente’ en esa posición.

El resultado obtenido en esta segunda etapa logra despintar la imagen en su totalidad.


Llega un punto en donde la imagen está completamente descubierta y no hay más por
hacer. El siguiente paso es volver a tapar la imagen de alguna manera para mantener
al público en movimiento constante.

73
3.2.3.3 Recubrimiento de la imagen

Para la funcionalidad de volver a pintar, se aprovechó el cuarto componente del tipo


Color, Alpha, que indica el nivel de transparencia [37]. Este componente brinda la
posibilidad, no sólo de tapar con un fade in, sino que también se puede jugar con un
efecto fade out al despintar. El efecto se logra manipulando de distinta manera los
niveles de transparencia que pueden ir del 0 a 255, siendo 255 un color sólido sin
transparencia.

Entonces ahora el método update del modelo, realiza una acción sobre el arreglo de
retorno dependiendo de si existe o no un jugador en esa posición. En el caso de que
pertenezca a un jugador, se hace más transparente ese color, es decir, disminuye el
valor alpha. En el caso de que no haya ningún jugador asociado, el nivel de
transparencia disminuye, tapando así la imagen. Esta lógica se ve en la Figura 3.39.

Figura 3.39 - Establecimiento de niveles transparencias con respecto a la existencia de los


jugadores.

Es importante que estos factores sean modificables. Para ello, como en el Reproductor
de Video, se utiliza el archivo configuration.xml que es levantado al Singleton
Configuration. En este caso, el Singleton sólo es utilizado por el modelo.

Para un mejor control de la transparencia, se decidió mantener un arreglo de valores


punto flotante. Luego se transforma ese valor en un entero para ser fijado en el cuarto
componente del color, alpha. De esta manera, el factor para descubrir la imagen en los
casos de prueba fue de 50/255, y para que se vuelva a tapar pudo ser de 0,1/255.

74
Esto permitió que recién al pasar 10 frames sin movimientos, la transparencia
disminuya en 1/255.

[] ⌊ [ ]⌋

Esta tercera aplicación demuestra la simplicidad de incorporar nueva funcionalidad sin


necesidad de modificar mucho el código. Como se puede ver, los métodos de
DiscoveryController que hereda de KinectController son muy similares a la aplicación
anterior. En la inicialización, se da comienzo al flujo de datos del dispositivo Kinect, y
como en la „Hinchada‟, también se utilizan los flujos de esqueletos y profundidad.
También es necesario inicializar el gestor de colores, que es de utilidad para
establecer un color al modelo. Luego, en la actualización, este modelo en particular
sólo requiere un arreglo que va a utilizar para crear un objeto.

El modelo implementa a IModel, y su método update también es similar al de la


„Hinchada‟. En este caso se recorre un arreglo de booleanos y se modifica el cuarto
componente de los colores. Cuando la vista ejecuta el getData, el modelo sólo
devuelve el objeto creado en su actualización.

A la hora de crear una nueva aplicación, se debe tener en claro cuáles son los datos
necesarios a incorporar en el modelo, y cuál es el objeto necesario para la vista. El
controlador debe establecer todos los atributos del modelo, y luego ejecutar update.
Es aquí en donde el modelo crea el objeto para la vista específico a la aplicación en
cuestión. La vista, además de inicializarse con todas las propiedades necesarias, debe
actualizar el controlador y recuperar los datos del modelo para mostrar una imagen por
pantalla.

75
Capítulo 4
Capítulo 4 Pruebas
Este capítulo se basa en las pruebas realizadas sobre las aplicaciones que fueron
explicadas en el capítulo 3, Diseño e Implementación. Se comienza explicando el
contexto de las pruebas, los elementos utilizados y la cantidad de personas que
asistieron. Luego se pasa a describir los resultados de las pruebas aplicación a
aplicación, indicando aquellos aspectos positivos, y también aquellos que deben
corregirse.

4.1 Contexto

Las pruebas se realizaron en un contexto controlado, intentando simular de la mejor


manera una situación en cualquier museo o paseo. El lugar elegido fue un aula de la
Biblioteca Central de la UNICEN Tandil, que cuenta con el equipamiento necesario
para realizar proyecciones. A pesar de que el aula contiene sillas, se creó un espacio
suficiente para que las personas puedan moverse con tranquilidad (Figura 4.1).

Figura 4.1 - Contexto de las pruebas realizadas.

76
Como se mencionó en los capítulos anteriores, el dispositivo Kinect no detecta más de
seis personas. Sin embargo, para las pruebas fue necesario incluir una mayor
cantidad. Es imposible controlar que, a la hora de usar las aplicaciones, sólo haya una
cantidad determinada de personas. Las pruebas se hicieron con ocho personas
activas.

A continuación se muestran los resultados de las pruebas realizadas.

4.2 Aplicaciones

Una vez que el ambiente estuvo preparado y las personas presentes, se comenzó con
una explicación. Se aclaró a los participantes que las aplicaciones que iban a probar
iban a estar en un museo o paseo relacionado al tenis. Durante las pruebas se
midieron sus reacciones y luego se tomaron sus opiniones.

4.2.1 Reproductor de video

La reproducción del video está pensada para ser controlada sólo por un usuario.
Además de imposible, va en contra de la interactividad controlar que sólo una persona
lo use por vez. La idea es que una persona que visite el museo sea libre, y se pueda
divertir junto a los otros. Por eso, se llevó a probar la reproducción del video con
muchas personas. Es correcto que sólo responda a una, pero el objetivo es que siga
funcionando aunque haya más de una persona.

Figura 4.2 - Prueba del reproductor del video con una sola persona moviéndose hacia la derecha.

Los resultados obtenidos al realizar pruebas con una sola persona son ideales. La
serie de imágenes de la Figura 4.2 muestran la evidencia de las pruebas realizadas
con una sola persona que se mueve hacia la derecha. Los movimientos hacia la
derecha, como se explica en el capítulo anterior 3.2.1, hace que el video avance, es
decir, se reproduzca de manera normal, pero a una velocidad variante.

77
Figura 4.3 - Prueba del reproductor del video con varias personas en fila hacia la izquierda.

Esta prueba fue un éxito. Se notó a las personas entretenidas, y con ganas de
probarlo. Además, como también se ve en la Figura 3.2, intentaban copiar los
movimientos de la persona que se estaba proyectando.

Las mismas personas decidieron realizar una prueba como si caminaran en un pasillo
del museo en fila (Figura 4.3). En este caso el movimiento es hacia la izquierda. Como
se explica en la sección 3.2.1, este tipo de movimiento genera una reproducción hacia
atrás, es decir, backwards. Esta prueba en cuestión generó una confusión.

Como las personas caminan hacia la izquierda, esperaron que la persona del video se
mueva también hacia la izquierda. En este caso en particular, utilizando este video, la
persona se mueve hacia la izquierda en reproducción normal, por lo tanto al
reproducirse hacia atrás, se mueve hacia la derecha. La funcionalidad es correcta,
pero el video elegido hizo confundir a los usuarios.

Como resultado de esta prueba se puede concluir que hay que tener en cuenta los
movimientos de las personas que se reproducen en el video proyectado. Para
aumentar el efecto en la gente, es ideal que las personas hagan movimientos hacia la
derecha en una reproducción normal.

78
4.2.2 Hinchada

Figura 4.4 - Pruebas realizadas sobre la ‘Hinchada’ con todas las personas a la vez.

La aplicación de la hinchada inicialmente fue pensada para interactuar con muchas


personas. Durante las pruebas realizadas no se generaron inconvenientes con el
audio. A mayor cantidad de personas, los audios respondieron de manera correcta.
Cuando los jugadores se mantienen quietos, se reproducen sonidos leves, y cuando
comienzan a saltar y mover los brazos, los audios crecen en intensidad.

A lo largo de esta prueba, se nota una reacción muy divertida de parte de los
participantes. Inmediatamente se pusieron a saltar y mover los brazos, y jugaban a
quedarse quietos para ver cómo respondía la aplicación. La prueba fue acompañada
con muchas risas (Figura 4.4).

Se encontró un leve problema al dibujar las siluetas en pantalla. Hubo algunas


ocasiones en las que se repitió un color, es decir, dos siluetas pintadas del mismo
color. El problema está en que el dispositivo Kinect está detectando dos siluetas con el
mismo id de jugador. La aplicación no es capaz de darse cuenta y corregirlo. Este
defecto no fue detectado por las personas que la probaron y se puede ver en la Figura
4.5.

79
Figura 4.5 - Dos personas detectadas como una sola cuando sus esqueletos se tocan.

Luego de realizar las pruebas sobre esta aplicación, se concluyó que es muy
importante la elección de los sonidos. Recordando, si hay 6 personas quietas en frente
al sensor, se van a reproducir los primeros 6 sonidos. Si estas 6 personas se mueven,
se van a reproducir 12 sonidos. Hay que tener en cuenta que los primeros sonidos
sean leves, para que las personas tengan la necesidad de moverse para sentir la
hinchada.

4.2.3 Descubrir la imagen

La última aplicación probada fue Descubrir la imagen. Las pruebas realizadas cuando
se desarrolló, se basaron en una o dos personas. Los valores de aparición y
desaparición de la imagen fueron acomodados a ese contexto. Pero el objetivo es que
pueda ser usada por muchas personas a la vez sin inconvenientes.

Estando la imagen totalmente tapada, una persona pasó en frente al Kinect, y se dio
cuenta que con su cuerpo podía descubrirla, momento retratado en la Figura 4.6). En
este primer paso se logró el objetivo, que incentiva a las personas a moverse por el
espacio horizontal, como también en el vertical, para descubrir la imagen.

Cuando el resto de las personas vieron cómo funcionaba la aplicación, se fueron


sumando al área de juego. Inmediatamente comenzaron a moverse en el espacio
saltando y levantando los brazos para lograr descubrir la imagen completa. La
aplicación respondió correctamente a estos movimientos y las personas se
encontraron divertidas.

80
Figura 4.6 - Proceso inicial de ‘Descubrir la imagen’ con una sola persona.

Pasados unos segundos se encontró un inconveniente. Al haber tantas personas, la


imagen se descubrió muy rápido, y además, el factor de volver a pintar quedó
demasiado bajo, por lo que la imagen se veía por demasiado tiempo. El efecto
provocado se puede apreciar en las imágenes de la Figura 4.7.

Figura 4.7 - Descubriendo la imagen con muchas personas.

De esta manera, las personas que estaban jugando, simplemente se quedaban


mirando la imagen, y no tenían la necesidad de moverse mucho. La solución es
disminuir el valor que se utiliza para destapar la imagen, esto obliga a que se tenga
que „despintar‟ varias veces en un mismo lugar para lograr ver la imagen en un 100%.
También se puede aumentar el valor utilizado para volver a pintar la imagen, así se
vuelve a tapar más rápido. Estos valores son fácilmente modificables, por lo que este
factor no genera un grave problema.

81
Figura 4.8 - Personas jugando con sus poses y eligiendo qué partes de la imagen descubrir.

La prueba en general, a pesar de los índices mal establecidos, fue exitosa. Las
personas esperaban a que se vuelva a tapar para ir pasando de a uno y jugar a hacer
poses. También jugaban con las partes de la imagen que destapaban y las que
dejaban escondidas (Figura 4.8).

82
Capítulo 5
Capítulo 5 Conclusiones
En este capítulo se presentan las conclusiones encontradas luego de realizar el
proyecto en cuestión. El mismo se encuentra dividido en dos secciones. En primer
lugar se detallan los resultados obtenidos respecto a los objetivos propuestos; luego,
se proponen trabajos futuros sobre la plataforma y las aplicaciones desarrolladas.

5.1 Resultados obtenidos

A lo largo de todo el informe se presentó una plataforma para la implementación de


aplicaciones interactivas. Esta plataforma ofrece a los desarrolladores la posibilidad de
utilizar los datos brindados por el dispositivo Kinect y utilizarlos en aplicaciones que se
enfoquen en la interacción y la multimedia, permitiendo incorporar dichos datos para
que afecten o modifiquen imágenes, videos y audios. El desarrollador es capaz de
elegir aquellos datos que considere necesarios para llegar a su fin.

Para probar la plataforma se crearon tres aplicaciones base que son detalladas en la
sección 2 del capítulo „Diseño e Implementación‟. El primer punto de los objetivos que
se buscó cumplir es que estas aplicaciones sean reutilizables, es decir, sin importar
para qué contexto fueron pensadas, pueden adaptarse fácilmente a cualquier otro.
Esto fue posible gracias al diseño de las aplicaciones y el correcto uso de archivos de
configuración.

Como se mostró a lo largo de los capítulos anteriores, las aplicaciones creadas se


basaron en el tenis. Sin embargo, aquellos videos o imágenes utilizadas, pueden ser
sustituidos por otros completamente distintos, generando diferentes efectos en las
personas.

Otro punto de los objetivos planteados a la hora de desarrollar aplicaciones de prueba,


fue el de la usabilidad. En el capítulo 4, „Pruebas‟, se muestra la evidencia del uso de
las tres aplicaciones desarrolladas. Este punto fue exitoso en lo que respecta a la

83
interactividad entre las personas y el sistema. Se encontraron leves problemas en dos
de las aplicaciones donde el usuario quedó confundido. Sin embargo, estos problemas
son solucionados desde archivos de configuración que se pueden ir adaptando sin
problemas, en caso de ser necesario, a un público en particular. Si el público no se ve
atraído por una imagen o un video, o los sonidos no los satisfacen, éstos se pueden
adaptar.

Un punto muy importante que se planteó como objetivo, es el de la facilidad de crear


una nueva aplicación basándose en la arquitectura propuesta y en las aplicaciones ya
desarrolladas. La tercera aplicación, que se encuentra en la sección 3.2.3 „Descubrir la
imagen‟ fue creada de esta manera. Se tomó como base el desarrollo de „Hinchada‟
(Sección 3.2.2) y, teniendo en cuenta la arquitectura propuesta, se realizaron
pequeñas modificaciones que resultaron en una aplicación totalmente diferente.

Gracias a esta arquitectura, la incorporación de nuevos recursos es muy sencilla. A lo


largo del desarrollo sólo se utilizaron gestores para abstraer el manejo de colores y
audios. Es probable que alguna persona necesite de un gestor diferente a la hora de
crear una aplicación, sin embargo, su incorporación al sistema no aumenta la
complejidad.

Basándose en los objetivos propuestos, se puede concluir que el desarrollo fue un


éxito. La arquitectura propuesta permite la incorporación de nuevos componentes, lo
que da flexibilidad a las diferentes posibles creaciones. Las aplicaciones existentes
que se encuentran en la sección 3.2 abarcan una importante cantidad de tecnologías y
recursos, que luego un desarrollador puede tomar de base sin necesidad de comenzar
de cero. Por último, y más importante, los usuarios aseguran haberse divertido
probándolas, lo que da un cierre positivo a este proyecto.

5.2 Trabajos futuros

Esta sección contiene aquellas características que se pueden incorporar en un futuro.


El proyecto es limitado, y la capacidad para crecer es muy grande. A continuación se
mencionan sólo algunas mejoras posibles.

Como se mencionó en el capítulo 2, las aplicaciones que se desarrollaron dependen


de los datos brindados por el dispositivo Kinect. Las tres aplicaciones en cuestión
tratan con imágenes, videos y audios, sin embargo, sería ideal seguir construyendo
más aplicaciones que abarquen más tecnologías. De esta manera se brinda al
desarrollador más opciones a la hora de pensar en una aplicación sencilla de crear.

84
Como una continuación al proyecto, se podría pensar en una cuarta aplicación que
interactúe con el usuario incorporando acciones que utilicen las reglas de la física. La
imaginación de los creadores puede ir más allá todavía teniendo como base una
aplicación de este estilo, en donde pueden entrar en acción diversos objetos que
interactúan con el cuerpo, manteniendo un efecto similar al real.

Se puede crear, también, un nuevo punto de vista proyectado sobre las personas. Este
tipo de aplicaciones requiere un mayor esfuerzo en la instalación del ambiente. El
efecto provocado pretende ser totalmente diferente a las aplicaciones que se tuvieron
en cuenta hasta el momento. Generalmente, al proyectar sobre personas, quién
controla la aplicación no es el espectador.

Con respecto a las aplicaciones existentes, también se pueden realizar mejoras con
respecto a la funcionalidad. Se podría incorporar dinamismo en las imágenes y videos
que se muestran de fondo. Tomando como ejemplo „Descubrir la imagen‟, después de
un determinado tiempo, se podría cambiar la imagen de fondo para mantener
motivados a los usuarios.

En la aplicación „Hinchada‟ se puede incorporar una lógica más compleja para manejar
los audios reproducidos. Por ejemplo, reproducir sonidos suaves por cada persona
quieta, y reproducir sonidos fuertes adicionales por cada persona que se mueve.
Hasta el momento, sólo importa un número referido a la suma de personas
independientemente de si están quietas o en movimiento, como tampoco se encuentra
distinción entre los sonidos reproducidos.

Durante el desarrollo del proyecto, se tuvieron en cuenta requerimientos no


funcionales, sin embargo, no se fijó suficiente atención a todos. Las aplicaciones no
aplican concurrencia. Un paso muy importante sería poder incorporarla para que cada
componente de la arquitectura pueda manejar sus datos de una manera ordenada sin
depender de la funcionalidad pendiente del otro.

Es probable, también, que la eficiencia relacionada a la creación de objetos para ser


mostrados por la vista pueda ser mejorada. Aunque se intentó, desde un comienzo,
sólo realizar la mínima cantidad de tareas sin dejar de lado la reusabilidad, nunca hubo
un control explícito.

Estas mejoras mencionadas, respecto a la plataforma y a las aplicaciones


desarrolladas, son sólo una porción de la cantidad de posibilidades de crecimiento y
sus incorporaciones aumentarían más aún el éxito en los objetivos propuestos.

85
Referencias
[1] Wii Remote
URL: http://es.metroid.wikia.com/wiki/Wii_Remote
[2] Leap Motion
URL: http://blog.leapmotion.com/hardware-to-software-how-does-
the-leap-motion-controller-work
[3] Kinect
URL: https://en.wikipedia.org/wiki/Kinect
[4] Virtual Rehab
URL: http://www.virtualrehab.info/es
[5] Manuel Armenteros Gallardo. “Aprendizaje de las reglas del Fútbol a través del
videojuego”. ICONO 14, nº 8 (2006)
[6] Ralph Lauren London 4D
URL: https://www.youtube.com/watch?v=H4JYpF5DpFo
[7] Video Mapping
URL: https://es.wikipedia.org/wiki/V%C3%ADdeo_mapping
[8] SDK para Kinect desarrollado por Microsoft
URL: https://dev.windows.com/en-us/kinect
[9] CLI
URL: https://en.wikipedia.org/wiki/Command-line_interface
[10] GUI
URL:https://es.wikipedia.org/wiki/Interfaz_gr%C3%A1fica_de_usuario
[11] NUI
URL:http://cyrilandersontraining.com/2014/05/02/natural-user-
interfaces-nui
[12] Kinect SDK 1.8
URL: https://msdn.microsoft.com/en-us/library/hh855347.aspx
[13] Kinect SDK 2.0
URL: https://msdn.microsoft.com/en-us/library/dn799271.aspx
[14] Una Nintendo 3DS para descubrir el Louvre
URL: http://www.xataka.com/videojuegos/una-nintendo-3ds-para-
descubrir-el-louvre
[15] Museon

86
URL: http://www.museon.nl
[16] PuppyIR - An Open Source Environment to Construct Information Services for
Children
URL: http://hmi.ewi.utwente.nl/puppyir/
[17] Expo EVA
URL: http://expoeva.com/
[18] Live projection Mapping EVA 2013
URL: https://www.behance.net/gallery/9353869/Live-Projection-
Mapping-Kinect
[19] Piso Interactivo
URL: http://www.pisointeractivo.net/
[20] National Building Museum
URL: http://www.nbm.org/exhibitions-
collections/exhibitions/play-work-build.html
[21] Video Oficial National Building Museum - Minuto en donde se presenta Play
Work Build
URL: https://youtu.be/w9t9vhvC8Z0?t=147
[22] Cleveland Museum of Art
URL: http://www.clevelandart.org/gallery-one/interactives
[23] Transforming the Art Museum Experience - Galery One
URL: http://mw2013.museumsandtheweb.com/paper/transforming-the-
art-museum-experience-gallery-one-2
[24] Chicago Sports Museum
URL: http://www.harrycarays.com/chicago-sports-museum
[25] Museo de la memoria México
URL: http://www.random.com.mx/projects/project3/index.html
[26] Emgu CV
URL: http://www.emgu.com/wiki/index.php/Main_Page
[27] Open CV
URL: http://opencv.org/
[28] FMOD
URL: http://www.fmod.org/
[29] XNA
URL: https://es.wikipedia.org/wiki/Microsoft_XNA
[30] Trygve Reenskaug. “The Model-View-Controller (MVC) Its Past and
Present”. University of Oslo. (2003)

87
[31] XML
URL: https://en.wikipedia.org/wiki/XML
[32] Singleton Design Pattern
URL: https://sourcemaking.com/design_patterns/singleton
[33] Finite-state machine
URL: https://en.wikipedia.org/wiki/Finite-state_machine
[34] SoundPlayer Class
URL: https://msdn.microsoft.com/en-
us/library/system.media.soundplayer(v=vs.110).aspx
[35] MediaPlayer Class
URL: https://msdn.microsoft.com/en-
us/library/system.windows.media.mediaplayer(v=vs.110).aspx
[36] Playing a Video - XNA
URL: https://msdn.microsoft.com/en-us/library/dd904198.aspx
[37] Color Alpha Property
URL: https://msdn.microsoft.com/en-
us/library/system.drawing.color.a(v=vs.110).aspx

88

También podría gustarte