Wednesday, November 26, 2014

Kinect for Windows 2 and XNA demo

Over the Thanksgiving break I managed to get my new Kinect for Windows 2 working with XNA. I couldn't find any code samples online using XNA with the new Kinect SDK, so hopefully this will help out others who are trying to do something similar.

This demo will show how to display the Kinect's video feed which is provided by its 1080p color camera. This is similar to the Color Basics-WPF C# Sample provided in the Kinect SDK 2 except that it is tailored for XNA.


Prerequisites

You must have the Kinect for Windows 2 correctly installed along with the SDK. There are plenty of online tutorials showing you how to program with the older Kinect; this is for the latest version.

Microsoft is no longer maintaining XNA, but but you can still use it in Visual Studio 2013. There are two different ways to get XNA working with VS2013:

Quick Way

Install XNA 4.0 Refresh for VS 2013. The zip file contains four components that you will need to install in succession.

Long Way

If you have VS 2010 laying around, this method will also work although it takes much longer. I found this method necessary when installing XNA in a lab setting. Using the Quick Way would not work for users who were not administrators.

  1. Install Visual Studio 2010. Any edition will work.
  2. Install Games for Windows Marketplace Client
  3. Install XNA Game Studio 4.0
  4. Install XNA 4.0 Refresh for VS 2013. After you have downloaded the zip file, extract it and run XNA Game Studio 4.0.vsix

If you want to skip both these options, you might try MonoGame. Just be aware that it does not have a content pipeline converter (software that converts content like sound files into xnb files). I have not tried MonoGame with Kinect, but I don't see any reason why it wouldn't work.


Create an XNA Project

First create an XNA project by selecting FileProject... from the menu. Then select XNA Game Studio 4.0 template under Visual C# and select Windows Game (2.0). Name the project KinectVideoXna.


Add Kinect Reference

Right-click the project in the Solution Explorer and from the context menu select AddReference.... Type kinect in the dialog box's search box, and check the Microsoft.Kinect reference. Then press OK. You should now see Microsoft.Kinect among the project's References in the Solution Explorer.


Adding Code

Add the Kinect namespace:

using Microsoft.Kinect;

Add some class-level variables:

// Texture to draw
Texture2D videoTexture;

// Active Kinect sensor
private KinectSensor kinectSensor;

// Reader for color frames
private ColorFrameReader colorFrameReader;
        
// Intermediate storage for receiving frame data from the sensor
private byte[] colorPixels;

Initialize the sensor and the data structures used for capturing data from the sensors:

protected override void Initialize()
{
 kinectSensor = KinectSensor.GetDefault();

 // Open the reader for the color frames
 colorFrameReader = 
  kinectSensor.ColorFrameSource.OpenReader();

 // Specify a handler for frame arrival
 colorFrameReader.FrameArrived += Reader_ColorFrameArrived;

 // Create the ColorFrameDescription using rgba format
 FrameDescription desc = kinectSensor.ColorFrameSource.
  CreateFrameDescription(ColorImageFormat.Rgba);
 
 // Allocate space to put the pixels to be rendered
 colorPixels = new byte[desc.Width * desc.Height * 
  desc.BytesPerPixel];

 // Open the sensor
 kinectSensor.Open();

 // Create texture large enough to hold the color frame
 videoTexture = new Texture2D(graphics.GraphicsDevice, 
  desc.Width, desc.Height);

 base.Initialize();
}

Also override the OnExiting method to free up the ColorFrameReder and Kinect sensor when the game exists:

protected override void OnExiting(object sender, EventArgs args)
{
 if (colorFrameReader != null)
 {
  colorFrameReader.Dispose();
  colorFrameReader = null;
 }

 if (kinectSensor != null)
 {
  kinectSensor.Close();
  kinectSensor = null;
 }

 base.OnExiting(sender, args);
}

Create the handler for the color photo sensor where we'll store the captured photo into videoTexture:

private void Reader_ColorFrameArrived(object sender, ColorFrameArrivedEventArgs e)
{          
 // ColorFrame is IDisposable
 using (ColorFrame colorFrame = e.FrameReference.AcquireFrame())
 {
  if (colorFrame != null)
  {
   // Copy color frame into the array
   colorFrame.CopyConvertedFrameDataToArray(
    colorPixels, 
    ColorImageFormat.Rgba);                   

   // Avoid exception when SetData method is used
   GraphicsDevice.Textures[0] = null;

   // Put pixel data into a texture
   videoTexture.SetData(colorPixels);
  }
 }
}

Finally, draw the videoTexture containing the color photo to the screen:

protected override void Draw(GameTime gameTime)
{
 GraphicsDevice.Clear(Color.CornflowerBlue);

 if (videoTexture != null)
 {
  // Draw color video
  spriteBatch.Begin();
  spriteBatch.Draw(videoTexture, new Rectangle(0, 0, 
   graphics.GraphicsDevice.Viewport.Width,
   graphics.GraphicsDevice.Viewport.Height), 
   Color.White);
  spriteBatch.End();
 }

 base.Draw(gameTime);
}

Press Ctrl-F5 to build and run the program. You should see color video of whatever your Kinect is pointed at.


Problems?

When I first tried to build and run my program, I got the following error message:

The primary reference "Microsoft.Kinect, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" could not be resolved because it was built against the ".NETFramework,Version=v4.5" framework. This is a higher version than the currently targeted framework ".NETFramework,Version=b4.0".
To fix this problem, I closed the project in Visual Studio and opened the project's .csproj file in a text editor and changed the following line:
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
to
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
Then I re-opened the project in Visual Studio and re-built the application with no problems.