实现Kinect控制幻灯片播放很简单,主要思路是:使用Kinect捕捉人体动作,然后根据识别出来的动作向系统发出点击向前,向后按键的事件,从而使得幻灯片能够切换。 这里的核心功能在于手势的识别,我们在开发之前需要定义怎么样的手势算是向前或者向后切换幻灯片。手势和姿势识别在我的Kinect开发入门第九第十十一篇文章有详细介绍。本文仅讨论主要思路及关键代码部分。


通过姿势实现PPT控制

姿势(pose)识别是通过关节点与关节点之间的相对位置关系来进行判断,相对来说比较容易,只需要通过某一帧骨骼关节点数据即可进行判断。而手势(gesture)识别则是通过对连续的一段时间内的动作来进行判断,比较复杂。但是两者对于我们需要实现特定的目的来说并没有优劣之分,就像常用的算法那样,并不是越复杂越好,有些方法就非常简单高效。

在控制ppt播放命令中,我们设定,如果右手关节点在x轴上的距离比头部关节点大于0.45的话,认为用户试图进行点击键盘上的right按钮。如果头部关节点位置在x轴方向是比左手关节点在x轴上的位置大于0.45的话,认为用户试图点击键盘上的left按钮。0.45这个值是通过反复试验的出来的,这种通过试验的方法在Kinect开发中比较常见。关键代码如下:

private void ProcessForwardBackGesture(Joint head, Joint rightHand, Joint leftHand)
{
if (rightHand.Position.X > head.Position.X + 0.45)
{
if (!isBackGestureActive && !isForwardGestureActive)
{
isForwardGestureActive = true;
System.Windows.Forms.SendKeys.SendWait("{Right}");
}
}
else
{
isForwardGestureActive = false;
} if (leftHand.Position.X < head.Position.X - 0.45)
{
if (!isBackGestureActive && !isForwardGestureActive)
{
isBackGestureActive = true;
System.Windows.Forms.SendKeys.SendWait("{Left}");
}
}
else
{
isBackGestureActive = false;
}
}

上面的代码中,当判断到用户向右挥手动作是,执行System.Windows.Forms.SendKeys.SendWait("{Right}")语句从而发出点击键盘向右按键; 该方法执行时,要求PowerPoint程序处于当前活动的状态,这样里面的PPT才会向右键盘点击事件。需要注意的是方法中isBackGestureActive和isForwardGestureActive这两个布尔型的标志位,可以防止当用户一直处于某一个动作时会一直发送System.Windows.Forms.SendKeys.SendWait("{xx}")。

上面的方法可以放在sensor_SkeletonFrameReady事件中,首先获取头部,左手右手关节点数据,然后调用该方法。

void sensor_SkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e)
{
using (var skeletonFrame = e.OpenSkeletonFrame())
{
if (skeletonFrame == null)
return; if (skeletons == null ||
skeletons.Length != skeletonFrame.SkeletonArrayLength)
{
skeletons = new Skeleton[skeletonFrame.SkeletonArrayLength];
} skeletonFrame.CopySkeletonDataTo(skeletons); Skeleton closestSkeleton = (from s in skeletons
where s.TrackingState == SkeletonTrackingState.Tracked &&
s.Joints[JointType.Head].TrackingState == JointTrackingState.Tracked
select s).OrderBy(s => s.Joints[JointType.Head].Position.Z)
.FirstOrDefault(); if (closestSkeleton == null)
return; var head = closestSkeleton.Joints[JointType.Head];
var rightHand = closestSkeleton.Joints[JointType.HandRight];
var leftHand = closestSkeleton.Joints[JointType.HandLeft]; if (head.TrackingState != JointTrackingState.Tracked ||
rightHand.TrackingState != JointTrackingState.Tracked ||
leftHand.TrackingState != JointTrackingState.Tracked)
{
//Don't have a good read on the joints so we cannot process gestures
return;
} ProcessForwardBackGesture(head, rightHand, leftHand);
}
}

通过姿势识别来进行幻灯片控制简单高效,但是也存在着两个主要问题:

首先是,如果幻灯片中嵌套有视频,flash或者其他多媒体要素的话,可能不能很好的控制这些要素的播放和暂停,一种处理办法是使用动画,使得用户在点击键盘显示多媒体的时候就开始播放。还有一种方法是使用VSTO编写针对PowerPoint的插件,来监听鼠标来控制多媒体播放。

