Skip to main content

Solución Reto SDK de Kinect : Usar las cámaras del sensor

En el segundo reto sobre el SDK de Kinect aprendimos a obtener los datos de la cámara RGB y de las cámaras de profundidad. En el rato teníamos que partir del proyecto explicado en el que mostrábamos los datos de las cámaras en una aplicación y cambiar el código para que mostrara los píxeles correspondiente a un jugador de la imagen de profundidad de color amarillo.

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í.

Partimos de la estructura vista en este reto donde inicializamos en el método Loaded la clase Runtime, que nos permite usar las capacidades de las cámaras pero en esta ocasión debemos sustituir la opción RuntimeOptions.UseDepth por RuntimeOptions.DepthAndPlayerIndex. Tenemos también los métodos para abrir el flujo de datos de las cámaras y los eventos para capturar los Frames cuando estén listos.

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.UseColor | RuntimeOptions. DepthAndPlayerIndex);

	kinect.VideoStream.Open(ImageStreamType.Video, 2, ImageResolution.Resolution640x480, ImageType.Color);
	kinect.DepthStream.Open(ImageStreamType.Depth, 2, ImageResolution.Resolution320x240, ImageType.DepthAndPlayerIndex);

	kinect.VideoFrameReady += new EventHandler<ImageFrameReadyEventArgs>(kinect_VideoFrameReady);
	kinect.DepthFrameReady += new EventHandler<ImageFrameReadyEventArgs>(kinect_DepthFrameReady);

}

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

Obtener la distancia

Como hemos cambiado la opción del tipo de datos que vamos a obtener de la cámara de profundidad (de UseDepth a DepthAndPlayerIndex) debemos cambiar la forma de calcular la distancia de los píxeles según comentamos en el reto. Esto se hace en el método convertDepthFrame.

byte[] depthFrame32 = new byte[320 * 240 * 4];
byte[] convertDepthFrame(byte[] depthFrame16)
{
	for (int i16 = 0, i32 = 0; i16 < depthFrame16.Length && i32 < depthFrame32.Length; i16 += 2, i32 += 4)
	{
		//desplazar el primer byte 3, el segundo byte 5 posiciones y hacer la OR 
		int distance = ((depthFrame16[i16]>>3) | (depthFrame16[i16 + 1] << 5));

Colorear el píxel según la distancia

El siguiente paso era crear el píxel para la imagen de un color dependiendo del valor de la distancia. Esta parte se queda igual que estaba.

if (distance <= 900)
{
	depthFrame32[i32 + RED_IDX] = 0;
	depthFrame32[i32 + GREEN_IDX] = 0;
	depthFrame32[i32 + BLUE_IDX] = 255;
}

else if (distance > 900 && distance < 2000)
{
	depthFrame32[i32 + RED_IDX] = 0;
	depthFrame32[i32 + GREEN_IDX] = 255;
	depthFrame32[i32 + BLUE_IDX] = 0;
}

else if (distance > 2000)
{
	depthFrame32[i32 + RED_IDX] = 255;
	depthFrame32[i32 + GREEN_IDX] = 0;
	depthFrame32[i32 + BLUE_IDX] = 0;
}

Identificar al jugador

Ahora sólo tenemos que averiguar si el píxel corresponde con un jugador o no y si corresponde asignar el color amarillo a la imagen. El número del jugador se obtiene a partir de los 3 primeros bits del byte, por ello hacemos una AND con el valor 7.

int player = depthFrame16[i16] & 0x07;
if (player!= 0)
{
	depthFrame32[i32 + RED_IDX] = 255;
	depthFrame32[i32 + GREEN_IDX] = 255;
	depthFrame32[i32 + BLUE_IDX] = 0;
}

Mostrar el resultado

Ahora tenemos que mostrar la imagen que creamos. Para ello utilizamos el método kinect_DepthFrameReady donde obtenemos los datos de la cámara y se los pasamos a la función que acabamos de crear para que los codifique. Con el resultado creamos un BitmapSource para después mostrarlo en un elemento imagen que hemos añadido a nuestra ventana principal.

void kinect_DepthFrameReady(object sender, ImageFrameReadyEventArgs e)

{

PlanarImage Image = e.ImageFrame.Image;

byte[] convertedFrame = convertDepthFrame(Image.Bits);

image2.Source = BitmapSource.Create(Image.Width, Image.Height, 96, 96, PixelFormats.Bgr32, null, convertedFrame, Image.Width * 4);

}

Con estos cambios ya tenemos el reto solucionado.

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?