viernes, 4 de diciembre de 2015

Reto 2: Lanzar aplicaciones c#

Lanzar una aplicacion dentro de otra usando C#

Realizando una rápida busqueda por internet entontramos como hacerlo, primero necesitas incluir las librerias necesarias

using System;
using System.Diagnostics;

Una vez incluidas, ya podemos llamar a un proceso desde nuestra aplicación, para ello es necesario declarar un proceso:
 ProcessStartInfo startInfo = new ProcessStartInfo();
Le añadimos las opciones que vemos a continuacion para que ejecute una ventana nueva y que no lo haga des del shell de windows:
startInfo.CreateNoWindow = false;
                startInfo.UseShellExecute = false;
Y añadirle el path del proceso que desees lanzar, así como sus argumentos si los requiere:
 startInfo.FileName = path;
startInfo.Arguments = " " + args;
Una vez hecho esto ya esta todo declarado, solo es necesario llamarlo y ejecutarlo, para ello lo meteremos en un "Try-catch" con el fin de que si se produce una excepcion durante la ejecución captarla:
                try
                {
                   //Empieza el proceso con toda la información puesta anteriormente.
                    using (Process execProcess = Process.Start(startInfo))
                    {

                    }
                }
                catch
                {
                    Console.WriteLine("Error");
                }
Una vez hemos aprendido como lanzar procesos, añadir esto a nuestros botones lanzadores resulta fácil, solo necesitamos que al hacer click en cada botón de icono de cada juego cambie el path a la dirección en la que se encuentra dicho juego y los argumentos. Y en el botón lanzar juego que lanze el proceso con los argumentos posteriormente asignados al seleccionar el juego.

Reto 2: Desarrollo

Empezamos


Vamos a crear un menú de juegos, llamado Game Menu, así que para ello necesitamos crear una interfaz que interactue con el usuario. Para ello vamos a modificar el archivo MainWindow.xaml, en dicho archivo vamos a crear una ventana de 1030 por 730 pixeles, empleando la herramienta Blend de Visual Studio:



La ventana en xaml tiene el siguiente codigo:

<Window x:Name="mainW"
WindowStartupLocation="CenterScreen"
 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" x:Class="Microsoft.Samples.Kinect.BodyBasics.MainWindow"
 Title="Game Menu" 
 Visibility="Visible"
 Height="730" Width="1030" 

Una vez creada la ventana le vamos a añadir los botones de jugar y exit, los iconos de los juegos y un pequeño display que te diga el juego que tienes seleccionado actualmente.

Empezaremos creando los botones de jugar, para ello con blend añadimos dos botones utilizando la interfaz gráfica quedando de esta manera:

<Button Visibility="Visible" x:Name="jugar" Content="Jugar" HorizontalAlignment="Left" Height="100" Margin="27,555.2,0,0" VerticalAlignment="Top" Width="444" FontSize="40" Click="Button_Launch" FontWeight="Bold">
            <Button.Background>
                <ImageBrush ImageSource="button.png"/>
            </Button.Background>
        </Button>

Así para cada botón que añadimos, como podemos ver con ImageBrush añadimos una imagen al botón, para darle textura, en este caso en Background, aunque también dispone de otras opciones, en este caso la pondremos en background para que así al pulsar el botón no desaparezca la textura.

Una vez creados estos botones añadimos tres botones más, cuya función sera la elección del juego a lanzar. Para ello creamos tres botones con las herramientas mencionadas anteriormente y le añadiremos una foto que contenga el icono del juego en cuestión de background. En nuestro caso hemos elegido el Hearthstone, League of legends y Mario Kart.

Como toda aplicación tiene que tener también unas instrucciones de uso para el usuario final, así que decidimos añadir dos diapositivas que contengan las instrucciones a modo de carta de presentación.
Para ello crearemos dos botones que se muestren al tamaño de la ventana y le añadiremos las texturas de las diapositivas, que previamente hemos exportado como jpeg o png.

Una vez hecho esto solo queda añadirle la funcionalidad a los botones y crear la secuencia para que se muestren los botones según corresponde.

Para ello en cada botón escribiremos el evento click que realiza, que se corresponde con una función. Ej:

 Click="Button_Launch"

