MSDN España

Noticias, avisos, reflexiones... del equipo que hay detrás de MSDN en España... también tendremos alguna que otra firma invitada :)

Reto SDK Kinect: Reconocer gestos con Skeletal tracking

Reto SDK Kinect: Reconocer gestos con Skeletal tracking

  • Comments 14

Imprescindible

Descargar el SDK de Kinect para Windows y tener alguna versión de Visual Studio 2010. Te puedes bajar la versión gratuita de Visual Studio 2010 Express o de la Ultimate Trial.

Para programar con el SDK utilizaremos la herramienta de desarrollo Visual Studio 2010 y Windows 7. Para ver más información sobre requerimientos previos y qué se puede hacer con la SDK de Kinect visita el post referente al SDK de Kinect en nuestro blog de MSDN.

Estamos atentos a tus comentarios en el twitter de @esmsdn y en el hashtag #retosmsdn.

Más sobre Skeletal Tracking

Como ya mencionamos en el reto anterior el Skeletal tracking se basa en un algoritmo de reconocimiento. Este algoritmo ha sido entrenado con muchas imágenes para lograr una gran precisión a la hora de identificar esqueletos.

El proceso de identificación del esqueleto tiene varias fases. Lo primero es obtener los datos del mapa de profundidad para separar los distintos jugadores que tiene en el campo de visión basándose en el fondo.

Una vez tenemos los distintos jugadores se clasifican las distintas partes del cuerpo para más tarde obtener los Joints o articulaciones, los distintos puntos que componen el esqueleto.

A partir de la identificación de los Joints ya podemos crear el esqueleto formado por estos puntos.

image

Reconocimiento de gestos

Cuando nos referimos a reconocimiento de gestos, en este caso, se trata de asignar a ciertos movimientos consecutivos de partes del cuerpo una determinada acción (saltar, saludar, girar, etc.).

Al igual que nos pasa con la detección de posturas el reconocimiento de gestos también tiene muchas técnicas diferentes que se pueden aplicar para lograr una mejor identificación o una implementación más sencilla. Una técnica muy utilizada para estos casos en utilizar redes neuronales las cuales se pueden entrenar para ir alcanzando cada vez más precisión y calidad de detección.

También podemos usar técnicas como definir algorítmicamente el gesto, al igual que hicimos con la postura, o comparar con una serie de plantillas ya definidas. La técnica de las plantillas es muy eficiente para gestos que siempre se realizan de la misma forma y que con cualquier otra técnica sería muy difícil de detectar.

Para ilustrar la técnica de comparación de plantillas podemos poner el golpeo de una bola jugando al tenis. Este movimiento es bastante complejo como para definirlo algorítmicamente y es más fácil si tenemos una serie de plantillas (gestos) e ir comparando cada captura con ellas. El movimiento capturado no será igual a la plantilla que tengamos pero se puede permitir un margen de error y si el resto del movimiento se sigue pareciendo al resto de plantillas podemos darlo por valido.

imageimageimageimage

imageimageimageimage

Repaso del proyecto

Para crear nuestro detector de gestos tendremos que crear un proyecto base WPF al igual que hicimos en el primer reto y añadir el código realizado en el reto anterior para la obtención de partes del cuerpo.

Hagamos un pequeño repaso. Se creaba un nuevo proyecto WPF y agregábamos la referencia al SDK de Kinect para poder utilizarlo. Más tarde añadíamos los eventos Loaded y Closed donde íbamos a implementar la inicialización y finalización del uso del sensor.

En evento Loaded teníamos que añadir en el método Initialize la opción de usar el Skeletal Tracking con el sensor y el evento SkeletonFrameReady,de donde obteníamos el esqueleto y la posición de las partes del cuerpo que vamos a utilizar en el reconocimiento de gestos, en este caso la posición de la mano derecha.

Código del Loaded:

