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 infrared image stream. /// public class InfraredImageStream : KinectStream { /// /// Maximum value (as a float) that can be returned by the InfraredFrame /// private const float InfraredSourceValueMaximum = (float)ushort.MaxValue; /// /// The value by which the infrared source data will be scaled /// private const float InfraredSourceScale = 0.75f; /// /// Smallest value to display when the infrared data is normalized /// private const float InfraredOutputValueMinimum = 0.01f; /// /// Largest value to display when the infrared data is normalized /// private const float InfraredOutputValueMaximum = 1.0f; /// /// Active Kinect sensor /// private KinectSensor kinectSensor = null; /// /// Reader for infrared frames /// private InfraredFrameReader infraredFrameReader = null; /// /// Description (width, height, etc) of the infrared frame data /// private FrameDescription infraredFrameDescription = null; /// /// Bitmap to display /// private WriteableBitmap infraredBitmap = null; /// /// Current status text to display /// private string statusText = null; /// /// Gets the bitmap to display /// public override ImageSource Source { get { return this.infraredBitmap; } } /// /// Execute shutdown tasks /// /// object sending the event /// event arguments private void MainWindow_Closing(object sender, CancelEventArgs e) { if (this.infraredFrameReader != null) { // InfraredFrameReader is IDisposable this.infraredFrameReader.Dispose(); this.infraredFrameReader = null; } if (this.kinectSensor != null) { this.kinectSensor.Close(); this.kinectSensor = null; } } public InfraredImageStream() { // get FrameDescription from InfraredFrameSource this.infraredFrameDescription = this.KinectSensor.InfraredFrameSource.FrameDescription; // create the bitmap to display this.infraredBitmap = new WriteableBitmap(this.infraredFrameDescription.Width, this.infraredFrameDescription.Height, 96.0, 96.0, PixelFormats.Gray32Float, null); } public override void Start() { if (this.KinectSensor != null) { // open the reader for the depth frames this.infraredFrameReader = this.KinectSensor.InfraredFrameSource.OpenReader(); if (this.infraredFrameReader != null) { // wire handler for frame arrival this.infraredFrameReader.FrameArrived += this.Reader_InfraredFrameArrived; } } } public override void Stop() { if (this.infraredFrameReader != null) { this.infraredFrameReader.FrameArrived -= this.Reader_InfraredFrameArrived; // 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.infraredFrameReader.Dispose(); this.infraredFrameReader = null; } } /// /// Handles the infrared frame data arriving from the sensor /// /// object sending the event /// event arguments private void Reader_InfraredFrameArrived(object sender, InfraredFrameArrivedEventArgs e) { // InfraredFrame is IDisposable using (InfraredFrame infraredFrame = e.FrameReference.AcquireFrame()) { if (infraredFrame != null) { // the fastest way to process the infrared frame data is to directly access // the underlying buffer using (Microsoft.Kinect.KinectBuffer infraredBuffer = infraredFrame.LockImageBuffer()) { // verify data and write the new infrared frame data to the display bitmap if (((this.infraredFrameDescription.Width * this.infraredFrameDescription.Height) == (infraredBuffer.Size / this.infraredFrameDescription.BytesPerPixel)) && (this.infraredFrameDescription.Width == this.infraredBitmap.PixelWidth) && (this.infraredFrameDescription.Height == this.infraredBitmap.PixelHeight)) { this.ProcessInfraredFrameData(infraredBuffer.UnderlyingBuffer, infraredBuffer.Size); } } } } } /// /// Directly accesses the underlying image buffer of the InfraredFrame 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 infraredFrameData pointer. /// /// Pointer to the InfraredFrame image data /// Size of the InfraredFrame image data private unsafe void ProcessInfraredFrameData(IntPtr infraredFrameData, uint infraredFrameDataSize) { // infrared frame data is a 16 bit value ushort* frameData = (ushort*)infraredFrameData; // lock the target bitmap this.infraredBitmap.Lock(); // get the pointer to the bitmap's back buffer float* backBuffer = (float*)this.infraredBitmap.BackBuffer; // process the infrared data for (int i = 0; i < (int)(infraredFrameDataSize / this.infraredFrameDescription.BytesPerPixel); ++i) { // since we are displaying the image as a normalized grey scale image, we need to convert from // the ushort data (as provided by the InfraredFrame) to a value from [InfraredOutputValueMinimum, InfraredOutputValueMaximum] backBuffer[i] = Math.Min(InfraredOutputValueMaximum, (((float)frameData[i] / InfraredSourceValueMaximum * InfraredSourceScale) * (1.0f - InfraredOutputValueMinimum)) + InfraredOutputValueMinimum); } // mark the entire bitmap as needing to be drawn this.infraredBitmap.AddDirtyRect(new Int32Rect(0, 0, this.infraredBitmap.PixelWidth, this.infraredBitmap.PixelHeight)); // unlock the bitmap this.infraredBitmap.Unlock(); } } }