Y creamos la funcion con el mismo nombre:

 private void Button_Launch(object sender, RoutedEventArgs e)
        {

Y en la función le añadimos toda la funcionalidad que le queramos dar al botón, por ejemplo cambiar la visibilidad de otro botón etc.

En los botones de los juegos y en lanzar exit añadiremos funcionalidad extra, destinada a lanzar cada aplicación, pero esto lo veremos en el siguiente apartado.

Reto 2 Kinect

Motivación


Con motivo de la segunda práctica de la asignatura de 4º GI de la UGR, NPI (Nuevos Paradigmas de Interacción) se nos propone el siguiente reto:

En esta práctica debéis crear una aplicación que utilice interacción gestual. El tema es libre pero se recomienda consultar con el profesor antes de comenzar la aplicación.

El objetivo principal, y por tanto el que se va a evaluar, es la inclusión de elementos interactivos en la aplicación. El resto de la misma puede ser reutilizado de otro desarrollo anterior o de alguna aplicación de la que se tenga acceso al código fuente.






Ejemplo de elementos interactivos.


Las actividades a realizar son las mismas que se pedían en la práctica anterior:

- Desarrollar la aplicación como tal.

- Escribir la documentación, un tutorial detallado.

¿Qué hacemos?


He aquí la pregunta. Nuestra primera idea fue ejecutar un emulador de la GameBoy Advance en windows con el juego Mario Kart, y utilizar Kinect para manejarlo. 

Emular un volante con las manos exactamente así

Pero en el desarrollo de esta aplicación tuvimos problemas, pues al enviar eventos desde teclado hacia el emulador, la cantidad de veces que puedes enviar una tecla es inferior al numero de veces que se envia una letra al pulsarla directamente desde teclado, es decir el flujo era insuficiente.

Por lo que el coche no se movía y nos vimos obligados a cambiar de idea.

Segunda idea


Nuestra segunda idea propuesta consiste en realizar un menú lanzador de juegos, utilizando tu mano como ratón para seleccionar las opciones o juego que quieres jugar y poder jugarlo utilizando tu mano o el teclado/ratón. Como por ejemplo jugar a Hearthstone Link Hearthstone utilizando tu mano para jugar, seleccionar las cartas y etc. 

Captura Hearthstone

Una vez nos dimos cuenta de que la primera idea no la podíamos realizar por el problema mencionado anteriormente, nos pusimos en marcha con la segunda. Cuyo desarrollo será contado a continuación

viernes, 30 de octubre de 2015

Desarrollo del reto 3

Añadiendo otras funcionalidades


Una vez hecho el reconocimiento de dar la patada identificado con las dos posturas, hemos decidido añadir otras funcionalidades para mejorar la experiencia del usuario, nuestra primera medida será añadir un botón a cierta distancia encima del usuario, que al pulsarlo se inicie la aplicación y a su vez, empiece a sonar una canción. Para crear dicho botón, añadimos la textura del Ying-Yang, como mencionamos anteriormente:

ImageBrush yinyangBrush = new ImageBrush(new BitmapImage(new Uri(@"PATH IMAGEN")));

Así, creamos un pincel (Objeto Brush) con la imagen del Ying-Yang, ahora tenemos que dibujarla, para ello previamente creamos una variable Tipo Point en la que vamos a definir la ubicación del objeto, para ello utilizaremos de referencia la posición de la cabeza del body, y la distanciamos 35 unidades en el eje Y para que se pose sobre el usuario:

Point posEsferaMusica = new Point(jointPoints[JointType.Head].X, (jointPoints[JointType.Head].Y) - 35.0);

Y la dibujamos en esta posición, encima de la cabeza del body a 35 unidades de distancia:

dc.DrawEllipse(yinyangBrush, null, posEsferaMusica, 20, 20);

Una vez creada la esfera, toca darle funcionalidad. En este caso le vamos a otorgar que sea el botón de Start de la aplicación y que al pulsarlo se lance la música y comiencen las siguientes fases, pero para ello necesitamos cargar las siguientes librerías y variables:

using System.Media; //Librería Música

private SoundPlayer kungfu = new SoundPlayer(@"PATH MUSICA.wav");

Una vez añadido esto, solo nos queda implementar dicha funcionalidad, para ello hay que crear un método que nos detecte cuando estamos tocando la esfera implementada anteriormente:

private bool PosturaStart(){}

Esta función devuelve true cuando el Joint de la mano izquierda o derecha se encuentra exactamente a la misma altura que la esfera, es decir, la toca.

De este modo queda definida la funcionalidad de la esfera. Ahora solo nos queda la interacción con el usuario y ordenar secuencialmente las acciones. Queda de esta manera:

Figura 3.

Interacción con el usuario:

Necesitamos guiar al usuario para conseguir que represente las posturas,  decidimos interactuar con el usuario por medio de imágenes y algo de texto, para hacerlo más intuitivo y fácil. En primer lugar pensamos en utilizar XAML añadiendo imágenes y habilitando y deshabilitando la visibilidad de estas para cambiarlas cuando sea necesario para las diferentes fases. Como se puede ver en la Figura 4, tenemos una serie de imágenes preparadas con figuras y textos que ofrecen unas instrucciones que permiten al usuario pasar por las diferentes fases.
dogo2.jpg
Figura 4.
El método que estábamos utilizando con las imágenes XAML no nos pareció el mejor y una vez que aprendimos a crear Brushes con texturas, decidimos utilizar varios Rectangles con las imágenes de las fases como texturas.
Fases de la aplicación:
La aplicación se compone de cuatro fases:
  • Fase 1: Se muestra la imagen inicial en la que se pide al usuario que toque el Yin Yang para comenzar. Al tocar el YinYang empieza a sonar la música y comenzará la fase 2.
  • Fase 2: Se pide al usuario que imite la postura de Karate Kid como hace la figura de ejemplo. Aquí entra en acción la función de la postura mirando que la rodilla esté a la altura de la cadera. Al hacer la primera postura con la pierna izquierda comienza la fase 3.
  • Fase 3: Se pide al usuario hacer la segunda postura, en este caso con la pierna derecha. Hacer esta postura dará comienzo a la fase 4.
  • Fase 4: Fase final de la aplicación en la que se invita al usuario a hacer un saludo como indica la figura de referencia. Este saludo parará la música y finalizará la aplicación.
Para el pase de fases hemos contabilizado el tiempo en que se estaba en una postura, esto se hace para que no se acepte la postura al mover partes del cuerpo por error. El tiempo en que se debe estar en una postura viene dado por el número de frames que han pasado desde que se tomó dicha postura, nosotros hemos puesto que las posturas esten entre 30 y 40 frames pues la Kinect 2 recibe 30 fps.
Una vez hecho esto, ya tenemos definida entera nuestra aplicación, el repositorio es: Proyecto Github


jueves, 29 de octubre de 2015

Desarrollo del reto 2

Detección de posturas con ángulos:

Nuestra primera idea para detectar la postura de Karate Kid (mostrada en la Figura 2) fue utilizar álgebra vectorial básica, calculamos los vectores correspondientes a las partes del cuerpo cuyos ángulos queremos comparar, en este caso probamos a generar los vectores del muslo y la pantorrilla. La postura sería correcta cuando el ángulo de nuestra pierna estuviese entre un rango razonable de valores como 70 grados y 100.

Para calcular el vector utilizamos:

V = (Pbx - Pax, Pby - Pax) Siendo Pa y Pb puntos del espacio con sus coordenadas (x,y) correspondientes.

Usando los puntos del tobillo, rodilla y cadera obtenemos los vectores de la pantorrilla y el muslo, necesarios para saber el ángulo de la pierna  y utilizando trigonometría calculamos el ángulo que forma la pierna y después de calcularlo aplicar un margen de error para darle mayor tolerancia. El cálculo del ángulo es el siguiente:

Figura 2.
Una vez tenemos el ángulo lo único que necesitamos hacer es ponerle un umbral para que la postura no fuese exacta, que admitiese cierta tolerancia y para ello pusimos un intervalo razonable de entre [70º-100º]

Tuvimos problemas con la detección de las posturas con este método pues no detectaba los ángulos correctamente, la solución fue darle otro enfoque.
Detección de posturas con alturas de los joints:

La solución que finalmente adoptamos fué  mirar a qué altura se encuentran dos joints en cuestión, en nuestro caso nos fijaremos en el joint central de la cadera (SpineBase) y el joint de la rodilla de la pierna en cuestión.

Para ello creamos una función que detectase que la cadera y la rodilla se encontrasen alineados y devolviese true cuando este hecho se produjera con cierto grado de error introduciendo las variables max y min, de nuevo para ofrecer mayor flexibilidad a la hora de detectar que ambos joints esten a la misma altura.

Esta función recibe dos BodyPartCoords, struct que hemos creado para obtener las coordenadas (x,y) de los joints y utilizarlos más cómodamente.

Esta idea de comprobar la postura utilizando alturas de los joints la hemos sacado de un tutorial de Kinect 1 que nos guió en la implementación.  Tutorial skeletal traking.
Para finalizar este apartado cabe mencionar que la detección de alturas es la herramienta que hemos utilizado para hacer las funciones de las posturas (Pose Karate Kid con pierna izquierda primero y despues pierna derecha).

Desarrollo del Reto 1

BodyBasics-D2D


La primera parte fué comprender el código de BodyBasics, en él realiza un tracking de las personas que se encuentren delante de Kinect y las pinta representando los huesos y articulaciones, de la siguiente forma:

FIgura 1:

BodyBasics2D representa las articulaciones del cuerpo en cuestión como joints, y entre los joints crea líneas representando las distintas partes del cuerpo. Las líneas que se ven en la Figura 1 son bones, creados a partir de parejas de tipos de Joint (JointType).
           // Torso

           this.bones.Add(new Tuple<JointType, JointType>(JointType.Head, JointType.Neck));
           this.bones.Add(new Tuple<JointType, JointType>(JointType.Neck, JointType.SpineShoulder));
           this.bones.Add(new Tuple<JointType, JointType>(JointType.SpineShoulder, JointType.SpineMid));
       this.bones.Add(new Tuple<JointType, JointType>(JointType.SpineMid, JointType.SpineBase));
           this.bones.Add(new Tuple<JointType, JointType>(JointType.SpineShoulder, JointType.ShoulderRight));
           this.bones.Add(new Tuple<JointType, JointType>(JointType.SpineShoulder, JointType.ShoulderLeft));
           this.bones.Add(new Tuple<JointType, JointType>(JointType.SpineBase, JointType.HipRight));
           this.bones.Add(new Tuple<JointType, JointType>(JointType.SpineBase, JointType.HipLeft));

           // Brazo Derecho
           this.bones.Add(new Tuple<JointType, JointType>(JointType.ShoulderRight, JointType.ElbowRight));
           this.bones.Add(new Tuple<JointType, JointType>(JointType.ElbowRight, JointType.WristRight));
           this.bones.Add(new Tuple<JointType, JointType>(JointType.WristRight, JointType.HandRight));
           this.bones.Add(new Tuple<JointType, JointType>(JointType.HandRight, JointType.HandTipRight));
           this.bones.Add(new Tuple<JointType, JointType>(JointType.WristRight, JointType.ThumbRight));

           // Brazo Izquierdo
           this.bones.Add(new Tuple<JointType, JointType>(JointType.ShoulderLeft, JointType.ElbowLeft));
           this.bones.Add(new Tuple<JointType, JointType>(JointType.ElbowLeft, JointType.WristLeft));
           this.bones.Add(new Tuple<JointType, JointType>(JointType.WristLeft, JointType.HandLeft));
           this.bones.Add(new Tuple<JointType, JointType>(JointType.HandLeft, JointType.HandTipLeft));
           this.bones.Add(new Tuple<JointType, JointType>(JointType.WristLeft, JointType.ThumbLeft));

           // Pierna derecha
           this.bones.Add(new Tuple<JointType, JointType>(JointType.HipRight, JointType.KneeRight));
           this.bones.Add(new Tuple<JointType, JointType>(JointType.KneeRight, JointType.AnkleRight));
           this.bones.Add(new Tuple<JointType, JointType>(JointType.AnkleRight, JointType.FootRight));

           // Pierna izquierda
           this.bones.Add(new Tuple<JointType, JointType>(JointType.HipLeft, JointType.KneeLeft));
           this.bones.Add(new Tuple<JointType, JointType>(JointType.KneeLeft, JointType.AnkleLeft));
           this.bones.Add(new Tuple<JointType, JointType>(JointType.AnkleLeft, JointType.FootLeft));


En este código podemos ver como crea bones, una pareja de tipos de Joints, para después pintar el esqueleto en pantalla. El dibujado del cuerpo entero se lleva a cabo en DrawBody. Esto nos ha sido muy útil para poder saber las posición de los Joints a la hora de probar la aplicación. Además del dibujado del cuerpo, viene en BodyBasics también un rectángulo dibujado que encuadran los bodies dibujados, esto se hace con la función DrawRectangle de Drawing Context.

dc.DrawRectangle(Brush.White, null, new Rect(0.0, 0.0, this.displayWidth, this.displayHeight));

Con esa función estamos dibujando un rectángulo de color blanco con un tamaño displayWidth y displayHeight predefinidos anteriormente. Ese cuadrado va a permitir a los bodies dibujados están dentro de un entorno definido y moverse por él. En nuestro caso hemos utilizado este método pero en lugar de utilizar un Brush con un color predefinido hemos creado un color con una imagen como textura. Para poder crear texturas a partir de imágenes podemos utilizar este código.

ImageBrush <nombre> = new ImageBrush(new BitmapImage(new Uri(“PATH IMAGEN”)));


Una vez visto como se dibuja el cuerpo y el entorno en el que se mueve, vamos a explicar la función en la que se ejecuta el código que hemos incluido en este ejemplo.

private void Reader_FrameArrived(object sender, BodyFrameArrivedEventArgs e){}

En esta función es donde definimos la lista de cuerpos que estamos detectando y cada vez que se recibe un frame se ejecuta la segunda parte de la función, donde ejecutaremos los dibujados y controlaremos el flujo de la aplicación (if (dataReceived)).

En primer lugar se crea un drawinContext que vamos a necesitar para todo lo que queramos dibujar. En este link se puede ver todo sobre drawinContext para más información: https://msdn.microsoft.com/en-us/library/system.windows.media.drawingcontext(v=vs.110).aspx

Una vez definido el drawingContext, dependiendo de la fase en la que estamos de la aplicación (fase 1 empezar tocando el yinyang, fase 2 para poner la primera postura, fase 3 para poner la segunda postura y fase 4 para finalizar la aplicación) definiremos un brush basado en texturas de los diferentes fondos que hemos preparado con texto para interaccionar con el usuario y dar las instrucciones de la aplicación):


