这篇来介绍一下几个正式版SDK提供的新特性,还有比较被主流应用的骨骼数据操作。
首先先介绍一个新特性,Kinect角度调整,继续上篇的项目工程,在界面上添加两个控件,一个下拉列表,一个按钮。
<Button Content="角度调整" Height="23" HorizontalAlignment="Left" Margin="138,276,0,0" Name="button3" VerticalAlignment="Top" Width="75" Click="button3_Click" />
<ComboBox Height="23" HorizontalAlignment="Left" Margin="12,276,0,0" Name="comboBox2" VerticalAlignment="Top" Width="120" />
并添加按钮的后台处理事件:
private void button3_Click(object sender, RoutedEventArgs e)
{
ks.ElevationAngle = (int)this.comboBox2.SelectedItem;
}
并准备获取角度值并放入下拉列表的方法:
private void LoadElevationAngle()
{
int min = ks.MinElevationAngle;
int max = ks.MaxElevationAngle;
for (int i = min; i <= max; i++)
{
this.comboBox2.Items.Add(i);
}
this.comboBox2.SelectedValue = ks.ElevationAngle;
}
PS:这里的ks是继续上篇工程中的button2_Click事件中的ks对象提取到了方法外面作为全局变量来访问。并在button2_Click事件中,启动了Kinect后调用LoadElevationAngle()加载kinect角度值。
然后我们就可以通过改变下拉列表中的值后,然后点击按钮,来调整Kinect角度:
然后进入这篇的正题,骨骼信息追踪。
继续在启动前加入代码:
//添加骨骼数据获取事件
ks.SkeletonFrameReady += new EventHandler<SkeletonFrameReadyEventArgs>(ks_SkeletonFrameReady);
//设置启动,启动骨骼监听
ks.SkeletonStream.Enable();
void ks_SkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e)
{
//获得所有骨骼信息
SkeletonFrame sf = e.OpenSkeletonFrame();
if (sf != null)
{
//取出骨骼信息
Skeleton[] arrS = new Skeleton[sf.SkeletonArrayLength];
sf.CopySkeletonDataTo(arrS);
Skeleton skeleton = null;
//获取第一个追踪到的骨骼信息
foreach (var item in arrS)
{
if (item.TrackingState == SkeletonTrackingState.Tracked)
{
skeleton = item;
break;
}
}
//如果有,获得这个人的右手点
if (skeleton != null)
{
Joint hand = skeleton.Joints[JointType.HandRight];
}
}
}
其中JointType包含20个值,可以取人体二十个有效骨骼点信息,但是只有这20个可以用么?理论上不是的,这20个只是kinect提供使用的,更多的点是可以通过算法计算出来位置的。下图介绍了Kinect支持的点的分布情况:
这之后我们能获取好多点的信息,可以应用这些信息能做些什么呢?这个就有待于大家积极地发现了,那么延续上面的功能,再多扩展点功能,使用右手点来控制鼠标移动来玩水果忍着吧,那么在获取到右手点的位置添加下面代码:
//如果有,获得这个人的右手点
if (skeleton != null)
{
Joint hand = skeleton.Joints[JointType.HandRight];
if (reHand != null)
{
int x,y;
GetScreenPoint(hand, reHand, out x, out y);
//鼠标按下
mouse_event(MouseEventFlag.LeftDown, 0, 0, 0, 0);
//鼠标移动
mouse_event(MouseEventFlag.Move, x, y, 0, 0);
}
reHand = hand;
}
添加方法外的全局变量以及win32函数引用:
private Joint reHand;
enum MouseEventFlag : uint
{
Move = 0x0001,
LeftDown = 0x0002,
LeftUp = 0x0004,
RightDown = 0x0008,
RightUp = 0x0010,
MiddleDown = 0x0020,
MiddleUp = 0x0040,
XDown = 0x0080,
XUp = 0x0100,
Wheel = 0x0800,
VirtualDesk = 0x4000,
Absolute = 0x8000
}
[DllImport("user32.dll")]
static extern void mouse_event(MouseEventFlag flags, int dx, int dy, uint data, int extraInfo);
补充两个点换算的方法:
private void GetScreenPoint(Joint hand, Joint hand2, out int w, out int h)
{
double w1;
double h1;
GetScreenPoint(hand, out w1, out h1);
double w2;
double h2;
GetScreenPoint(hand2, out w2, out h2);
w = (int)(w1 - w2);
h = (int)(h1 - h2);
}
private void GetScreenPoint(Joint hand, out double w, out double h)
{
w = SystemParameters.PrimaryScreenWidth;
h = SystemParameters.PrimaryScreenHeight;
w = w / 2 + hand.Position.X * w;
h = h / 2 - hand.Position.Y * h;
}
现在运行起来,并且获得人体信息的时候就会鼠标按下,别且计算两次点的相对坐标来移动鼠标了。怎么样,你的水果忍着能体感了么?呵呵,这篇代码上的比较全了,如果需要帮助,可以留言,或者发送邮件到:57512434@qq.com,看到后会第一时间回复的。
有好多Kinect的应用已经出来了,Kinect控制机器人、代替遥控器、商场试衣,相信陆续会有更多惊喜。