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