Skip to main content

Solución Reto SDK de Kinect: Detectar posturas con Skeletal tracking

En la explicación de este reto aprendimos a realizar un detector de posturas utilizando la capacidad de obtener las posiciones de las partes del cuerpo por medio de los datos del Skeletal tracking. Como reto propusimos detectar cuando el jugador está en posición de cruz.

Para solucionar este reto necesitamos:

 
Visual Studio. Si ya tienes VS instalado perfecto, pero por si acaso, aquí tienes el enlace de descarga de la versión gratuita express o de la Ultimate Trial.
 

 

SDK de Kinect para Windows. SDK necesario para utilizar las capacidades del sensor Kinect en nuestras aplicaciones. Descárgalo aquí.

Como siempre partiremos de la estructura vista en la explicación al reto donde inicializamos en el método Loaded la clase Runtime, activando el Skeletal tracking. Tendremos que crear el evento para capturar los datos del esqueleto cuando estén listos. Para acabar tenemos el evento Closed donde finalizamos el uso del sensor.

 

Runtime kinect;

public MainWindow()
{
	InitializeComponent();
	Loaded += new RoutedEventHandler(MainWindow_Loaded);
	Closed += new EventHandler(MainWindow_Closed);
}

void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
	kinect = new Runtime();
	kinect.Initialize(RuntimeOptions.UseSkeletalTracking);	
                kinect.SkeletonFrameReady += new EventHandler<SkeletonFrameReadyEventArgs>(kinect_SkeletonFrameReady);
}

void MainWindow_Closed(object sender, EventArgs e)
{
	kinect.Uninitialize();
}

 

Obtener posiciones de las partes del cuerpo

Por medio de la función kinect_SkeletonFrameReady obtendremos los datos del esqueleto para después sacar las posiciones de las partes del cuerpo que nos interesan. En este caso necesitamos manos, codos, rodillas y pies. Utilizaremos un struct para hacerlo de una forma más limpia.

 

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

 

Con este struct crearemos un vector de datos por cada parte del cuerpo y después pasaremos esos datos al método que usaremos para identificar la postura que lo crearemos más adelante.

 

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;

			Vector3 handLeft = new Vector3();
			handLeft.X = skeleton.Joints[JointID.HandLeft].Position.X;
			handLeft.Y = skeleton.Joints[JointID.HandLeft].Position.Y;
			handLeft.Z = skeleton.Joints[JointID.HandLeft].Position.Z;
			Vector3 elbowRight = new Vector3();
			elbowRight.X = skeleton.Joints[JointID.ElbowRight].Position.X;
			elbowRight.Y = skeleton.Joints[JointID.ElbowRight].Position.Y;
			elbowRight.Z = skeleton.Joints[JointID.ElbowRight].Position.Z;

			Vector3 elbowLeft = new Vector3();
			elbowLeft.X = skeleton.Joints[JointID.ElbowLeft].Position.X;
			elbowLeft.Y = skeleton.Joints[JointID.ElbowLeft].Position.Y;
			elbowLeft.Z = skeleton.Joints[JointID.ElbowLeft].Position.Z;

			Vector3 kneeRight = new Vector3();
			kneeRight.X = skeleton.Joints[JointID.KneeRight].Position.X;
			kneeRight.Y = skeleton.Joints[JointID.KneeRight].Position.Y;
			kneeRight.Z = skeleton.Joints[JointID.KneeRight].Position.Z;

			Vector3 kneeLeft = new Vector3();
			kneeLeft.X = skeleton.Joints[JointID.KneeLeft].Position.X;
			kneeLeft.Y = skeleton.Joints[JointID.KneeLeft].Position.Y;
			kneeLeft.Z = skeleton.Joints[JointID.KneeLeft].Position.Z;

			Vector3 footRight = new Vector3();
			footRight.X = skeleton.Joints[JointID.FootRight].Position.X;
			footRight.Y = skeleton.Joints[JointID.FootRight].Position.Y;
			footRight.Z = skeleton.Joints[JointID.FootRight].Position.Z;

			Vector3 footLeft = new Vector3();
			footLeft.X = skeleton.Joints[JointID.FootLeft].Position.X;
			footLeft.Y = skeleton.Joints[JointID.FootLeft].Position.Y;
			footLeft.Z = skeleton.Joints[JointID.FootLeft].Position.Z;

			//CODIGO DE LLAMADA AL DETECTOR

 

