25 de octubre de 2012

Plantilla para crear programas con interfaz gráfica - Kinect SDK

Las aplicaciones que hemos realizado hasta el momento sirven perfectamente para ilustrar los primeros pasos que se deben llevar a cabo en cualquier desarrollo con el Kinect. Sin embargo, para aprovechar completamente las capacidades del Kinect es mucho mejor realizar programas que cuenten con una interfaz gráfica.

La gran mayoría de los programas que realizamos con el Kinect y C# tienen la misma estructura por lo que en esta entrada vamos a ver como crear la base de todos los programas que vamos a realizar.

1. Vamos a abrir  Microsoft Visual C# 2010 Express (cualquier versión de Visual Studio servirá pero uso la express porque es gratuita). Vamos a Archivo / Nuevo Proyecto. Esto abrirá una ventana en la seleccionamos "Aplicación WPF" y le damos cualquier nombre (en mi caso le puse "plantilla").

Como ya había dicho en una entrada anterior podemos realizar programas de consola, windows forms, y WPF (Windows presentation foundation) pero por su facilidad de describir la interfaz gráfica por medio de un lenguaje de marcado como lo es XAML es mejor trabajar con aplicaciones WPF.


Al darle aceptar nos va a crear dos pestañas. Una llamada MainWindow.xaml que contiene el XAML que describe la interfaz gráfica, en este caso, una ventana vacía. La segunda pestaña llamada MainWindow:xaml.cs contiene el código en lenguaje C#.

2. Como en los programas anteriores debemos agregar las referencias para poder tener control sobre el Kinect. (Cada vez que sale una nueva versión del Kinect SDK y la instalamos, debemos repetir este paso para que nuestro código siga funcionando)






3. Ahora que nuestro proyecto cuenta con las librerías mínimas necesarias podemos agregar al principio de nuestro programa la instrucción "using Microsoft.Kinect;". Sin ninguna cosa extra, nuestro código en el archivo MainWindow.xaml.cs debería ser así:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Microsoft.Kinect;

namespace Plantilla
{
    /// 
    /// Lógica de interacción para MainWindow.xaml
    /// 
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    }
}


4. Para interactuar con el Kinect, y como ya lo habíamos hecho en entradas anteriores, creamos una instancia de la clase KinectSensor adentro de la clase MainWindow. Una vez declarado este objeto podemos usarlo en cualquier parte del programa para que el Kinect realice alguna tarea en particular. Vamos a llamar a este objeto miKinect (el nombre puede ser cualquiera). El Kinect SDK puede controlar varios dispositivos Kinect a la vez y la única limitante es la capacidad del computador en el que se ejecuta el programa. Si fuéramos a usar mas de un dispositivo, tendríamos que crear diferentes instancias de la clase KinectSensor para cada uno.

Para declarar miKinect, entramos otra vez a el código fuente del programa que controla la ventana principal.  MainWindow.xaml.cs

Hay que declarar miKinect adentro de la clase MainWindow. De esa forma el programa puede hacer uso de esta variable para controlar el Kinect. Con la declaración de miKinect el código del programa debería lucir similar a este:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Microsoft.Kinect;

namespace Plantilla
{
    /// <summary>
    /// Lógica de interacción para MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        KinectSensor miKinect;
        
        public MainWindow()
        {
            InitializeComponent();
        }
    }
}

5. Ahora que declaramos nuestra variable miKinect, debemos asignar el Kinect que tenemos conectado a nuestra variable recién creada y esto debe ser realizado en el momento que se inicia el programa, por lo que lo vamos a poner en el método Window_Loaded . Este método es llamado al momento de cargarse la ventana principal cuando el programa es iniciado. Para crear este método vamos a usar las herramientas que nos brinda el Visual Studio realizando los siguientes pasos.

    1. Seleccionamos el diseñador de ventanas.
    2. Vamos a la pestaña eventos
    3. Hacemos doble clic en el evento Loaded



 De esa manera el Visual Studio nos agregara lo siguiente en nuestro código fuente:

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {

        }

Lo que se encuentre dentro de este método se ejecutará al momento de iniciar el programa.

6. Adentro del método que acabamos de crear vamos a asignar nuestra variable miKinect. La clase KinectSensor provee una colección con todos los Kinects conectados en el computador por lo que debemos decirle al programa cual de todos sera el Kinect con el que trabajaremos. Para hacer esto agregamos la siguiente linea en el método Window_Loaded.

