|
@@ -3,30 +3,45 @@ using Microsoft.Kinect;
|
|
|
using System;
|
|
|
using System.Collections.Generic;
|
|
|
using System.ComponentModel;
|
|
|
-using System.Linq;
|
|
|
using System.Media;
|
|
|
using System.Reflection;
|
|
|
-using System.Text;
|
|
|
-using System.Threading.Tasks;
|
|
|
using System.Windows;
|
|
|
using System.Windows.Controls;
|
|
|
-using System.Windows.Data;
|
|
|
-using System.Windows.Documents;
|
|
|
using System.Windows.Input;
|
|
|
using System.Windows.Media;
|
|
|
using System.Windows.Media.Imaging;
|
|
|
-using System.Windows.Navigation;
|
|
|
-using System.Windows.Shapes;
|
|
|
|
|
|
namespace FireDrill
|
|
|
{
|
|
|
/// <summary>
|
|
|
/// MainWindow.xaml 的交互逻辑
|
|
|
/// </summary>
|
|
|
- public partial class MainWindow : Window
|
|
|
+ public partial class MainWindow : Window, INotifyPropertyChanged
|
|
|
{
|
|
|
// 活动的 Kinect 传感器
|
|
|
private KinectSensor _kinectSensor = null;
|
|
|
+
|
|
|
+ // 身体框架索引渲染器
|
|
|
+ private BodyIndexFrameReader bodyIndexFrameReader = null;
|
|
|
+ // 身体框架中包含的数据的说明
|
|
|
+ private FrameDescription bodyIndexFrameDescription = null;
|
|
|
+ // 要显示的位图
|
|
|
+ private WriteableBitmap bodyIndexBitmap = null;
|
|
|
+ // 帧数据转换成颜色的中间存储器
|
|
|
+ private uint[] bodyIndexPixels = null;
|
|
|
+ // 位图中 RGB 像素的大小
|
|
|
+ private const int BytesPerPixel = 4;
|
|
|
+ // 用于显示 BodyIndexFrame 数据的颜色集合
|
|
|
+ private static readonly uint[] BodyColor =
|
|
|
+ {
|
|
|
+ 0x0000FF00,
|
|
|
+ 0x00FF0000,
|
|
|
+ 0xFFFF4000,
|
|
|
+ 0x40FFFF00,
|
|
|
+ 0xFF40FF00,
|
|
|
+ 0xFF808000,
|
|
|
+ };
|
|
|
+
|
|
|
// 坐标映射器将一种类型的点映射到另一种
|
|
|
private CoordinateMapper _coordinateMapper = null;
|
|
|
// 身体框架渲染器
|
|
@@ -65,8 +80,6 @@ namespace FireDrill
|
|
|
private readonly Brush _inferredJointBrush = Brushes.Yellow;
|
|
|
// 用于绘制当前推断的骨骼的笔
|
|
|
private readonly Pen _inferredBonePen = new Pen(Brushes.Gray, 1);
|
|
|
- // 要显示的当前设备名称
|
|
|
- private string _deviceName;
|
|
|
// 要显示的当前状态文本
|
|
|
private string _statusText;
|
|
|
// 要显示的提示文本
|
|
@@ -79,9 +92,56 @@ namespace FireDrill
|
|
|
private WriteableBitmap _colorBitmap;
|
|
|
private SoundPlayer soundPlayer = new SoundPlayer();
|
|
|
|
|
|
+ // INotifyPropertyChangedPropertyChanged 事件允许窗口控件绑定到可更改的数据
|
|
|
+ public event PropertyChangedEventHandler PropertyChanged;
|
|
|
+
|
|
|
+ public string StatusText
|
|
|
+ {
|
|
|
+ get
|
|
|
+ {
|
|
|
+ return _statusText;
|
|
|
+ }
|
|
|
+
|
|
|
+ set
|
|
|
+ {
|
|
|
+ if (_statusText == value) return;
|
|
|
+ _statusText = value;
|
|
|
+ // 通知任何绑定元素文本已更改
|
|
|
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("StatusText"));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public ImageSource ImageSource
|
|
|
+ {
|
|
|
+ get
|
|
|
+ {
|
|
|
+ return bodyIndexBitmap;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
public MainWindow()
|
|
|
{
|
|
|
+ // 初始化窗口的组件(控件)
|
|
|
InitializeComponent();
|
|
|
+ // 目前支持一个传感器
|
|
|
+ _kinectSensor = KinectSensor.GetDefault();
|
|
|
+ // open the reader for the depth frames
|
|
|
+ bodyIndexFrameReader = _kinectSensor.BodyIndexFrameSource.OpenReader();
|
|
|
+ // wire handler for frame arrival
|
|
|
+ bodyIndexFrameReader.FrameArrived += Reader_FrameArrived;
|
|
|
+ bodyIndexFrameDescription = _kinectSensor.BodyIndexFrameSource.FrameDescription;
|
|
|
+ // allocate space to put the pixels being converted
|
|
|
+ bodyIndexPixels = new uint[bodyIndexFrameDescription.Width * bodyIndexFrameDescription.Height];
|
|
|
+ // create the bitmap to display
|
|
|
+ bodyIndexBitmap = new WriteableBitmap(bodyIndexFrameDescription.Width, bodyIndexFrameDescription.Height, 96.0, 96.0, PixelFormats.Bgr32, null);
|
|
|
+ // 设置 IsAvailableChanged 事件通知程序
|
|
|
+ _kinectSensor.IsAvailableChanged += this.Sensor_IsAvailableChanged;
|
|
|
+ // 打开传感器
|
|
|
+ _kinectSensor.Open();
|
|
|
+ // set the status text
|
|
|
+ StatusText = _kinectSensor.IsAvailable ? Properties.Resources.RunningStatusText : Properties.Resources.NoSensorStatusText;
|
|
|
+ // 在这个简单的例子中使用window对象作为视图模型
|
|
|
+ DataContext = this;
|
|
|
}
|
|
|
|
|
|
private void Window_Loaded(object sender, RoutedEventArgs e)
|
|
@@ -105,6 +165,7 @@ namespace FireDrill
|
|
|
{
|
|
|
// 绑定视频文件
|
|
|
VideoPlayer.Source = new Uri(videoContent);
|
|
|
+ VideoPlayer.Play();
|
|
|
}
|
|
|
if (string.IsNullOrEmpty(audioContent))
|
|
|
{
|
|
@@ -126,6 +187,14 @@ namespace FireDrill
|
|
|
else
|
|
|
{
|
|
|
soundPlayer?.Stop();
|
|
|
+ if (bodyIndexFrameReader != null)
|
|
|
+ {
|
|
|
+ // 移除事件处理程序
|
|
|
+ bodyIndexFrameReader.FrameArrived -= Reader_FrameArrived;
|
|
|
+ // 清除身体框架索引渲染器
|
|
|
+ bodyIndexFrameReader.Dispose();
|
|
|
+ bodyIndexFrameReader = null;
|
|
|
+ }
|
|
|
if (_bodyFrameReader != null)
|
|
|
{
|
|
|
_bodyFrameReader.Dispose();
|
|
@@ -153,7 +222,9 @@ namespace FireDrill
|
|
|
{
|
|
|
case Key.Escape:
|
|
|
ToolBar.Visibility = Visibility.Visible;
|
|
|
- ViewBox.Margin = new Thickness { Left = 0, Top = 32, Right = 0, Bottom = 0 };
|
|
|
+ VideoPlayer.Margin = new Thickness { Left = 0, Top = 32, Right = 0, Bottom = 0 };
|
|
|
+ ViewBox.Height = 150;
|
|
|
+ ViewBox.Width = 150;
|
|
|
WindowState = WindowState.Normal;
|
|
|
WindowStyle = WindowStyle.SingleBorderWindow;
|
|
|
break;
|
|
@@ -165,6 +236,64 @@ namespace FireDrill
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ private void Reader_FrameArrived(object sender, BodyIndexFrameArrivedEventArgs e)
|
|
|
+ {
|
|
|
+ bool bodyIndexFrameProcessed = false;
|
|
|
+ using (BodyIndexFrame bodyIndexFrame = e.FrameReference.AcquireFrame())
|
|
|
+ {
|
|
|
+ if (bodyIndexFrame != null)
|
|
|
+ {
|
|
|
+ // 处理 body 索引数据的最快方法是直接访问底层缓冲区
|
|
|
+ using (KinectBuffer bodyIndexBuffer = bodyIndexFrame.LockImageBuffer())
|
|
|
+ {
|
|
|
+ // 验证数据并将颜色数据写入显示位图
|
|
|
+ if (((bodyIndexFrameDescription.Width * bodyIndexFrameDescription.Height) == bodyIndexBuffer.Size) &&
|
|
|
+ (bodyIndexFrameDescription.Width == bodyIndexBitmap.PixelWidth) && (bodyIndexFrameDescription.Height == bodyIndexBitmap.PixelHeight))
|
|
|
+ {
|
|
|
+ ProcessBodyIndexFrameData(bodyIndexBuffer.UnderlyingBuffer, bodyIndexBuffer.Size);
|
|
|
+ bodyIndexFrameProcessed = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (bodyIndexFrameProcessed)
|
|
|
+ {
|
|
|
+ // RenderBodyIndexPixels
|
|
|
+ bodyIndexBitmap.WritePixels(
|
|
|
+ new Int32Rect(0, 0, bodyIndexBitmap.PixelWidth, bodyIndexBitmap.PixelHeight),
|
|
|
+ bodyIndexPixels,
|
|
|
+ bodyIndexBitmap.PixelWidth * BytesPerPixel,
|
|
|
+ 0);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private unsafe void ProcessBodyIndexFrameData(IntPtr bodyIndexFrameData, uint bodyIndexFrameDataSize)
|
|
|
+ {
|
|
|
+ byte* frameData = (byte*)bodyIndexFrameData;
|
|
|
+ // 将正文索引转换为可视表示
|
|
|
+ for (int i = 0; i < (int)bodyIndexFrameDataSize; ++i)
|
|
|
+ {
|
|
|
+ // BodyColor 数组的大小已调整为与 BodyFrameSource.BodyCount 匹配
|
|
|
+ if (frameData[i] < BodyColor.Length)
|
|
|
+ {
|
|
|
+ // 像素是播放器的一部分,显示适当的颜色
|
|
|
+ bodyIndexPixels[i] = BodyColor[frameData[i]];
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ // 此像素不是播放器的一部分,显示黑色
|
|
|
+ bodyIndexPixels[i] = 0x00000000;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void Sensor_IsAvailableChanged(object sender, IsAvailableChangedEventArgs e)
|
|
|
+ {
|
|
|
+ // 如果失败,设置状态文本
|
|
|
+ StatusText = _kinectSensor.IsAvailable ? Properties.Resources.RunningStatusText : Properties.Resources.SensorNotAvailableStatusText;
|
|
|
+ }
|
|
|
+
|
|
|
private void Settings_Click(object sender, RoutedEventArgs e)
|
|
|
{
|
|
|
var dialog = new SettingsWindow();
|
|
@@ -180,7 +309,9 @@ namespace FireDrill
|
|
|
private void FullScreen_Click(object sender, RoutedEventArgs e)
|
|
|
{
|
|
|
ToolBar.Visibility = Visibility.Hidden;
|
|
|
- ViewBox.Margin = new Thickness { Left = 0, Top = 0, Right = 0, Bottom = 0 };
|
|
|
+ VideoPlayer.Margin = new Thickness { Left = 0, Top = 0, Right = 0, Bottom = 0 };
|
|
|
+ ViewBox.Height = 300;
|
|
|
+ ViewBox.Width = 300;
|
|
|
Topmost = false;
|
|
|
WindowStyle = WindowStyle.None;
|
|
|
WindowState = WindowState.Maximized;
|