kinect = new Runtime();
kinect.Initialize(RuntimeOptions.UseDepthAndPlayerIndex | RuntimeOptions.UseSkeletalTracking);
kinect.SkeletonFrameReady += new EventHandler<SkeletonFrameReadyEventArgs>(kinect_SkeletonFrameReady);

Código del evento SkeletonFrameReady:

void kinect_SkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e)
{
     foreach (SkeletonData skeleton in e.SkeletonFrame.Skeletons)
        if (skeleton.TrackingState == SkeletonTrackingState.Tracked)
        {
            Vector3 handRight = new Vector3();
            handRight.X = skeleton.Joints[JointID.HandRight].Position.X;
            handRight.Y = skeleton.Joints[JointID.HandRight].Position.Y;
            handRight.Z = skeleton.Joints[JointID.HandRight].Position.Z;
            //Código del detector
        }
}

También hay que crear la estructura Vector3 para trabajar con las posiciones más fácilmente añadiendo un campo más para almacenar la fecha.

[Serializable]
        public struct Vector3
        {
            public float X;
            public float Y;
            public float Z;
            public DateTime date;
        }

Deslizar

Ya tenemos el proyecto listo para añadir el código necesario para detectar gestos. Pero antes de eso vamos a ver qué gesto queremos detectar.

Vamos a implementar la detección de Swipe o deslizamiento. Este gesto es simple, se trata de mover la mano derecha hacia la derecha estando siempre a la misma altura y con una determinada velocidad.

image

Con esos factores podremos definir el gesto adecuadamente. Tenemos que tener el cuenta que para ello lo que vamos a hacer es ir comparando cada posición que obtengamos del sensor con las sucesivas para saber si el gesto es el correcto o no.

Los aspectos básicos para reconocer el gesto serán que la altura de la mano sea parecida, que el movimiento se realice a la derecha y que la longitud del movimiento sea suficiente para llegar a ser un Swipe.

Implementar el reconocimiento

Para poder identificar gestos vamos a necesitar 2 listas, una de tipo Vector3 para almacenar las posiciones que vamos obteniendo y otra para llevar la cuenta de los gestos que hemos identificado.

List<Vector3> positionList = new List<Vector3>();
List<Gesture> gestureAcceptedList = new List<Gesture>();

Después crearemos las propiedades que usaremos para definir el gesto, para la longitud, ancho del y duración del movimiento. También tendremos otra propiedad para saber cuándo hemos detectado el último gesto y otra por si queremos añadir un tiempo mínimo entre detecciones de gesto. Por último un enumerado para nombrar los gestos.

const float SwipeMinimalLength = 0.4f;
const float SwipeMaximalHeight = 0.2f;
const int SwipeMininalDuration = 250;
const int SwipeMaximalDuration = 1500;
DateTime lastGestureDate = DateTime.Now;
int MinimalPeriodBetweenGestures = 0;

public enum Gesture
{
     None,
     Swipe
}

 

Lo siguiente es crear la función que se va a encargar de recorrer la lista de posiciones que tenemos e ir comprobando si existe un conjunto de ellas que pueda ser el gesto que queremos detectar.

Entre estas comprobaciones se encuentran las mencionadas anteriormente de conservar la misma altura de la mano y dirección correcta de movimiento.

Si cumple eso hay que comprobar si la longitud del gesto es la adecuada para más tarde calcular los tiempos para saber si la velocidad es la idónea y entra dentro del rango del periodo entre gestos ( en este caso el periodo entre gestos es 0).

Por último mostraremos que hemos detectado el gesto en una etiqueta, añadimos el gesto a la lista de gestos aceptados, asignamos la fecha de ahora a la propiedad correspondiente a la fecha del último gestos detectado y borramos la lista de posiciones que tenemos.

