Kinect for Windows SDK开发入门六骨骼追踪基础 上Word格式文档下载.docx
- 文档编号:19264384
- 上传时间:2023-01-04
- 格式:DOCX
- 页数:14
- 大小:475.33KB
Kinect for Windows SDK开发入门六骨骼追踪基础 上Word格式文档下载.docx
《Kinect for Windows SDK开发入门六骨骼追踪基础 上Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《Kinect for Windows SDK开发入门六骨骼追踪基础 上Word格式文档下载.docx(14页珍藏版)》请在冰豆网上搜索。
每一个关节有一个唯一标示符如头(head)、肩(shoulder)、肘(dlbow)等信息和3D向量数据。
现在来写代码。
首先创建一个新的wpf工程文件,添加Microsoft.Kinect.dll。
添加基本查找和初始化传感器的代码,这些代码参考之前的文章。
在开始启动传感器之前,初始化SkeletonStream数据流,并注册KinectSensor对象的SkeletonFrameReady事件,这个例子没有使用彩色摄像机和红外摄像机产生的数据,所以不需要初始化这些数据流。
UI界面采用默认的,将Grid的名称改为LayoutRoot,之后就再Grid里面绘制。
代码如下:
<
Windowx:
Class="
KinectSkeletonTracking.MainWindow"
xmlns="
xmlns:
x="
Title="
MainWindow"
Height="
350"
Width="
525"
>
<
Gridx:
Name="
LayoutRoot"
Background="
White"
/Grid>
/Window>
后台逻辑代码如下:
privateKinectSensorkinectDevice;
privatereadonlyBrush[]skeletonBrushes;
//绘图笔刷
privateSkeleton[]frameSkeletons;
publicMainWindow()
{
InitializeComponent();
skeletonBrushes=newBrush[]{Brushes.Black,Brushes.Crimson,Brushes.Indigo,Brushes.DodgerBlue,Brushes.Purple,Brushes.Pink};
KinectSensor.KinectSensors.StatusChanged+=KinectSensors_StatusChanged;
this.KinectDevice=KinectSensor.KinectSensors.FirstOrDefault(x=>
x.Status==KinectStatus.Connected);
}
publicKinectSensorKinectDevice
get{returnthis.kinectDevice;
}
set
{
if(this.kinectDevice!
=value)
//Uninitialize
=null)
this.kinectDevice.Stop();
this.kinectDevice.SkeletonFrameReady-=KinectDevice_SkeletonFrameReady;
this.kinectDevice.SkeletonStream.Disable();
this.frameSkeletons=null;
this.kinectDevice=value;
//Initialize
if(this.kinectDevice.Status==KinectStatus.Connected)
this.kinectDevice.SkeletonStream.Enable();
this.frameSkeletons=newSkeleton[this.kinectDevice.SkeletonStream.FrameSkeletonArrayLength];
this.kinectDevice.SkeletonFrameReady+=KinectDevice_SkeletonFrameReady;
this.kinectDevice.Start();
privatevoidKinectSensors_StatusChanged(objectsender,StatusChangedEventArgse)
switch(e.Status)
caseKinectStatus.Initializing:
caseKinectStatus.Connected:
caseKinectStatus.NotPowered:
caseKinectStatus.NotReady:
caseKinectStatus.DeviceNotGenuine:
this.KinectDevice=e.Sensor;
break;
caseKinectStatus.Disconnected:
//TODO:
Givetheuserfeedbacktoplug-inaKinectdevice.
this.KinectDevice=null;
default:
Showanerrorstate
以上代码中,值得注意的是frameSkeletons数组以及该数组如何在流初始化时进行内存分配的。
Kinect能够追踪到的骨骼数量是一个常量。
这使得我们在整个应用程序中能够一次性的为数组分配内存。
为了方便,KinectSDK在SkeletonStream对象中定义了一个能够追踪到的骨骼个数常量FrameSkeletonArrayLength,使用这个常量可以方便的对数组进行初始化。
代码中也定义了一个笔刷数组,这些笔刷在绘制骨骼时对多个游戏者可以使用不同的颜色进行绘制。
也可以将笔刷数组中的颜色设置为自己喜欢的颜色。
下面的代码展示了SkeletonFrameReady事件的响应方法,每一次事件被激发时,通过调用事件参数的OpenSkeletonFrame方法就能够获取当前的骨骼数据帧。
剩余的代码遍历骨骼数据帧的Skeleton数组frameSkeletons,在UI界面通过关节点将骨骼连接起来,用一条直线代表一根骨骼。
UI界面简单,将Grid元素作为根结点,并将其背景设置为白色。
privatevoidKinectDevice_SkeletonFrameReady(objectsender,SkeletonFrameReadyEventArgse)
using(SkeletonFrameframe=e.OpenSkeletonFrame())
if(frame!
Polylinefigure;
BrushuserBrush;
Skeletonskeleton;
LayoutRoot.Children.Clear();
frame.CopySkeletonDataTo(this.frameSkeletons);
for(inti=0;
i<
this.frameSkeletons.Length;
i++)
skeleton=this.frameSkeletons[i];
if(skeleton.TrackingState==SkeletonTrackingState.Tracked)
userBrush=this.skeletonBrushes[i%this.skeletonBrushes.Length];
//绘制头和躯干
figure=CreateFigure(skeleton,userBrush,new[]{JointType.Head,JointType.ShoulderCenter,JointType.ShoulderLeft,JointType.Spine,
JointType.ShoulderRight,JointType.ShoulderCenter,JointType.HipCenter
});
LayoutRoot.Children.Add(figure);
figure=CreateFigure(skeleton,userBrush,new[]{JointType.HipLeft,JointType.HipRight});
//绘制作腿
figure=CreateFigure(skeleton,userBrush,new[]{JointType.HipCenter,JointType.HipLeft,JointType.KneeLeft,JointType.AnkleLeft,JointType.FootLeft});
//绘制右腿
figure=CreateFigure(skeleton,userBrush,new[]{JointType.HipCenter,JointType.HipRight,JointType.KneeRight,JointType.AnkleRight,JointType.FootRight});
//绘制左臂
figure=CreateFigure(skeleton,userBrush,new[]{JointType.ShoulderLeft,JointType.ElbowLeft,JointType.WristLeft,JointType.HandLeft});
//绘制右臂
figure=CreateFigure(skeleton,userBrush,new[]{JointType.ShoulderRight,JointType.ElbowRight,JointType.WristRight,JointType.HandRight});
循环遍历frameSkeletons对象,每一次处理一个骨骼,在处理之前需要判断是否是一个追踪好的骨骼,可以使用Skeleton对象的TrackingState属性来判断,只有骨骼追踪引擎追踪到的骨骼我们才进行绘制,忽略哪些不是游戏者的骨骼信息即过滤掉那些TrackingState不等于SkeletonTrackingState.Tracked的骨骼数据。
Kinect能够探测到6个游戏者,但是同时只能够追踪到2个游戏者的骨骼关节位置信息。
在后面我们将会详细讨论TrackingState这一属性。
处理骨骼数据相对简单,首先,我们根Kinect追踪到的游戏者的编号,选择一种颜色笔刷。
然后利用这只笔刷绘制曲线。
CreateFigure方法为每一根骨骼绘制一条直线。
GetJointPoint方法在绘制骨骼曲线中很关键。
该方法以关节点的三维坐标作为参数,然后调用KinectSensor对象的MapSkeletonPointToDepth方法将骨骼坐标转换到深度影像坐标上去。
后面我们将会讨论为什么需要这样转换以及如何定义坐标系统。
现在我们只需要知道的是,骨骼坐标系和深度坐标及彩色影像坐标系不一样,甚至和UI界面上的坐标系不一样。
在开发Kinect应用程序中,从一个坐标系转换到另外一个坐标系这样的操作非常常见,GetJointPoint方法的目的就是将骨骼关节点的三维坐标转换到UI绘图坐标系统,返回该骨骼关节点在UI上的位置。
下面的代码展示了CreateFigure和GetJointPoint这两个方法。
privatePolylineCreateFigure(Skeletonskeleton,Brushbrush,JointType[]joints)
Polylinefigure=newPolyline();
figure.StrokeThickness=8;
figure.Stroke=brush;
joints.Length;
figure.Points.Add(GetJointPoint(skeleton.Joints[joints[i]]));
returnfigure;
privatePointGetJointPoint(Jointjoint)
DepthImagePointpoint=this.KinectDevice.MapSkeletonPointToDepth(joint.Position,this.KinectDevice.DepthStream.Format);
point.X*=(int)this.LayoutRoot.ActualWidth/KinectDevice.DepthStream.FrameWidth;
point.Y*=(int)this.LayoutRoot.ActualHeight/KinectDevice.DepthStream.FrameHeight;
returnnewPoint(point.X,point.Y);
}
值得注意的是,骨骼关节点的三维坐标中我们舍弃了Z值,只用了X,Y值。
Kinect好不容易为我们提供了每一个节点的深度数据(Z值)而我们却没有使用,这看起来显得很浪费。
其实不是这样的,我们使用了节点的Z值,只是没有直接使用,没有在UI界面上展现出来而已。
在坐标空间转换中是需要深度数据的。
可以试试在GetJointPoint方法中,将joint的Position中的Z值改为0,然后再调用MapSkeletonPointToDepth方法,你会发现返回的对象中x和y值均为0,可以试试,将图像以Z值进行等比缩放,可以发现图像的大小是和Z值(深度)成反的。
也就是说,深度值越小,图像越大,即人物离Kinect越近,骨骼数据越大。
运行程序,会得到如下骨骼图像,这个是手握键盘准备截图的姿势。
一开始可能需要调整一些Form窗体的大小。
程序会为每一个游戏者以一种颜色绘制骨骼图像,可以试着在Kinect前面移动,可以看到骨骼图像的变化,也可以走进然后走出图像以观察颜色的变化。
仔细观察有时候可以看到绘图出现了一些奇怪的图案,在讨论完骨骼追踪相关的API之后,就会明白这些现象出现的原因了。
2.骨骼对象模型
KinectSDK中骨骼追踪有一些和其他对象不一样的对象结构和枚举。
在SDK中骨骼追踪相关的内容几乎占据了三分之一的内容,可见Kinect中骨骼追踪技术的重要性。
下图展示了骨骼追踪系统中涉及到的一些主要的对象模型。
有四个最主要的对象,他们是SkeletonStream,SkeletonFrame,Skeleton和Joint。
下面将详细介绍这四个对象。
2.1SkeletonStream对象
SkeletonStream对象产生SkeletonFrame。
从SkeletonStream获取骨骼帧数据和从ColorStream及DepthStream中获取数据类似。
可以注册SkeletonFrameReady事件或者AllFramesReady事件通过事件模型来获取数据,或者是使用OpenNextFrame方法通过“拉”模型来获取数据。
不能对同一个SkeletonStream同时使用这两种模式。
如果注册了SkeletonFrameReady事件然后又调用OpenNextFrame方法将会返回一个InvalidOperationException异常。
SkeletonStream的启动和关闭
除非启动了SkeletonStream对象,否则,不会产生任何数据,默认情况下,SkeletonStream对象是关闭的。
要使SkeletonStream产生数据,必须调用对象的Enabled方法。
相反,调用Disable方法能够使SkeletonStream对象暂停产生数据。
SkeletonStream有一个IsEnabled方法来描述当前SkeletonStream对象的状态。
只有SkeletonStream对象启动了,KinectSensor对象的SkeletonFrameReady事件才能被激活。
如果要使用“拉”模式来获取数据SkeletonStream也必须启动后才能调用OpenNextFrame方法。
否则也会抛出InvalidOperationException异常。
一般地在应用程序的声明周期中,一旦启动了SkeletonStream对象,一般会保持启动状态。
但是在有些情况下,我们希望关闭SkeletonStream对象。
比如在应用程序中使用多个Kinect传感器时。
只有一个Kinect传感器能够产生骨骼数据,这也意味着,即使使用多个Kinect传感器,同时也只能追踪到两个游戏者的骨骼数据信息。
在应用程序执行的过程中,有可能会关闭某一个Kinect传感器的SkeletonStream对象而开启另一个Kinect传感器的SkeletonStream对象。
另一个有可能关闭骨骼数据产生的原因是出于性能方面的考虑,骨骼数据处理是很耗费计算性能的操作。
打开骨骼追踪是可以观察的到CPU的占用率明显增加。
当不需要骨骼数据时,关闭骨骼追踪很有必要。
例如,在有些游戏场景中可能在展现一些动画效果或者播放视频,在这个动画效果或者视频播放时,停止骨骼追踪可能可以使得游戏更加流畅。
当然关闭SkeletonStream也有一些副作用。
当SkeletonStream的状态发生改变时,所有的数据产生都会停止和从新开始。
SkeletonStream的状态改变会使传感器重新初始化,将TimeStamp和FrameNumber重置为0。
在传感器重新初始化时也有几毫秒的延迟。
平滑化
在前面的例子中,会注意到,骨骼运动会呈现出跳跃式的变化。
有几个原因会导致出现这一问题,可能是应用程序的性能,游戏者的动作不够连贯,也有可能是Kinect硬件的性能问题。
骨骼关节点的相对位置可能在帧与帧之间变动很大,这回对应用程序产生一些负面的影像。
除了会影像用户体验和不愉快意外,也可能会导致用户的形象或者手的颤动抽搐而使用户感到迷惑。
SkeletonStream对象有一种方法能够解决这个问题。
他通过将骨骼关节点的坐标标准化来减少帧与帧之间的关节点位置差异。
当初始化SkeletonStream对象调用重载的Enable方法时可以传入一个TransformSmoothParameters参数。
SkeletonStream对象有两个与平滑有关只读属性:
IsSmoothingEnabled和SmoothParameters。
当调用Enable方法传入了TransformSmoothParameters是IsSmoothingEnabled返回true而当使用默认的不带参数的Enable方法初始化时,IsSmoothingEnabled对象返回false。
SmoothParameters属性用来存储定义平滑参数。
TransformSmoothParameters这个结构定义了一些属性:
∙修正值(Correction)属性,接受一个从0-1的浮点型。
值越小,修正越多。
∙抖动半径(JitterRadius)属性,设置修正的半径,如果关节点“抖动”超过了设置的这个半径,将会被纠正到这个半径之内。
该属性为浮点型,单位为米。
∙最大偏离半径(MaxDeviationRadius)属性,用来和抖动半径一起来设置抖动半径的最大边界。
任何超过这一半径的点都不会认为是抖动产生的,而被认定为是一个新的点。
∙预测帧大小(Prediction)属性,返回用来进行平滑需要的骨骼帧的数目。
∙平滑值(Smoothing)属性,设置处理骨骼数据帧时的平滑量,接受一个0-1的浮点值,值越大,平滑的越多。
0表示不进行平滑。
对骨骼关节点进行平滑处理会产生性能开销。
平滑处理的越多,性能消耗越大。
设置平滑参数没有经验可以遵循。
需要不断的测试和调试已达到最好的性能和效果。
在程序运行的不同阶段,可能需要设置不同的平滑参数。
Note:
SDK使用霍尔特指数平滑(HoltDoubleExponentialSmoothing)来对减少关节点的抖动。
指数平滑数据处理与时间有关。
骨骼数据是时间序列数据,因为骨骼引擎会以某一时间间隔不断产生一帧一帧的骨骼数据。
平滑处理使用统计方法进行滑动平均,这样能够减少时间序列数据中的噪声和极值。
类似的处理方法最开始被用于金融市场和经济数据的预测。
骨骼追踪对象选择
默认情况下,骨骼追踪引擎会对视野内的所有活动的游戏者进行追踪。
但只会选择两个可能
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Kinect for Windows SDK开发入门六骨骼追踪基础 SDK 开发 入门 骨骼 追踪 基础
![提示](https://static.bdocx.com/images/bang_tan.gif)
链接地址:https://www.bdocx.com/doc/19264384.html