前言:
之前写过一篇关于姿势(pose)识别的博文,之后又定义了几个姿势实现了体感俄罗斯方块。姿势识别是通过关节点与关节点之间的相对位置关系来进行判断。当判断成立,即执行指定的指令。那么,我们就可以指定姿势实现我们的天花乱坠的想法啦~~~ PPT播放助手应运而生。
基本思路:
有了Kinect,我们就可以使用手势(手部姿势)来控制幻灯片的播放,而不需要一边演讲一遍按键盘或者手持一个ppt控制器,我们只需要做的就是双手握住头部就实现放映,轻轻的向左或者向右挥一下手就可以控制幻灯片向前或者向后翻一页,双手举起就使屏幕变黑。酷吧。虽然可能在演讲的时候做这个动作可能有点奇怪,但是这也是一种控制幻灯片放映的好方法。
实现Kinect控制幻灯片播放很简单,主要思路是:使用Kinect捕捉人体动作,然后根据识别出来的动作向系统发出点击向前,向后,"F5","B"按键的事件,从而使得幻灯片能够切换,放映,变黑。 这里的核心功能在于手势的识别,我们在开发之前需要定义怎么样的手势算是向前或者向后切换幻灯片。
对应关系:
姿势 | 对应按键 | 触发动作 |
双手抱住头部 | F5 | 放映 |
向左挥动左手 | left | 上一页 |
向右挥动右手 | right | 下一页 |
双手举起 | B | 变黑 |
代码实现
由于之前几篇博文已经写了获取Kinect各种数据的代码,在此就讨论关键部分的代码。
由于是姿势控制,自然存在精确度的问题,所以我们需要定义几个阈值,作为判断依据。
/// <summary> /// 手臂水平伸展的阈值 /// </summary> private const double ArmStretchedThreshold = 0.45; /// <summary> /// 手臂垂直上举的阈值 /// </summary> private const double ArmRaisedThreshold = 0.20; /// <summary> /// 头离双手距离的阈值 /// </summary> private const double DistanceThreshold = 0.05;
在控制ppt播放命令中,我们设定,如果双手距离头部小于0.05,认为用户试图进行点击键盘上的F5键,如果右手关节点在x轴上的距离比头部关节点大于0.45的话,认为用户试图进行点击键盘上的right按钮。如果头部关节点位置在x轴方向是比左手关节点在x轴上的位置大于0.45的话,认为用户试图点击键盘上的left按钮。如果双手超过头部高度0.20的话,认为用户试图点击键盘上的B键,0.05、0.45和0.20这几个阈值是通过反复测试的出来的(没错,是Test,而不是Dubug);所以,测试很重要。
关键代码如下:
/// <summary> /// 处理手势的方法 /// </summary> /// <param name="head"></param> /// <param name="rightHand"></param> /// <param name="leftHand"></param> private void ProcessForwardBackGesture(Joint head, Joint rightHand, Joint leftHand) { //若右手位置的横坐标值超过设定的阈值,除法PPT下一页命令 if (rightHand.Position.X > head.Position.X + ArmStretchedThreshold) { if (!isForwardGestureActive) { //激活forward命令,确保每次操作执行一次命令 isForwardGestureActive = true; //模拟鼠标按下“右”方向键 System.Windows.Forms.SendKeys.SendWait("{Right}"); } } else { isForwardGestureActive = false; } //若左手位置的横坐标超过设定的阈值,触发PPT上一页命令 if (leftHand.Position.X < head.Position.X - ArmStretchedThreshold) { if (!isBackGestureActive) { //激活back命令,确保每次操作执行一次命令 isBackGestureActive = true; //模拟鼠标按下“左”方向键 System.Windows.Forms.SendKeys.SendWait("{Left}"); } } else { isBackGestureActive = false; } //双手同时上举,在控制PPT时让屏幕变黑 if ((leftHand.Position.Y > head.Position.Y - ArmRaisedThreshold) && (rightHand.Position.Y > head.Position.Y - ArmRaisedThreshold)) { if (!isBlackScreenActive) { isBlackScreenActive = true; System.Windows.Forms.SendKeys.SendWait("{B}"); } } else { isBlackScreenActive = false; } //判断双手靠近头部,触发PPT放映 if (Math.Abs(head.Position.Y - rightHand.Position.Y) < DistanceThreshold && (Math.Abs(head.Position.Y - leftHand.Position.Y) < DistanceThreshold && !isForwardGestureActive &&!isBackGestureActive)) { if (!isPresent) { isPresent = true; System.Windows.Forms.SendKeys.SendWait("{F5}"); } } else { isPresent = false; } }
上面的代码中,当判断到用户向右挥手动作是,执行System.Windows.Forms.SendKeys.SendWait("{Right}")语句从而发出点击键盘向右按键; 该方法执行时,要求PowerPoint程序处于当前活动的状态,这样里面的PPT才会向右键盘点击事件。需要注意的是方法中isBackGestureActive,isForwardGestureActive,isBlackScreenActive和isPresent这四个布尔型的标志位,可以防止当用户一直处于某一个动作时会一直发送System.Windows.Forms.SendKeys.SendWait("{xx}")。
上面的方法需要放在sensor_SkeletonFrameReady事件中,首先获取头部,左手右手关节点数据,然后调用该方法。
/// <summary> /// 骨骼事件处理 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> 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 = skeletons.Where(s => s.TrackingState == SkeletonTrackingState.Tracked) .OrderBy(s => s.Position.Z * Math.Abs(s.Position.X)) .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.NotTracked || rightHand.TrackingState == JointTrackingState.NotTracked || leftHand.TrackingState == JointTrackingState.NotTracked) { //Don't have a good read on the joints so we cannot process gestures return; } //调用填充头和双手位置图案的的方法 SetEllipsePosition(ellipseHead, head, false); SetEllipsePosition(ellipseLeftHand, leftHand, isBackGestureActive); SetEllipsePosition(ellipseRightHand, rightHand, isForwardGestureActive); //调用处理手势的方法 ProcessForwardBackGesture(head, rightHand, leftHand); }
代码已开诚布公到GitHub:https://github.com/Marsyangkang/KinectPowerpointControl
Kinect开发系列博文:
相关推荐
Kinect开发教程.pdf
kinect应用开发实战
kinect核心技术简介; kinect音频开发文档; kinect机械学习摘要; ProgrammingGuide_KinectSDK; SkeletalViewer_Walkthrough。
Kinect2.0开发实用文档
介绍基本的kinect技术开发的文档!共享给大家使用。
一份基础的KINECT的开发进阶文档,希望有志者一起进步!
PC 版ms kinect SDK 控制 PowerPoint C# source code
Kinect_Kinect Hands Finger Tracking and Voxel UI.pptx
非常有用的matlab实例,包含C++程序可以用于Microsoft Kinect等多种编程环境,起很强的加速作用,
kinect开发教程,需要一定的c++和c#基础,需要有一定的英文阅读基础
kinect for windows 开发从入门到精通,总共包含27份文档,内容包括从kinect环境配置到应用开发的全过程。
本资料收集并整理了第二代Kinect入门开发的资料。适合准备利用Kinect开发的学生、爱好者和工作人员。程序主要用WPF开发,也涉及到如何Unity3D和Kinect结合的介绍。资料具体介绍如下: 1.资料内容 提供C#+Kinect...
Kinect的开发人员的福音,超级棒的一本电子书,希望对大家有帮助
《Kinect人机交互开发实践》分为3个部分,首先介绍了Kinect的结构和功能以及如何配置相关的开发环境,接着结合实例介绍如何使用Kinect for Windows SDK提供的API,最后通过4个实例详细讲述了使用Kinect for Windows ...
关于kinect开发的程序,是我从很多立方搜集来的,希望正在研究kinect的朋友有帮助 手势识别非常重要的一个特点是要体验要好,即需要以用户为核心。而手势的定位一般在手势识别过程的前面,在上一篇博文kinect+OpenNI...
包含Kinect v1和Kinect v2分别在Windows 平台与Ubuntu16.04+ROS kinetic 平台安装方法
Unity结合Kinect2体感开发:KinectForWindows_UnityPro
Azure Kinect的入门开发,您可以通过本示例了解微软Azure Kinect的基本使用。
《Kinect应用开发实战》全书,适合各个阶段水平的读者。内容很不错
本文是整理中的Kinect for Windows v2 的C++ 程式开发教程。内容包括但不限于: • Kinect for Windows SDK v2 基本介绍 • Kinect for Windows SDK v2 C++ API 简介 • K4W v2 C++ Part 1:简单的深度读取方法 • ...