KinectSensor內有個SkeletonStream,SkeletonStream是用於接收骨架追蹤的串流,SkeletonStream類別又包含了AppChoosesSkeletons屬性,該屬性為布林值
AppChoosesSkeletons的說明為『Gets or sets a value indicating whether the application or the runtime chooses which skeletons to track.』
聰明的你一定看得出來用於鎖定骨架的第一步就設定為true
在透過ChooseSkeletons來鎖定指定的骨架,每個骨架都有它的編號,要注意ChooseSkeletons是多載的方法
- SkeletonStream.ChooseSkeletons ()
- SkeletonStream.ChooseSkeletons (Int32)
- SkeletonStream.ChooseSkeletons (Int32, Int32)
第一種方法僅偵測當前的骨架
第二種方法僅偵測指定的骨架ID,填入0也等同於第一種方法
第三種方法僅偵測兩個指定的骨架ID,這意謂著Kinect頂多鎖定兩個人的骨架而已
鎖定之前,要先確認AppChoosesSkeletons值要設定為True,否則會出錯
XAML:
<Window x:Class="WpfApplicationKinectTest2.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="350" Width="525" Unloaded="Window_Unloaded" Loaded="Window_Loaded"> <Grid> <Image Name="Image"></Image> </Grid> </Window>
Code:
using Microsoft.Kinect; using System; using System.Linq; using System.Threading; using System.Windows; using System.Windows.Controls; using System.Windows.Media; using System.Windows.Media.Imaging; namespace WpfApplicationKinectTest2 { /// <summary> /// MainWindow.xaml 的互動邏輯 /// </summary> public partial class MainWindow : Window { /// <summary> /// 影像寬度 /// </summary> private const float RenderWidth = 640.0f; /// <summary> /// 影像高度 /// </summary> private const float RenderHeight = 480.0f; /// <summary> /// 關節厚度 /// </summary> private const double JointThickness = 3; /// <summary> /// 身體中間厚度 /// </summary> private const double BodyCenterThickness = 10; /// <summary> /// 整體區塊厚度 /// </summary> private const double ClipBoundsThickness = 10; /// <summary> /// 身體刷子 /// </summary> private readonly Brush centerPointBrush = Brushes.Blue; /// <summary> /// 追蹤關節筆刷 /// </summary> private readonly Brush trackedJointBrush = new SolidColorBrush(Color.FromArgb(255, 68, 192, 68)); /// <summary> /// 位置的筆刷 /// </summary> private readonly Brush inferredJointBrush = Brushes.Yellow; /// <summary> /// 追蹤的筆 /// </summary> private readonly Pen trackedBonePen = new Pen(Brushes.Green, 6); /// <summary> /// 位置的筆 /// </summary> private readonly Pen inferredBonePen = new Pen(Brushes.Gray, 1); /// <summary> /// 繪圖集合 /// </summary> private DrawingGroup drawingGroup; /// <summary> /// 繪圖影像 /// </summary> private DrawingImage imageSource; /// <summary> /// 感應器 /// </summary> private KinectSensor sensor; /// <summary> /// Color data bytes /// </summary> private byte[] dataPixels = null; /// <summary> /// Track ID /// </summary> private int trackID = -1; public MainWindow() { InitializeComponent(); } private void Window_Loaded(object sender, RoutedEventArgs e) { //Refresh drawingGroup = new DrawingGroup(); imageSource = new DrawingImage(drawingGroup); Image.Source = this.imageSource; sensor = KinectSensor.KinectSensors[0]; if (sensor != null) { sensor.SkeletonStream.Enable(); sensor.ColorStream.Enable(); sensor.SkeletonFrameReady += SensorSkeletonFrameReady; sensor.ColorFrameReady += SensorColorFrameReady; sensor.Start(); } } private void Window_Unloaded(object sender, RoutedEventArgs e) { sensor.Stop(); } private void SensorColorFrameReady(object sender, ColorImageFrameReadyEventArgs e) { using (ColorImageFrame frame = e.OpenColorImageFrame()) { if (frame != null) { dataPixels = new byte[frame.PixelDataLength]; frame.CopyPixelDataTo(dataPixels); } } } private void SensorSkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e) { Skeleton[] skeletons = new Skeleton[0]; using (SkeletonFrame skeletonFrame = e.OpenSkeletonFrame()) { if (skeletonFrame == null) return; if (skeletonFrame != null) { skeletons = new Skeleton[skeletonFrame.SkeletonArrayLength]; skeletonFrame.CopySkeletonDataTo(skeletons); } //取得目前背景 using (DrawingContext dc = this.drawingGroup.Open()) { BitmapSource source = BitmapSource.Create((int)RenderWidth, (int)RenderHeight, 96, 96, PixelFormats.Bgr32, null, dataPixels, 640 * 4); dc.DrawImage(source, new Rect(0.0, 0.0, RenderWidth, RenderHeight)); //還有資料傳入 if (skeletons.Length != 0) { foreach (Skeleton skel in skeletons.Where(skl => skl.TrackingState != SkeletonTrackingState.NotTracked)) { if (skel.TrackingState == SkeletonTrackingState.Tracked) { DrawBonesAndJoints(skel, dc); LockUser(skel); } else if (skel.TrackingState == SkeletonTrackingState.PositionOnly) { dc.DrawEllipse( centerPointBrush, null, SkeletonPointToScreen(skel.Position), BodyCenterThickness, BodyCenterThickness); } } } // prevent drawing outside of our render area drawingGroup.ClipGeometry = new RectangleGeometry(new Rect(0.0, 0.0, RenderWidth, RenderHeight)); } } } private void LockUser(Skeleton skeleton) { if (skeleton.Joints[JointType.Head].Position.Y < skeleton.Joints[JointType.HandRight].Position.Y) { if (this.trackID == -1) { this.trackID = skeleton.TrackingId; if (this.sensor.SkeletonStream.AppChoosesSkeletons == false) { this.sensor.SkeletonStream.AppChoosesSkeletons = true; } this.sensor.SkeletonStream.ChooseSkeletons(trackID); Console.WriteLine("鎖定中, ID:" + trackID); } else { this.trackID = -1; if (this.sensor.SkeletonStream.AppChoosesSkeletons == true) { this.sensor.SkeletonStream.ChooseSkeletons(); this.sensor.SkeletonStream.AppChoosesSkeletons = false; } Console.WriteLine("解鎖"); } Thread.Sleep(700); } } private void DrawBonesAndJoints(Skeleton skeleton, DrawingContext drawingContext) { // Render Torso DrawBone(skeleton, drawingContext, JointType.Head, JointType.ShoulderCenter); DrawBone(skeleton, drawingContext, JointType.ShoulderCenter, JointType.ShoulderLeft); DrawBone(skeleton, drawingContext, JointType.ShoulderCenter, JointType.ShoulderRight); DrawBone(skeleton, drawingContext, JointType.ShoulderCenter, JointType.Spine); DrawBone(skeleton, drawingContext, JointType.Spine, JointType.HipCenter); DrawBone(skeleton, drawingContext, JointType.HipCenter, JointType.HipLeft); DrawBone(skeleton, drawingContext, JointType.HipCenter, JointType.HipRight); // Left Arm DrawBone(skeleton, drawingContext, JointType.ShoulderLeft, JointType.ElbowLeft); DrawBone(skeleton, drawingContext, JointType.ElbowLeft, JointType.WristLeft); DrawBone(skeleton, drawingContext, JointType.WristLeft, JointType.HandLeft); // Right Arm DrawBone(skeleton, drawingContext, JointType.ShoulderRight, JointType.ElbowRight); DrawBone(skeleton, drawingContext, JointType.ElbowRight, JointType.WristRight); DrawBone(skeleton, drawingContext, JointType.WristRight, JointType.HandRight); // Left Leg DrawBone(skeleton, drawingContext, JointType.HipLeft, JointType.KneeLeft); DrawBone(skeleton, drawingContext, JointType.KneeLeft, JointType.AnkleLeft); DrawBone(skeleton, drawingContext, JointType.AnkleLeft, JointType.FootLeft); // Right Leg DrawBone(skeleton, drawingContext, JointType.HipRight, JointType.KneeRight); DrawBone(skeleton, drawingContext, JointType.KneeRight, JointType.AnkleRight); DrawBone(skeleton, drawingContext, JointType.AnkleRight, JointType.FootRight); // Render Joints foreach (Joint joint in skeleton.Joints) { Brush drawBrush = null; if (joint.TrackingState == JointTrackingState.Tracked) //追蹤中 { drawBrush = this.trackedJointBrush; } else if (joint.TrackingState == JointTrackingState.Inferred) //大概位置 { drawBrush = this.inferredJointBrush; } //如果畫筆有被設置,畫出關節為橢圓形 if (drawBrush != null) { drawingContext.DrawEllipse(drawBrush, null, SkeletonPointToScreen(joint.Position), JointThickness, JointThickness); } } } private Point SkeletonPointToScreen(SkeletonPoint skelpoint) { DepthImagePoint depthPoint = this.sensor.CoordinateMapper.MapSkeletonPointToDepthPoint(skelpoint, DepthImageFormat.Resolution640x480Fps30); return new Point(depthPoint.X, depthPoint.Y); } private void DrawBone(Skeleton skeleton, DrawingContext drawingContext, JointType jointType0, JointType jointType1) { Joint joint0 = skeleton.Joints[jointType0]; Joint joint1 = skeleton.Joints[jointType1]; //找不到任何追蹤的點就不動作 if (joint0.TrackingState == JointTrackingState.NotTracked || joint1.TrackingState == JointTrackingState.NotTracked) { return; } //找不到任何位置就不動作 if (joint0.TrackingState == JointTrackingState.Inferred && joint1.TrackingState == JointTrackingState.Inferred) { return; } //兩者都有就畫出位置 Pen drawPen = this.inferredBonePen; if (joint0.TrackingState == JointTrackingState.Tracked && joint1.TrackingState == JointTrackingState.Tracked) { drawPen = trackedBonePen; } //畫出關節與關節的線 drawingContext.DrawLine(drawPen, SkeletonPointToScreen(joint0.Position), SkeletonPointToScreen(joint1.Position)); } } }
參考資料: http://msdn.microsoft.com/en-us/library/microsoft.kinect.skeletonstream_members.aspx