using Microsoft.Kinect;
using System;
using System.ComponentModel;
using System.Globalization;
using System.IO;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace KinectConnection
{
///
/// The depth image stream.
///
public class DepthImageStream : KinectStream
{
///
/// Map depth range to byte range
///
private const int MapDepthToByte = 8000 / 256;
///
/// Active Kinect sensor
///
private KinectSensor kinectSensor = null;
///
/// Reader for depth frames
///
private DepthFrameReader depthFrameReader = null;
///
/// Description of the data contained in the depth frame
///
private FrameDescription depthFrameDescription = null;
///
/// Bitmap to display
///
private WriteableBitmap depthBitmap = null;
///
/// Intermediate storage for frame data converted to color
///
private byte[] depthPixels = null;
///
/// Gets the bitmap to display
///
public override ImageSource Source
{
get
{
return this.depthBitmap;
}
}
public override void Start()
{
if (this.KinectSensor != null)
{
// open the reader for the depth frames
this.depthFrameReader = this.KinectSensor.DepthFrameSource.OpenReader();
if (this.depthFrameReader != null)
{
// wire handler for frame arrival
this.depthFrameReader.FrameArrived += this.Reader_FrameArrived;
}
}
}
public override void Stop()
{
if (this.depthFrameReader != null)
{
this.depthFrameReader.FrameArrived -= this.Reader_FrameArrived;
// Dispose the reader to free resources.
// If we don't dispose manualy, the gc will do it for us, but we don't know when.
this.depthFrameReader.Dispose();
this.depthFrameReader = null;
}
}
public DepthImageStream() : base()
{
// get FrameDescription from DepthFrameSource
this.depthFrameDescription = this.KinectSensor.DepthFrameSource.FrameDescription;
// allocate space to put the pixels being received and converted
this.depthPixels = new byte[this.depthFrameDescription.Width * this.depthFrameDescription.Height];
// create the bitmap to display
this.depthBitmap = new WriteableBitmap(this.depthFrameDescription.Width, this.depthFrameDescription.Height, 96.0, 96.0, PixelFormats.Gray8, null);
}
///
/// Handles the depth frame data arriving from the sensor
///
/// object sending the event
/// event arguments
private void Reader_FrameArrived(object sender, DepthFrameArrivedEventArgs e)
{
bool depthFrameProcessed = false;
using (DepthFrame depthFrame = e.FrameReference.AcquireFrame())
{
if (depthFrame != null)
{
// the fastest way to process the body index data is to directly access
// the underlying buffer
using (Microsoft.Kinect.KinectBuffer depthBuffer = depthFrame.LockImageBuffer())
{
// verify data and write the color data to the display bitmap
if (((this.depthFrameDescription.Width * this.depthFrameDescription.Height) == (depthBuffer.Size / this.depthFrameDescription.BytesPerPixel)) &&
(this.depthFrameDescription.Width == this.depthBitmap.PixelWidth) && (this.depthFrameDescription.Height == this.depthBitmap.PixelHeight))
{
// Note: In order to see the full range of depth (including the less reliable far field depth)
// we are setting maxDepth to the extreme potential depth threshold
ushort maxDepth = ushort.MaxValue;
// If you wish to filter by reliable depth distance, uncomment the following line:
//// maxDepth = depthFrame.DepthMaxReliableDistance
this.ProcessDepthFrameData(depthBuffer.UnderlyingBuffer, depthBuffer.Size, depthFrame.DepthMinReliableDistance, maxDepth);
depthFrameProcessed = true;
}
}
}
}
if (depthFrameProcessed)
{
this.RenderDepthPixels();
}
}
///
/// Directly accesses the underlying image buffer of the DepthFrame to
/// create a displayable bitmap.
/// This function requires the /unsafe compiler option as we make use of direct
/// access to the native memory pointed to by the depthFrameData pointer.
///
/// Pointer to the DepthFrame image data
/// Size of the DepthFrame image data
/// The minimum reliable depth value for the frame
/// The maximum reliable depth value for the frame
private unsafe void ProcessDepthFrameData(IntPtr depthFrameData, uint depthFrameDataSize, ushort minDepth, ushort maxDepth)
{
// depth frame data is a 16 bit value
ushort* frameData = (ushort*)depthFrameData;
// convert depth to a visual representation
for (int i = 0; i < (int)(depthFrameDataSize / this.depthFrameDescription.BytesPerPixel); ++i)
{
// Get the depth for this pixel
ushort depth = frameData[i];
// To convert to a byte, we're mapping the depth value to the byte range.
// Values outside the reliable depth range are mapped to 0 (black).
this.depthPixels[i] = (byte)(depth >= minDepth && depth <= maxDepth ? (depth / MapDepthToByte) : 0);
}
}
///
/// Renders color pixels into the writeableBitmap.
///
private void RenderDepthPixels()
{
this.depthBitmap.WritePixels(
new Int32Rect(0, 0, this.depthBitmap.PixelWidth, this.depthBitmap.PixelHeight),
this.depthPixels,
this.depthBitmap.PixelWidth,
0);
}
}
}