Identificar la postura

Ahora crearemos el método que utilizaremos para identificar la postura. La postura no es muy complicada de identificar pero se tiene que hacer bastantes comprobaciones.

 

bool Cross(Vector3 handRight, Vector3 handLeft, Vector3 elbowRight, Vector3 elbowLeft,Vector3 kneeRight, Vector3 kneeLeft, Vector3 footRight, Vector3 footLeft)

 

Empezaremos por los brazos. Miraremos si la altura de manos y codos es la misma. Si es la misma entonces tendremos los brazos alineados paralelos al suelo.

 

if (Math.Abs(handRight.Y - handLeft.Y) > 0.01f || Math.Abs(elbowRight.Y - elbowLeft.Y) > 0.01f ||
Math.Abs(elbowRight.Y - handRight.Y) > 0.01f || Math.Abs(elbowLeft.Y - handLeft.Y) > 0.01f)

 

Lo siguiente es comprobar las piernas. Las piernas tienen que estar rectas perpendiculares al suelo. Para ello comprobaremos que cada pie está alineado con su rodilla correspondiente mirando que este en la misma coordenada X y si las rodillas están a la misma altura entre ellas, al igual que los pies.

 

if(distance(kneeRight.X, footRight.X) > 0.02f || distance(kneeLeft.X, footLeft.X) > 0.02f||
Math.Abs(kneeRight.Y - kneeLeft.Y) > 0.02f || Math.Abs(footRight.Y - footLeft.Y) > 0.02f)

 

La función distance se utiliza para calcular bien la distancia con el eje de coordenadas ya que el origen es el centro del sensor. Por ello al colocarnos en el centro podemos tener las piernas separadas siendo la propiedad X de una positiva y de la otra negativa y al restarlas podemos obtener un resultado erróneo.

 

float distance(float right, float left)
{
	if((right <0 &&left<0) ||(right >0 &&left>0))
		return Math.Abs(right-left);
	else
		return Math.Abs(right + left);
}

 

Con esta función calculamos la distancia de una forma u otra dependiendo de si las 2 partes del cuerpo están en la misma zona cartesiana o no.

Podemos añadir más comprobaciones como mirar que estén todas las partes del cuerpo a la misma distancia utilizando el eje Z o calcular la distancia entre pies y rodillas, etc.

Crear detector

Una vez que ya tenemos las posiciones de las partes del cuerpo y el método para identificar la postura implementaremos el código del detector añadiendo al enumerado de posturas la nueva postura.

 

const int PostureDetectionNumber = 10; 
int accumulator = 0; 
Posture postureInDetection = Posture.None; 
Posture previousPosture = Posture.None; 
public enum Posture 
{ 
	None, 
	Cross 
}

bool PostureDetector(Posture posture) 
{ 
	if (postureInDetection != posture) 
	{ 
		accumulator = 0; 
		postureInDetection = posture; 
		return false; 
	} 
	if (accumulator < PostureDetectionNumber) 
	{ 
		accumulator++; 
		return false; 
	} 
	if (posture != previousPosture) 
	{ 
		previousPosture =posture; 
		accumulator = 0; 
		return true; 
	} 
	else 
		accumulator = 0; 
	return false; 
}

 

El funcionamiento del detector está explicado en el post del reto.

Para finalizar tenemos que añadir al método kinect_SkeletonFrameReady la llamada al detector una vez que hemos detectado la postura, justo después del código donde obtenemos las posiciones de las partes del cuerpo.

 

//CODIGO DE LLAMADA AL DETECTOR
if (Cross(handRight, handLeft, elbowRight, elbowLeft, kneeRight, kneeLeft, footRight, footLeft)) 
{ 
	if (PostureDetector(Posture.Cross)) 
		label1.Content = previousPosture.ToString(); 
} 
else 
	if(PostureDetector(Posture.None)) 
		label1.Content = previousPosture.ToString();
}

 

Con esto damos por solucionado el tercer reto del SDK de Kinect: Detectar posturas con Skeletal tracking.

Microsoft está realizando una encuesta en línea para comprender su opinión del sitio web de. Si decide participar, se le presentará la encuesta en línea cuando abandone el sitio web de.

¿Desea participar?