miKinect = KinectSensor.KinectSensors[0];

7. Ahora que tenemos un objeto que representa nuestro Kinect podemos comenzar a darle ordenes. Lo primero que hacemos es habilitar el dispositivo y decirle que tipo de datos debe entregarnos. Como esta entrada se trata de crear una plantilla para futuros programas vamos a habilitar los tres tipos de información que nos puede entregar el kinect. La imagen de color, la imagen de profundidad, y el rastreo de esqueleto. Los habilitamos de la siguiente manera:

miKinect.ColorStream.Enable();
miKinect.DepthStream.Enable();
miKinect.SkeletonStream.Enable();

Cada tipo de información que nos envía el kinect viene con unas características por defecto que pueden ser modificadas si pasamos argumentos a la función Enable(). Por ejemplo, las imágenes de color vienen por defecto a una resolución de 640x480 píxeles a una tasa de 30FPS pero podemos obtener imágenes de 1280x960 a 12FPS si activamos el flujo de información de esta manera:

miKinect.ColorStream.Enable(ColorImageFormat.RgbResolution1280x960Fps12);

8. El programa ya esta configurado para entregar los flujos de información disponibles. Sin embargo el programa no sabe que hacer con esta información. Para solucionarlo, debemos crear métodos que se disparen cada vez que el kinect tenga una imagen lista, ya sea de color, de profundidad, datos de esqueleto o las tres al tiempo. Estos métodos son conocidos como manejadores de eventos. En otras palabras, el manejador de eventos de la información a color se va a ejecutar 30 veces por segundo (ya que por defecto el ColorStream es de 30 FPS).

Para crear estos manejadores de eventos vamos a escribir, en el caso del manejador de eventos del ColorStream, lo siguiente:

miKinect.ColorFrameReady +=

y luego presionamos dos veces la tecla TAB. De esa manera el manejador de eventos para el flujo de información que entrega el kinect para las imágenes de color se crea automáticamente. Para crear los otros manejadores deberíamos hacer algo similar:

miKinect.DepthFrameReady +=

y

miKinect.SkeletonFrameReady +=

Por ultimo iniciaremos el flujo de datos del kinect con la linea:

miKinect.Start();

De esta manera nuestra plantilla esta lista para realizar programas complejos. En el caso que no necesitemos algún flujo de información de los que pusimos, se debe borrar todas las que hagan alución a el. Nuestra plantilla debería haber quedado de la siguiente manera:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Microsoft.Kinect;

namespace Plantilla
{
    /// 
    /// Lógica de interacción para MainWindow.xaml
    /// 
    public partial class MainWindow : Window
    {
        KinectSensor miKinect;
        
        public MainWindow()
        {
            InitializeComponent();
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            miKinect = KinectSensor.KinectSensors[0];
            miKinect.ColorStream.Enable();
            miKinect.DepthStream.Enable();
            miKinect.SkeletonStream.Enable();

            miKinect.ColorFrameReady += new EventHandler<ColorImageFrameReadyEventArgs>(miKinect_ColorFrameReady);
            miKinect.DepthFrameReady += new EventHandler<DepthImageFrameReadyEventArgs>(miKinect_DepthFrameReady);
            miKinect.SkeletonFrameReady += new EventHandler<SkeletonFrameReadyEventArgs>(miKinect_SkeletonFrameReady);
            
            miKinect.Start();
        }

        void miKinect_SkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e)
        {
            throw new NotImplementedException();
        }

        void miKinect_DepthFrameReady(object sender, DepthImageFrameReadyEventArgs e)
        {
            throw new NotImplementedException();
        }

        void miKinect_ColorFrameReady(object sender, ColorImageFrameReadyEventArgs e)
        {
            throw new NotImplementedException();
        }

    }
}

El siguiente video permite ver de una manera mas clara el como se desarrolla esta plantilla que es la base de cualquier proyecto con el kinect.




2 comentarios:

  1. muchas gracias....
    me aclaraste muchas ideas.
    espero publiques un poco mas sobre el tema.

    ResponderEliminar
  2. excelente tutorial
    todo muy claro
    Muchas gracias! <3

    ResponderEliminar