//——————————————————————————
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//——————————————————————————
namespace Microsoft.Samples.Kinect.ColorBasics
{
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using Microsoft.Kinect;
/// <summary>
/// Interaction logic for MainWindow
/// </summary>
public partial class MainWindow : Window, INotifyPropertyChanged
{
/*基于Kinect开发的应用程序最开始需要用到的对象就是KinectSensor对象,
* 该对象直接表示Kinect硬件设备。KinectSensor对象是我们想要获取数据,
* 包括彩色影像数据,景深数据和骨骼追踪数据的源头。
从KinectSensor获取数据最常用的方式是通过监听该对象的一系列事件。
* 每一种数据流都有对应的事件,当改类型数据流可用时,就会触发改时间。
每一种数据流(Color,Depth,Skeleton)都是以数据点的方式在不同的坐标系中显示的,
* 在后面的讨论中我们能够清楚的看到这一点。将一个数据流中的点数据转换到另一个数据流中是一个很常见的操作,
* KinectSensor对象有一些列的方法能够进行数据流到数据点阵的转换,
* 他们是MapDepthToColorImagePoint,MapDepthToSkeletonPoint以及MapSkeletonPointToDepth。*/
// 1.KinectSensor.open()开启传感器。
//2.获取KinectSensor传感器对象,初始化
//3.打开对应的this.kinectSensor.ColorFrameSource.OpenReader(),选定所用的流,(说明Kinect V2会将流都扔给你。) FrameDescription获得对色彩帧的描述,在这里是以何种格式。
//4.注册色彩帧到达后的处理事件,绑定的方法要自己写,
//5.使用WriteableBitmap初始化bitmap(提前),
//在4.的方法中画出相应的位图。
//6.写返回Bitmap的ImageSource函数,可用其他替带。
//7.收尾,释放资源,KinectSensor.close()关闭传感器。
//...
/// <summary>
/// Active Kinect sensor
/// </summary>
private KinectSensor kinectSensor = null;//创建一个传感器对象
/// <summary>
/// Reader for color frames
/// </summary>
/// //创建一个彩色数据接口 类似的还有DepthFrameReader
private ColorFrameReader colorFrameReader = null;
/// <summary>
/// Bitmap to display
/// </summary>
/// //WriteableBitmap类用于显示位图
private WriteableBitmap colorBitmap = null;
/// <summary>
/// Current status text to display
/// </summary>
private string statusText = null;
/// <summary>
/// Initializes a new instance of the MainWindow class.
/// </summary>
public MainWindow()
{
// get the kinectSensor object
//KinectSensor类的GetDefault()函数可以取得当前连接的kinect设备;
this.kinectSensor = KinectSensor.GetDefault();
// open the reader for the color frames
//打开当前kinect设备的彩色数据帧信息源
this.colorFrameReader = this.kinectSensor.ColorFrameSource.OpenReader();
// wire handler for frame arrival
//事件 函数 属性 注册色彩帧到达后的发生事件,绑定执行函数Reader_ColorFreamArrived
this.colorFrameReader.FrameArrived += this.Reader_ColorFrameArrived;
// create the colorFrameDescription from the ColorFrameSource using Bgra format
//获得对色彩帧的描述,以Rgba格式
FrameDescription colorFrameDescription = this.kinectSensor.ColorFrameSource.CreateFrameDescription(ColorImageFormat.Bgra);
// create the bitmap to display
//创造用于显示的bitmap,图宽,图高,水平/垂直每英寸像素点数,像素点格式,调色板为空.
this.colorBitmap = new WriteableBitmap(colorFrameDescription.Width, colorFrameDescription.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 ? Properties.Resources.RunningStatusText
: Properties.Resources.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 the bitmap to display
/// </summary>
/// //以下为wpf的显示提供图源
public ImageSource ImageSource
{
get
{
return this.colorBitmap;
}
}
/// <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 MainWindow_Closing(object sender, CancelEventArgs e)
{
if (this.colorFrameReader != null)
{
// ColorFrameReder is IDisposable
this.colorFrameReader.Dispose();
this.colorFrameReader = null;
}
if (this.kinectSensor != null)
{
this.kinectSensor.Close();
this.kinectSensor = null;
}
}
/// <summary>
/// Handles the user clicking on the screenshot button
/// </summary>
/// <param name="sender">object sending the event</param>
/// <param name="e">event arguments</param>
/// //截屏函数处理
private void ScreenshotButton_Click(object sender, RoutedEventArgs e)
{
if (this.colorBitmap != null)
{
// create a png bitmap encoder which knows how to save a .png file
BitmapEncoder encoder = new PngBitmapEncoder();
// create frame from the writable bitmap and add to encoder
encoder.Frames.Add(BitmapFrame.Create(this.colorBitmap));
string time = System.DateTime.Now.ToString("hh'-'mm'-'ss", CultureInfo.CurrentUICulture.DateTimeFormat);
string myPhotos = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures);
string path = Path.Combine(myPhotos, time+ "截图" + ".png");
// write the new file to disk
try
{
// FileStream is IDisposable
using (FileStream fs = new FileStream(path, FileMode.Create))
{
encoder.Save(fs);
}
this.StatusText = string.Format(Properties.Resources.SavedScreenshotStatusTextFormat, path);
}
catch (IOException)
{
this.StatusText = string.Format(Properties.Resources.FailedScreenshotStatusTextFormat, path);
}
}
}
/// <summary>
/// Handles the color frame data arriving from the sensor
/// </summary>
/// <param name="sender">object sending the event</param>
/// <param name="e">event arguments</param>
private void Reader_ColorFrameArrived(object sender, ColorFrameArrivedEventArgs e)
{
// ColorFrame is IDisposable
using (ColorFrame colorFrame = e.FrameReference.AcquireFrame())
{
if (colorFrame != null)
{
//获得对帧的描述对象
FrameDescription colorFrameDescription = colorFrame.FrameDescription;
using (KinectBuffer colorBuffer = colorFrame.LockRawImageBuffer())
{
this.colorBitmap.Lock();
// verify data and write the new color frame data to the display bitmap
if ((colorFrameDescription.Width == this.colorBitmap.PixelWidth) && (colorFrameDescription.Height == this.colorBitmap.PixelHeight))
{ //显示方法
//colorFrame的帧数据转化到colorBitmap中去
byte[] framedata = new byte[colorFrameDescription.Height * colorFrameDescription.Width * 4];
colorFrame.CopyConvertedFrameDataToArray(framedata, ColorImageFormat.Bgra);
//改变alpha值
/* for (int i = 0; i < framedata.Length - 4; i += 4)
{
framedata[i +3] = 255;
}
*/
/* //保留bgr的最大值
for (int i = 0; i < framedata.Length - 4; i += 4)
{
if (framedata[i] > framedata[i + 1])
{
if (framedata[i] > framedata[i + 2])
{
framedata[i + 1] = framedata[i + 2] = 0;
}
else
{
framedata[i] = framedata[i + 1] = 0;
}
}
else {
if (framedata[i + 1] > framedata[i + 2])
{
framedata[i] = framedata[i + 2]=0;
}
else {
framedata[i] = framedata[i + 1] = 0;
}
}
}
*/
//转化为灰度图
/*
byte max;
for (int i = 0; i < framedata.Length - 4; i += 4)
{
max = Math.Max(Math.Max(framedata[i], framedata[i + 1]), framedata[i + 2]);
framedata[i] = max;
framedata[i+1] = max;
framedata[i+2] = max;
}
*/
//平滑
byte max;
for (int i = 0; i < framedata.Length - 4; i += 4)
{
max = Math.Max(Math.Max(framedata[i], framedata[i + 1]), framedata[i + 2]);
framedata[i] = max;
framedata[i + 1] = max;
framedata[i + 2] = max;
}
for (int i = 0; i < framedata.Length - 8; i += 4)
{
framedata[i] = (byte)((int)framedata[i] + (int)framedata[i + 4] + (int)framedata[i + 8]);
framedata[i] = (byte)((int)framedata[i]/3);
framedata[i + 1] = framedata[i];
framedata[i + 2] = framedata[i];
}
Int32Rect dirtyRect= new Int32Rect(0, 0, this.colorBitmap.PixelWidth, this.colorBitmap.PixelHeight);
colorBitmap.WritePixels( dirtyRect,framedata,colorBitmap.BackBufferStride,0) ;
/* colorFrame.CopyConvertedFrameDataToIntPtr(
this.colorBitmap.BackBuffer,//BackBuffer是后台缓冲区
(uint)(colorFrameDescription.Width * colorFrameDescription.Height * 4),
ColorImageFormat.Bgra);
//指定bitMap显示区域
this.colorBitmap.AddDirtyRect(new Int32Rect(0, 0, this.colorBitmap.PixelWidth, this.colorBitmap.PixelHeight));*/
}
this.colorBitmap.Unlock();
}
}
}
}
/// <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 ? Properties.Resources.RunningStatusText
: Properties.Resources.SensorNotAvailableStatusText;
}
}
}