浏览代码

完善主窗口传感器视图渲染

王育民 5 年之前
父节点
当前提交
1f67523f25
共有 3 个文件被更改,包括 147 次插入15 次删除
  1. 1 0
      FireDrill/FireDrill.csproj
  2. 3 3
      FireDrill/MainWindow.xaml
  3. 143 12
      FireDrill/MainWindow.xaml.cs

+ 1 - 0
FireDrill/FireDrill.csproj

@@ -24,6 +24,7 @@
     <DefineConstants>DEBUG;TRACE</DefineConstants>
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
+    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
   </PropertyGroup>
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
     <PlatformTarget>AnyCPU</PlatformTarget>

+ 3 - 3
FireDrill/MainWindow.xaml

@@ -25,10 +25,10 @@
             <Label x:Name="Tip2" Foreground="Gray"/>
         </ToolBar>
 
-        <MediaElement x:Name="VideoPlayer" Margin="0,32,0,0"/>
+        <MediaElement x:Name="VideoPlayer" Margin="0,32,0,0" Stretch="Fill"/>
 
-        <Viewbox x:Name="ViewBox" Margin="0,32,0,0" HorizontalAlignment="Center">
-            <Image Name="Image" Source="{Binding ImageSource}" Stretch="UniformToFill" />
+        <Viewbox x:Name="ViewBox" HorizontalAlignment="Right" VerticalAlignment="Bottom" Height="150" Width="150">
+            <Image Name="Image" Source="{Binding ImageSource}" Stretch="UniformToFill"/>
         </Viewbox>
     </Grid>
 </Window>

+ 143 - 12
FireDrill/MainWindow.xaml.cs

@@ -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;