Getting started with Microsoft Kinect SDK - Depth
Written by Mike James   
Friday, 08 July 2011
Article Index
Getting started with Microsoft Kinect SDK - Depth
Working with Windows Forms
A depth histogram

 

Displaying the image - Windows Forms

The next big problem is finding a way to display a depth frame. As the data take the form of a 13-bit image the most obvious thing to do is convert it into a grey scale image. This is where we hit a small snag. While Windows Forms supports the Format16bppGrayScale constant it doesn't actually support the type. That is you can't load up a Bitmap object with grey scale data and then display it using a PictureBox - it just shows as a big red cross.

So what can we do?

One answer, although it is a bit of a cheat, is to simply use the Format16bppRgb555 format which is supported. This treats a 16-bit value so that 5 bits are used for each of R,G and B and the topmost bit is ignored. So using the same general approach to transferring the bits from the PlanarImage to a Bitmap we first need a Bitmap in the correct format and size:


Bitmap bmap = new Bitmap(
PImage.Width,
PImage.Height,
PixelFormat.Format16bppRgb555);

Next we create and lock a BitMapData object using the same size and format:

BitmapData bmapdata = bmap.LockBits(
new Rectangle(0, 0, PImage.Width,
PImage.Height),
ImageLockMode.WriteOnly,
bmap.PixelFormat);
Finally we copy the bits from the PlanarImage to the BitmapData object and then unlock it to place the bits into the Bitmap object:
IntPtr ptr = bmapdata.Scan0;
Marshal.Copy(PImage.Bits,
0,
ptr,
PImage.Width *
PImage.BytesPerPixel *
PImage.Height);
bmap.UnlockBits(bmapdata);

To make this work we need to add:

using System.Drawing.Imaging;
using System.Runtime.InteropServices;

at the start of the program.

If you now place a PictureBox control on the form you can view the depth data:

pictureBox1.Image = bmap;

Distance1

The entire function is:

Bitmap DepthToBitmap(PlanarImage PImage)
{
Bitmap bmap = new Bitmap(
PImage.Width,
PImage.Height,
PixelFormat.Format16bppRgb555);
BitmapData bmapdata = bmap.LockBits(
new Rectangle(0, 0, PImage.Width,
PImage.Height),
ImageLockMode.WriteOnly,
bmap.PixelFormat);
IntPtr ptr = bmapdata.Scan0;
Marshal.Copy(PImage.Bits,
0,
ptr,
PImage.Width *
PImage.BytesPerPixel *
PImage.Height);
bmap.UnlockBits(bmapdata);
return bmap;
}

This is a quick and easy way to get a false color display of the depth data but it isn't particularly good as the R channel isn't used. We can improve it slightly by shifting each depth value by 2 bits to the left. The reason is that the color is determined by 15 bits but the depth field is only a 13-bit value - this only leaves the top two bits to control the red. To do this involves some bit manipulation. First we put the two bytes that make up the 13-bit value together into a single 32-bit integer:

int temp= (PImage.Bits[i+1]<<8 | 
PImage.Bits[i]) ;

Then we shift the 32-bit integer two places to the left:

temp <<= 2;

and splitout the high and low bytes back into the array:

PImage.Bits[i] = (byte) (temp & 0xFF);
PImage.Bits[i + 1] = (byte) (temp >> 8);

Putting this together with a for loop that scans the entire byte array gives:

int temp= 0; 
for (int i = 0; i < PImage.Bits.Length; i += 2)
{
temp= (PImage.Bits[i+1]<<8 | PImage.Bits[i]) ;
temp <<= 2;
PImage.Bits[i] = (byte) (temp & 0xFF);
PImage.Bits[i + 1] = (byte) (temp >> 8);
}

Distance2

Displaying the Image - WPF

If you want to use WPF then things are a little easier but there are still some odd problems to sort out. The WPF BitmapSource class does support a much wider range of pixel formats. including gray16. To convert the PlanarImage to a BitmapSource is almost trivial:

BitmapSource DepthToBitmapSource(
PlanarImage PImage)
{
BitmapSource bmap = BitmapSource.Create(
PImage.Width,
PImage.Height,
96, 96,
PixelFormats.Gray16,
null,
PImage.Bits,
PImage.Width * PImage.BytesPerPixel);
return bmap;
}

And if you place an Image control on the form you can display the result:

image1.Source = DepthToBitmapSource(PImage);

If you try this out you will most probably discover that the result is black or at best very dark. The reason for this is that the depth field occupies only the lower 13 bits of the 16 available which means that most of the time the distances are rendered as black or very dark grey. To solve this problem we need to adjust the values by shifting the 13 bits two places to the left. This can be done in exactly the same way as the color modification made in the previous section:

 for (int i = 0; 
i < PImage.Bits.Length; i += 2)
{
temp = (PImage.Bits[i + 1] << 8 |
PImage.Bits[i]);
temp <<2;
PImage.Bits[i] = (byte)(temp & 0xFF);
PImage.Bits[i + 1] = (byte)(temp >> 8);
}
image1.Source = DepthToBitmapSource(PImage);
}

 

Distance3



Last Updated ( Monday, 06 February 2012 )