You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
290 lines
12 KiB
290 lines
12 KiB
//------------------------------------------------------------------------------
|
|
// <copyright file="MainPage.xaml.cs" company="Microsoft">
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
// </copyright>
|
|
//------------------------------------------------------------------------------
|
|
|
|
using System;
|
|
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.InfraredBasics
|
|
{
|
|
/// <summary>
|
|
/// Main page for sample
|
|
/// </summary>
|
|
public sealed partial class MainPage : Page, INotifyPropertyChanged
|
|
{
|
|
/// <summary>
|
|
/// InfraredSourceValueMaximum is the highest value that can be returned in the InfraredFrame.
|
|
/// It is cast to a float for readability in the visualization code.
|
|
/// </summary>
|
|
private const float InfraredSourceValueMaximum = (float)ushort.MaxValue;
|
|
|
|
/// <summary>
|
|
/// The InfraredOutputValueMinimum value is used to set the lower limit, post processing, of the
|
|
/// infrared data that we will render.
|
|
/// Increasing or decreasing this value sets a brightness "wall" either closer or further away.
|
|
/// </summary>
|
|
private const float InfraredOutputValueMinimum = 0.01f;
|
|
|
|
/// <summary>
|
|
/// The InfraredOutputValueMaximum value is the upper limit, post processing, of the
|
|
/// infrared data that we will render.
|
|
/// </summary>
|
|
private const float InfraredOutputValueMaximum = 1.0f;
|
|
|
|
/// <summary>
|
|
/// The InfraredSceneValueAverage value specifies the average infrared value of the scene.
|
|
/// This value was selected by analyzing the average pixel intensity for a given scene.
|
|
/// Depending on the visualization requirements for a given application, this value can be
|
|
/// hard coded, as was done here, or calculated by averaging the intensity for each pixel prior
|
|
/// to rendering.
|
|
/// </summary>
|
|
private const float InfraredSceneValueAverage = 0.08f;
|
|
|
|
/// <summary>
|
|
/// The InfraredSceneStandardDeviations value specifies the number of standard deviations
|
|
/// to apply to InfraredSceneValueAverage. This value was selected by analyzing data
|
|
/// from a given scene.
|
|
/// Depending on the visualization requirements for a given application, this value can be
|
|
/// hard coded, as was done here, or calculated at runtime.
|
|
/// </summary>
|
|
private const float InfraredSceneStandardDeviations = 3.0f;
|
|
|
|
/// <summary>
|
|
/// Size of the RGB pixel in the bitmap
|
|
/// </summary>
|
|
private const int BytesPerPixel = 4;
|
|
|
|
/// <summary>
|
|
/// Resource loader for string resources
|
|
/// </summary>
|
|
#if WIN81ORLATER
|
|
private ResourceLoader resourceLoader = ResourceLoader.GetForCurrentView("Resources");
|
|
#else
|
|
private ResourceLoader resourceLoader = new ResourceLoader("Resources");
|
|
#endif
|
|
|
|
/// <summary>
|
|
/// Active Kinect sensor
|
|
/// </summary>
|
|
private KinectSensor kinectSensor = null;
|
|
|
|
/// <summary>
|
|
/// Reader for infrared frames
|
|
/// </summary>
|
|
private InfraredFrameReader infraredFrameReader = null;
|
|
|
|
/// <summary>
|
|
/// Bitmap to display
|
|
/// </summary>
|
|
private WriteableBitmap bitmap = null;
|
|
|
|
/// <summary>
|
|
/// Intermediate storage for receiving frame data from the sensor
|
|
/// </summary>
|
|
private ushort[] infraredFrameData = null;
|
|
|
|
/// <summary>
|
|
/// Intermediate storage for frame data converted to color
|
|
/// </summary>
|
|
private byte[] infraredPixels = null;
|
|
|
|
/// <summary>
|
|
/// Current status text to display
|
|
/// </summary>
|
|
private string statusText = null;
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the MainPage class.
|
|
/// </summary>
|
|
public MainPage()
|
|
{
|
|
// get the kinectSensor object
|
|
this.kinectSensor = KinectSensor.GetDefault();
|
|
|
|
// get the infraredFrameDescription from the InfraredFrameSource
|
|
FrameDescription infraredFrameDescription = this.kinectSensor.InfraredFrameSource.FrameDescription;
|
|
|
|
// open the reader for the infrared frames
|
|
this.infraredFrameReader = this.kinectSensor.InfraredFrameSource.OpenReader();
|
|
|
|
// wire handler for frame arrival
|
|
this.infraredFrameReader.FrameArrived += this.Reader_InfraredFrameArrived;
|
|
|
|
// allocate space to put the pixels being received and converted
|
|
this.infraredFrameData = new ushort[infraredFrameDescription.Width * infraredFrameDescription.Height];
|
|
this.infraredPixels = new byte[infraredFrameDescription.Width * infraredFrameDescription.Height * BytesPerPixel];
|
|
|
|
// create the bitmap to display
|
|
this.bitmap = new WriteableBitmap(infraredFrameDescription.Width, infraredFrameDescription.Height);
|
|
|
|
// 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();
|
|
}
|
|
|
|
/// <summary>
|
|
/// INotifyPropertyChangedPropertyChanged event to allow window controls to bind to changeable data.
|
|
/// </summary>
|
|
public event PropertyChangedEventHandler PropertyChanged;
|
|
|
|
/// <summary>
|
|
/// Gets or sets the current status text to display
|
|
/// </summary>
|
|
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"));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Execute shutdown tasks.
|
|
/// </summary>
|
|
/// <param name="sender">object sending the event</param>
|
|
/// <param name="e">event arguments</param>
|
|
private void MainPage_Unloaded(object sender, RoutedEventArgs e)
|
|
{
|
|
if (this.infraredFrameReader != null)
|
|
{
|
|
// InfraredFrameReder is IDisposable
|
|
this.infraredFrameReader.Dispose();
|
|
this.infraredFrameReader = null;
|
|
}
|
|
|
|
if (this.kinectSensor != null)
|
|
{
|
|
this.kinectSensor.Close();
|
|
this.kinectSensor = null;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Handles the infrared frame data arriving from the sensor.
|
|
/// </summary>
|
|
/// <param name="sender">object sending the event</param>
|
|
/// <param name="e">event arguments</param>
|
|
private void Reader_InfraredFrameArrived(object sender, InfraredFrameArrivedEventArgs e)
|
|
{
|
|
bool infraredFrameProcessed = false;
|
|
|
|
// InfraredFrame is IDisposable
|
|
using (InfraredFrame infraredFrame = e.FrameReference.AcquireFrame())
|
|
{
|
|
if (infraredFrame != null)
|
|
{
|
|
FrameDescription infraredFrameDescription = infraredFrame.FrameDescription;
|
|
|
|
// verify data and write the new infrared frame data to the display bitmap
|
|
if (((infraredFrameDescription.Width * infraredFrameDescription.Height) == this.infraredFrameData.Length) &&
|
|
(infraredFrameDescription.Width == this.bitmap.PixelWidth) && (infraredFrameDescription.Height == this.bitmap.PixelHeight))
|
|
{
|
|
// Copy the pixel data from the image to a temporary array
|
|
infraredFrame.CopyFrameDataToArray(this.infraredFrameData);
|
|
|
|
infraredFrameProcessed = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
// we got a frame, convert and render
|
|
if (infraredFrameProcessed)
|
|
{
|
|
this.ConvertInfraredData();
|
|
this.RenderInfraredPixels(this.infraredPixels);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Convert infrared to RGB.
|
|
/// </summary>
|
|
private void ConvertInfraredData()
|
|
{
|
|
// Convert the infrared to RGB
|
|
int colorPixelIndex = 0;
|
|
for (int i = 0; i < this.infraredFrameData.Length; ++i)
|
|
{
|
|
// normalize the incoming infrared data (ushort) to a float ranging from
|
|
// [InfraredOutputValueMinimum, InfraredOutputValueMaximum] by
|
|
// 1. dividing the incoming value by the source maximum value
|
|
float intensityRatio = (float)this.infraredFrameData[i] / InfraredSourceValueMaximum;
|
|
|
|
// 2. dividing by the (average scene value * standard deviations)
|
|
intensityRatio /= InfraredSceneValueAverage * InfraredSceneStandardDeviations;
|
|
|
|
// 3. limiting the value to InfraredOutputValueMaximum
|
|
intensityRatio = Math.Min(InfraredOutputValueMaximum, intensityRatio);
|
|
|
|
// 4. limiting the lower value InfraredOutputValueMinimym
|
|
intensityRatio = Math.Max(InfraredOutputValueMinimum, intensityRatio);
|
|
|
|
// 5. converting the normalized value to a byte and using the result
|
|
// as the RGB components required by the image
|
|
byte intensity = (byte)(intensityRatio * 255.0f);
|
|
this.infraredPixels[colorPixelIndex++] = intensity;
|
|
this.infraredPixels[colorPixelIndex++] = intensity;
|
|
this.infraredPixels[colorPixelIndex++] = intensity;
|
|
this.infraredPixels[colorPixelIndex++] = 255;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Renders color pixels into the writeableBitmap.
|
|
/// </summary>
|
|
/// <param name="pixels">pixel data</param>
|
|
private void RenderInfraredPixels(byte[] pixels)
|
|
{
|
|
pixels.CopyTo(this.bitmap.PixelBuffer);
|
|
this.bitmap.Invalidate();
|
|
theImage.Source = this.bitmap;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Handles the event which the sensor becomes unavailable (E.g. paused, closed, unplugged).
|
|
/// </summary>
|
|
/// <param name="sender">object sending the event</param>
|
|
/// <param name="e">event arguments</param>
|
|
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");
|
|
}
|
|
}
|
|
}
|