void Swipe()
        {
            int start = 0;
            for (int index = 0; index < positionList.Count-1; index++)
            {
                if ((Math.Abs(positionList[0].Y - positionList[index].Y) > SwipeMaximalHeight) || (positionList[index].X - positionList[index + 1].X > -0.01f))
                {
                    start = index;
                }

                if ((Math.Abs(positionList[index].X - positionList[start].X) > SwipeMinimalLength))
                {
                    double totalMilliseconds = (positionList[index].date- positionList[start].date).TotalMilliseconds;
                    if (totalMilliseconds >= SwipeMininalDuration && totalMilliseconds <= SwipeMaximalDuration)
                    {
                        if (DateTime.Now.Subtract(lastGestureDate).TotalMilliseconds > MinimalPeriodBetweenGestures)
                        {
                            label1.Content = "Swipe "+ gestureAcceptedList.Count;
                            gestureAcceptedList.Add(Gesture.Swipe);
                            lastGestureDate = DateTime.Now;
                            positionList.Clear();
                        }
                    }
                }

            }
        }

Ahora añadimos la llamada en el evento SkeletonFrameReady en el lugar indicado donde añadiremos las posiciones a la lista de posiciones, llamaremos al detector de gestos y después borraremos las posiciones sobrantes de la lista si hemos alcanzado el tope máximo que lo hemos puesto en 20.

positionList.Add(new Vector3()
{
    X = handRight.X,
    Y = handRight.Y,
    Z = handRight.Z,
    date = DateTime.Now
}
    );
Swipe();
if (positionList.Count() > 20)
{
    positionList.RemoveAt(0);
}

Tu turno… ¡el Reto! – Swipe Vertical

Tenemos implementado un Swipe horizontal, de izquierda a derecha. Os proponemos realizar el Swipe de derecha a izquierda y también el de abajo a arriba (vertical).

Pista: ¡Este reto va sin pistas!

Recursos: Post sobre Kinect en el blog de MSDN, documentación sobre el SDK de Kinect y centro de desarrollo de WPF.

Solución: http://msdn.microsoft.com/es-es/windows/hh545505

Participa: twitter de @esmsdn o hashtag #retosmsdn.

¡A Kinectear!

José Perona – @JVPerona - Developer Evangelist Jr.

Ver el primer Reto SDK de Kinect: Desarrolla con Kinect

Ver el segundo Reto SDK de Kinect: Usar las cámaras del sensor

Ver el tercer Reto SDK de Kinect: Detectar posturas con Skeletal tracking