其次是误操作问题,这个问题是使用基于姿势识别存在的最大问题。有时候可能出于肢体语言表达需要,可能需要张开双臂,或者弯下腰来捡东西,这样会使得头部关节点位置和手部关节点位置的相对关系可能会满足之前我们设定的距离,从而产生误操作。

使用姿势识别的第一个问题是一个普遍存在的问题,即使使用ppt控制器也存在该问题,ppt控制器似乎也是通过发送键盘点击事件来进行幻灯片控制的。第二个问题可以使用手势识别的方式来在一定程度上避免。

Skeleton closestSkeleton = (from s in skeletons
where s.TrackingState == SkeletonTrackingState.Tracked &&
s.Joints[JointType.Head].TrackingState == JointTrackingState.Tracked
select s).OrderBy(s => s.Joints[JointType.Head].Position.Z)
.FirstOrDefault();

手势识别控制

手势识别通过判断在一定时间内一系列连续的动作之间的前后相关关系来进行动作的识别,在第十篇 文章中对swip这一动作如何识别有详细介绍。在Kinect for Windows Developer ToolKit v 1.5中,增加了一个名为Slideshow Gesture-WPF的例子。

要使用该dll提供的手势识别,必须先创建一个Recognizer对象。然后初始化改Recognizer。在初始化的时候注册左右挥动识别后进行的操作,该操作可以通过方法提供,由于方法体比较小,这里使用lambda表达式。

private readonly Recognizer activeRecognizer;
this.activeRecognizer = this.CreateRecognizer();
private Recognizer CreateRecognizer()
{
// Instantiate a recognizer.
var recognizer = new Recognizer();
// swipe right to press right key .
recognizer.SwipeRightDetected += (s, e) =>
{
System.Windows.Forms.SendKeys.SendWait("{Right}");
};
// swipe left to press left key ..
recognizer.SwipeLeftDetected += (s, e) =>
{
System.Windows.Forms.SendKeys.SendWait("{Left}");
};
return recognizer;
}

然后在sensor_SkeletonFrameReady事件中调用即可


private Skeleton[] skeletons = new Skeleton[];
private void sensor_SkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e)
{
// Get the frame.
using (var frame = e.OpenSkeletonFrame())
{
// Ensure we have a frame.
if (frame != null)
{
// Resize the skeletons array if a new size (normally only on first call).
if (this.skeletons.Length != frame.SkeletonArrayLength)
{
this.skeletons = new Skeleton[frame.SkeletonArrayLength];
}
// Get the skeletons.
frame.CopySkeletonDataTo(this.skeletons);
// Pass skeletons to recognizer.
this.activeRecognizer.Recognize(sender, frame, this.skeletons);
}
}
}

把上面的代码放到程序中,运行即可看到使用左手向左挥手,使用右手向右挥手即可控制幻灯片向左向右切换。如前面的文章所述,使用手势识别动作有一个时间阈值和一定的规则,如果该动作在某一时间内没有完成则识别失败。所以在本例中,如果挥手动作过慢,可能导致识别不出。而不像之前使用姿势识别例子中的那样,只需保持某个动作即可完成识别操作,这在一定程度上减少了第一种情况下出现误识别的概率。

