//------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // //------------------------------------------------------------------------------ using System.ComponentModel; using System.IO; using System.Runtime.InteropServices.WindowsRuntime; using Windows.ApplicationModel.Resources; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Media.Imaging; using WindowsPreview.Kinect; namespace Microsoft.Samples.Kinect.DepthBasics { /// /// Main page for sample /// public sealed partial class MainPage : Page, INotifyPropertyChanged { /// /// Map depth range to byte range /// private const int MapDepthToByte = 8000 / 256; /// /// Resource loader for string resources /// #if WIN81ORLATER private ResourceLoader resourceLoader = ResourceLoader.GetForCurrentView("Resources"); #else private ResourceLoader resourceLoader = new ResourceLoader("Resources"); #endif /// /// Size of the RGB pixel in the bitmap /// private readonly int cbytesPerPixel = 4; /// /// Active Kinect sensor /// private KinectSensor kinectSensor = null; /// /// Reader for depth frames /// private DepthFrameReader depthFrameReader = null; /// /// Bitmap to display /// private WriteableBitmap bitmap = null; /// /// Intermediate storage for receiving frame data from the sensor /// private ushort[] depthFrameData = null; /// /// Intermediate storage for frame data converted to color /// private byte[] depthPixels = null; /// /// Current status text to display /// private string statusText = null; /// /// Initializes a new instance of the MainPage class. /// public MainPage() { // get the kinectSensor object this.kinectSensor = KinectSensor.GetDefault(); // get the depthFrameDescription from the DepthFrameSource FrameDescription depthFrameDescription = this.kinectSensor.DepthFrameSource.FrameDescription; // open the reader for the depth frames this.depthFrameReader = this.kinectSensor.DepthFrameSource.OpenReader(); // wire handler for frame arrival this.depthFrameReader.FrameArrived += this.Reader_DepthFrameArrived; // allocate space to put the pixels being received and converted this.depthFrameData = new ushort[depthFrameDescription.Width * depthFrameDescription.Height]; this.depthPixels = new byte[depthFrameDescription.Width * depthFrameDescription.Height * this.cbytesPerPixel]; // create the bitmap to display this.bitmap = new WriteableBitmap(depthFrameDescription.Width, depthFrameDescription.Height);//, 96.0, 96.0, PixelFormats.Bgr32, null); // set IsAvailableChanged event notifier this.kinectSensor.IsAvailableChanged += this.Sensor_IsAvailableChanged; // open the sensor this.kinectSensor.Open(); // set the status text this.StatusText = this.kinectSensor.IsAvailable ? resourceLoader.GetString("RunningStatusText") : resourceLoader.GetString("NoSensorStatusText"); // use the window object as the view model in this simple example this.DataContext = this; // initialize the components (controls) of the window this.InitializeComponent(); } /// /// INotifyPropertyChangedPropertyChanged event to allow window controls to bind to changeable data. /// public event PropertyChangedEventHandler PropertyChanged; /// /// Gets or sets the current status text to display /// public string StatusText { get { return this.statusText; } set { if (this.statusText != value) { this.statusText = value; // notify any bound elements that the text has changed if (this.PropertyChanged != null) { this.PropertyChanged(this, new PropertyChangedEventArgs("StatusText")); } } } } /// /// Execute shutdown tasks. /// /// object sending the event /// event arguments private void MainPage_Unloaded(object sender, RoutedEventArgs e) { if (this.depthFrameReader != null) { // DepthFrameReder is IDisposable this.depthFrameReader.Dispose(); this.depthFrameReader = null; } if (this.kinectSensor != null) { this.kinectSensor.Close(); this.kinectSensor = null; } } /// /// Handles the depth frame data arriving from the sensor. /// /// object sending the event /// event arguments private void Reader_DepthFrameArrived(object sender, DepthFrameArrivedEventArgs e) { ushort minDepth = 0; ushort maxDepth = 0; bool depthFrameProcessed = false; // DepthFrame is IDisposable using (DepthFrame depthFrame = e.FrameReference.AcquireFrame()) { if (depthFrame != null) { FrameDescription depthFrameDescription = depthFrame.FrameDescription; // verify data and write the new depth frame data to the display bitmap if (((depthFrameDescription.Width * depthFrameDescription.Height) == this.depthFrameData.Length) && (depthFrameDescription.Width == this.bitmap.PixelWidth) && (depthFrameDescription.Height == this.bitmap.PixelHeight)) { // Copy the pixel data from the image to a temporary array depthFrame.CopyFrameDataToArray(this.depthFrameData); minDepth = depthFrame.DepthMinReliableDistance; // 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 maxDepth = ushort.MaxValue; // If you wish to filter by reliable depth distance, uncomment the following line: //// maxDepth = depthFrame.DepthMaxReliableDistance depthFrameProcessed = true; } } } // we got a frame, convert and render if (depthFrameProcessed) { ConvertDepthData(minDepth, maxDepth); RenderDepthPixels(this.depthPixels); } } /// /// Converts depth to RGB. /// /// private void ConvertDepthData(ushort minDepth, ushort maxDepth) { int colorPixelIndex = 0; for (int i = 0; i < this.depthFrameData.Length; ++i) { // Get the depth for this pixel ushort depth = this.depthFrameData[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). byte intensity = (byte)(depth >= minDepth && depth <= maxDepth ? (depth / MapDepthToByte) : 0); // Write out blue byte this.depthPixels[colorPixelIndex++] = intensity; // Write out green byte this.depthPixels[colorPixelIndex++] = intensity; // Write out red byte this.depthPixels[colorPixelIndex++] = intensity; // Write out alpha byte this.depthPixels[colorPixelIndex++] = 255; } } /// /// Renders color pixels into the writeableBitmap. /// /// pixel data private void RenderDepthPixels(byte[] pixels) { pixels.CopyTo(this.bitmap.PixelBuffer); this.bitmap.Invalidate(); theImage.Source = this.bitmap; } /// /// Handles the event which the sensor becomes unavailable (E.g. paused, closed, unplugged). /// /// object sending the event /// event arguments private void Sensor_IsAvailableChanged(object sender, IsAvailableChangedEventArgs e) { // on failure, set the status text this.StatusText = this.kinectSensor.IsAvailable ? resourceLoader.GetString("RunningStatusText") : resourceLoader.GetString("SensorNotAvailableStatusText"); } } }