Después de esta parte que hemos añadido nosotros, se crean para cada cuerpo un diccionario de tipos de Joint y las coordenadas del Joint(x,y) que nos será de mucha utilidad posteriormente. Una vez disponemos del diccionario jointPoints comenzamos a buscar las posturas y otras funciones para la aplicación.





Reto Kinect

¿Reto?


Con motivo de la primera práctica de la asignatura de 4º GI de la UGR, NPI (Nuevos Paradigmas de Interacción), en la primera práctica tenemos la misión de usar un dispositivo de detección de movimientos, a elegir entre LEAP, KINECT Y KINECT V2. Nosotros hemos elegido Kinect 2 (Xbox One), hay que aclarar que es la primera vez que usamos Kinect, asi que es la primera toma de contacto con el dispositivo, aunque cabe destacar que para esta práctica podemos utilizar funcionalidades de la SDK.




Bien, los objetivos del reto consisten en:

- Familiarizarnos con los dispositivos de detección de movimientos.

- Generar módulos de detección que sean reutilizables por los compañeros de la asignatura y por la comunidad en general.


- Presentar ante el grupo los problemas asociados a la detección asignada, la solución implementada y como se utiliza.

Las actividades a realizar consisten en dos partes:


Realizar una aplicación de detección de una postura fija y un gesto, Debe actuar del siguiente modo:

