实现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. 上传golang 版本SDK

    在上传的时候,文件都上传成功了,但是返回的信息里面errcode 404 token 是"".是不是因为我的callbackUrl(随便写的) 写错导致的. 上传golang 版本 ...

  2. EasyUI 之 DataGrid的两种赋值方法

    方法一:使用ViewData赋值 首先,我们创建一个User的实体类 public class User { public string UserID; public string UserName; ...

  3. numa 和 mysql

    cpu numa结构反应的内存访问速度问题: 在多核cpu的时代引入了cpu的numa(非一致内存访问结构): NUMA引入了node的概念,每个物理CPU都被视作一个node,而每个node都有一个 ...

  4. [JSOI2018]潜入行动 树形DP_复杂计数

    code #include <cstdio> #include <algorithm> #include <cstring> #include <string ...

  5. iOS开发——捕获崩溃信息

    可通过注册NSUncaughtExceptionHandler捕获异常信息,将拿到的NSException细节写入Crash日志,精准的定位出错程序位置,有需要的,可直接将crash信息直接上传服务器 ...

  6. Java web application——基础

    概述 一个WAR文件包含了构成一个Web应用程序所需要的文件.WAR文件作为一个单元部署在一个或多个WebLogic Server实例上. WebLogic Server上的Web存档始终包含以下文件 ...

  7. 【BZOJ 1047】[HAOI2007]理想的正方形

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 二维的ST表. 每个大的正方形可以由4个小的正方形组成. 然后区域内的最大值最小值.也可以由4个小的张方形部分全部覆盖到. [代码] ...

  8. 实习第一天(安装svn管理工具跟tomcat插件)

    在eclipse中安装svn管理解压工具是有好几种方法. 方法1 1>可以直接下载svn插件subclipse,之后进行解压 2>然后将将插件包features和plugins目录中的文件 ...

  9. Delphi的参数修饰const/var/output 与C++的对应关系

    delphi的const/input和默认的没有修饰, C++都是一样的 delphi的var,对应C++那边是指针,  调用方需要管理内存(负责分配内存及销毁) delphi的output , 对应 ...

  10. 19.浏览器Window服务($window)

    转自:https://www.cnblogs.com/best/tag/Angular/ 引用浏览器的window对象.默认浏览器的window是全局的根对象. 示例代码: <!DOCTYPE ...