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); } } }