- Mostrar al usuario la posición a adoptar, antes de realizar el gesto, ayudándolo mediante indicaciones.
- Ayudar al usuario por medio de marcas virtuales (primitivas geométricas, texto, imágenes etc)

(Además para dichas acciones debe poder tolerar un margen de error, es decir reconocer acciones parecidas, pues es difícil para el usuario adoptar posiciones exactas sin demasiadas indicaciones)

Realizar un tutorial detallado, explicando que hemos hecho, cómo lo hemos hecho y las piedras que nos hemos encontrado en el camino. Es decir, los módulos que hemos utilizado, que hemos modificado, los parámetros que requieren, referencias y ayudas que hemos empleado, problemas que hemos tenido y como hemos conseguido solucionarlos.

Primeros pasos


Primero debemos instalar el SDK de Kinect que nos proporciona Microsoft  Link SDK Kinect V2, hecho esto, el primer paso es ver que funcionalidades nos ofrece Microsoft para poder emplearlas en nuestra práctica, nosotros hemos decidido hacerla en C# puesto que es un lenguaje que desconocemos y como todo en la vida, cuanto mas sepas, mejor (o al menos eso creemos, somos gente curiosa). Como nos pide realizar un "traking" del esqueleto del usuario, la funcionalidad "BodyBasics2D" nos viene perfecta para dicha función.

La comprensión del código de BodyBasics2D creado por Microsoft será explicada en otra entrada.

¿Qué hacemos?


Probablemente esta pregunta sea difícil, dado que la imaginación es algo que escasea normalmente. A nosotros se nos ocurrió la idea de hacer una especie de aplicación/minijuego/fit que tengas que dar una patada en el aire y cambiar de pierna (estilo kung fu), y como buena patada de kung fu, tiene que tener música de ambiente ("Everybody loves kung fu fighting" parece idónea para dicha tarea). 

(Algo así, pero sin levantar tanto la pierna, para que cualquier usuario pueda hacerlo)


Posteriormente contaremos como hemos ido realizando dichas funcionalidades y la aplicación como tal en GitHub