Leave a Comment
  • Please add 6 and 4 and type the answer here:
  • Post
  • ¿Vais a realizar mas tutoriales? es que para una persona que esta empezando con el kinect, esto es lo mejor que puede encontrar.

    Gracias!

  • Muchas gracias David!

    Los retos del verano ya han acabado pero pondremos más material sobre el SDK de Kinect y ¡muchas más cosas!

    Estate atento tanto al blog como a nuestro facebook MSDN.Spain y twitter @esmsdn para enterarte de las novedades.

    Un saludo!

  • Muy buenos tutoriales, ya de a poco voy aprendiendo, incluso son comprensibles para los que están empezando programación en visual studio =)

  • DIANA is with BILLY?

    NEWFOUNDLAND?

    And they are with EDWARD MEESE?

    And NAVY  SEALS?

    You know, DIANA was about the most HICK thing since ELVIS PRESLEY...and I guess BILLY BOO 222 was too.

    But whatever they say about anybody, both had enormous options in life.

    But racism,is racism, and pedophilia is pedophilia and because that served their purpose in raping kids, it " rocked".

    EDWARD MEESE was the DEN- TEXAS- with CHENEY?

    See what I mean?

    HICKS.

    And with guns.

  • Excelentes tutoriales, actualmente estoy desarrollando mi tesis con una aplicación para kinect y estos tutoriales me ayudaron demasiado, desde México MUCHAS GRACIAS.

    FELICIDADES y espero sigan haciendo más.

  • Hola

    Yo estoy comenzando a trabajar con el kinect  , ya entendiendo que me entrega el kinect quiero saber cada cuanto me entrega esos datos de profundidad  , o si es por demanda (cada que yo se lo pida) , también he estado leyendo y entiendo que el kinect cuando ya tiene la imagen de profundidad la segmenta en partes (los puntos de interes) mi pregunta es si uno trabaja con cada punto  por separado o hace el reconocimiento según la posición del conjunto de puntos y también como hace la unión de estos puntos .

  • Hola a todos

    Me han ofrecido hacer el proyecto de fin de carrera basado en una aplicación de Kinect y antes de aceptarlo quisiera preguntar una serie de cuestiones..

    ¿Que diferencias habría entre desarrollar aplicaciones para una cámara kinect de XBOX y hacerlo con el paquete que venden de Kinect for windows?

    Los requisitos mínimos que piden para el ordenador son altos, ¿creeis que valdría con un procesador duo a 2.4 GHz (Core2Duo E6600)?

    Y por ultimo la pregunta que más me preocupa, la aplicación que me han encargado se basa en un control de helicóptero, no a modo de mando a distancia y que siga mis instrucciones, sino que una computadora sea capaz de reconocerlo y corregir el error de posición para hacerlo aterrizar en una posición predeterminada. Mi pregunta seria si veis factible hacer que Kinect reconozca un helicóptero, por lo que tengo entendido ya traen funciones para hacer que reconozca un cuerpo humano y sus movimientos, pero no he leido nada acerca de reconocer otras formas. Estoy ahora mismo aprendiendo por mi cuenta programación orientada a objetos en c++ y no se si este es un jardin que de momento me queda demasiado grande...

    Un saludo y muchas gracias

  • Hola Diego,

    Los datos se obtienen cuando el frame está listo, no es por demanda.

    Cuando estás trabajando con el Skeletan tracking se obtiene un vector de puntos correspondientes a las partes del cuerpo, no se unen estos puntos, tienes un vector. Para obtener las posiciones de todos los puntos (píxeles) de la imagen tienes que usar los datos de profundidad.

    Jose Perona- Development Advisor en Plain Concepts

  • Hola luispsmith,

    La diferencia es que Kinect for windows es mejor, tiene lo que se llama el "near mode" para detectar posturas más de cerca.

    En cuanto al rendimiento yo he probado en un dual Core p8400 y no he tenido problemas.

    Lo que quieres hacer no es tarea fácil. Primero tienes que identificar la posición del helicoptero, si está solo en la imagen lo puedes hacer con la imagen de profundidad que te da la distancia de los puntos al sensor, con eso tienes que calcularla sabiendo el ángulo de la cámara, altura al suelo y demás.

    Si tienes más objetos tendrás que utilizar la imagen RGB y crearte un algoritmo para identificar qué puntos son del helicoptero para después coger esos puntos de la imagen de profundidad.

    Cuando tengas la posición del helicoptero habrá que enviar las ordenes a éste, tendrás que saber cómo hacer eso y también saber dónde tiene que ir.

    No son tanto los conocimientos de programación los que tienes que saber, programar con el SDK es sencillo, sino más de recocimiento visual, trigonometría, tratamiento de imágenes, etc.

    Piénsatelo bien antes de hacerlo. Es un proyecto muy interesante pero complejo.

    Jose Perona- Development Advisor en Plain Concepts

  • Saludos estoy realizando mi proyecto de fin de carrera el cual consiste en detectar posturas y para eso necesito calcular los ángulos de las articulaciones me podrían ayudar.. osea como hago para calcular los ángulos del hombro, codo, mano etc. gracias

  • El Kinect te arroja las coordenadas de las articulaciones (x,y,z) con esto ya se puede calcular el angulo de flexion de las articulaciones a travès de la trigonometrìa.

  • Muy util y muy bien explicado gracias por compartir

    Saludos

  • buenas tardes, yo tengo una api que funciona solo con las manos es igual de kinect y mi duda es que como puedo crear un gesto, por ejemplo un puño y que este me imprima una letra o algo en la pantalla, gracias

  • Gracias amigo

    con este tutorial me diste muchas ideas para programar

Page 1 of 1 (14 items)