Kinect 开发 —— 控制PPT播放的更多相关文章

  1. 基于windowsphone7的控制ppt播放

    最近突然想起了一个学长的一个利用手机控制ppt播放的一个创意,并想将其在windows phone7上实现一下. 经过几天的努力已经可以控制ppt的播放,暂停,上一张,下一张了,并且电脑会将当前ppt ...

  2. Kinect开发文章目录

    整理了一下去年为止到现在写的和翻译的Kinect的相关文章,方便大家查看.另外,最近京东上微软在搞活动, 微软 Kinect for Windows 京东十周年专供礼包 ,如果您想从事Kinect开发 ...

  3. Kinect开发笔记之二Kinect for Windows 2.0新功能

    这是本博客翻译文档的第一篇文章.笔者已经苦逼的竭尽全力的在翻译了.但无奈英语水平也是非常有限.不正确或者不妥当不准确的地方必定会有,还恳请大家留言或者邮件我以批评指正.我会虚心接受. 谢谢大家.   ...

  4. Kinect开发学习笔记之(一)Kinect介绍和应用

    Kinect开发学习笔记之(一)Kinect介绍和应用 zouxy09@qq.com http://blog.csdn.net/zouxy09 一.Kinect简单介绍 Kinectfor Xbox ...

  5. iOS开发—音乐的播放

    iOS开发—音乐的播放 一.简单说明 音乐播放用到一个叫做AVAudioPlayer的类,这个类可以用于播放手机本地的音乐文件. 注意: (1)该类(AVAudioPlayer)只能用于播放本地音频. ...

  6. 手机控制PPT good

    以前做了一个小东西,通过手机来控制PPT的翻页,最大化和最小化,东西很简单,近期整理电脑发现了拿来和大家分享一下 主要分为两个部分,客户端和服务器 客户端实现 当初考虑到跨平台的特性就选择了qt来写的 ...

  7. Kinect开发资源汇总

    Kinect开发资源汇总   转自: http://www.sigvc.org/bbs/forum.php?mod=viewthread&tid=254&highlight=kinec ...

  8. 自己编写的一个有关安卓应用开发培训PPT

    这个是我自己编写的一个有关安卓应用开发培训PPT,适合新手. 在这里下载PPT

  9. Swift实战-豆瓣电台(九)简单手势控制暂停播放(全文完)

    Swift实战-豆瓣电台(九)简单手势控制暂停播放 全屏清晰观看地址:http://www.tudou.com/programs/view/tANnovvxR8U/ 这节我们主要讲UITapGestu ...

随机推荐

  1. ES6中includes、startsWith、endsWith

    es6新增includes:返回布尔值,表示是否找到字符串.startsWith:返回布尔值,表示字符串是否在源字符串的头部位置.endsWith:返回布尔值,表示参数字符串是否在源字符串尾部. va ...

  2. [APIO2014]回文串 后缀自动机_Manancher_倍增

    Code: // luogu-judger-enable-o2 #include <cstdio> #include <algorithm> #include <cstr ...

  3. 关于zxing生成二维码,在微信长按识别不了问题

    在做校园学生到校情况签到系统时,我采用了zxing作为二维码生成工具.在测试的时候使用微信打开连接发现.我长按我的二维码之后,总是不会出现以下这种识别二维码的选项. 这就大大的降低了用户的体验,只能大 ...

  4. bzoj1618 购买干草

    Description 约翰的干草库存已经告罄,他打算为奶牛们采购日(1≤日≤50000)磅干草.他知道N(1≤N≤100)个干草公司,现在用1到N给它们编号.第i个公司卖的干草包重量为Pi(1≤Pi ...

  5. 前端之CSS介绍

    CSS介绍 CSS(Cascading Style Sheet,层叠样式表)定义如何显示HTML元素. 当浏览器读到一个样式表,它就会按照这个样式表来对文档进行格式化(渲染). CSS的语法 CSS语 ...

  6. shell脚本不同运行方式的差异

    说明:以下是个人的见解,不一定都正确,如有错误,欢迎指正! 一,shell脚本的运行方式,最常见的有以下几种: 1 )  . xxx.sh,注意,前面是一个点'.' 2 ) source xxx.sh ...

  7. python-排序算法 冒泡和快速排序

    交换排序 交换排序有冒泡排序和快速排序 冒泡排序 冒泡排序就是每次找出最大(最小)元素,放在集合最前或最后,这是最简单的排序算法 print("未排序之前:",collection ...

  8. HDU——T 2647 Reward

    http://acm.hdu.edu.cn/showproblem.php?pid=2647 Time Limit: 2000/1000 MS (Java/Others)    Memory Limi ...

  9. [Recompose] Merge RxJS Button Event Streams to Build a React Counter Component

    Combining input streams then using scan to track the results is a common scenario when coding with s ...

  10. 为什么用卷积滤波,而不是非常easy的在频率领域内进行数据的频率处理

    卷积.为了更好的"动态"滤波. 问题来了.为什么用卷积滤波.而不是非常easy的在频率领域内进行数据的频率处理? 为了强调我觉得的答案,已经用blog标题给出了.卷积.为了更好的& ...