关注Leap Motion很长时间了,很早就想入手。可是,一方面,一直忙着其它的比赛,没时间顾及;二是缺钱,钱都垫在比赛上了。

好不容易,11月18日,下定决心买进了,这么长时间,也就是再给贵阳职业学院的学生上课的时候显摆了一次。

周末休息,总算是强迫自己摆弄一下Leap Motion了。

那么做点什么呢?不放就先从简单的开始吧,就在窗口上显示一个红色的圆,以表示追踪到的某一个手指头(指尖)。

要开发Leap Motion应用,我觉得官方的文档必须要仔细的看看。

文档1:开发者首页,这里可以下载SDK。

文档2:理解C#例程,以便开发我们自己的应用程序。

文档3:Leap概述,获取开发的必要知识。

Step1:下载SDK,并解压缩。在“LeapSDK”中有我们需要用的源代码和类库。

Step2:创建一个C# WPF应用程序,不妨就叫“LeapMotion1_WPF”。

Step3:在项目中添加“lib/LeapCSharp.NET4.0.dll”引用(如果是.net framework 3.5的话,则添加LeapCSharp.NET3.5.dll),如图。

Step4:在项目中添加现有项,“lib/x86/Leap.dll”、“lib/x86/Leap.lib”和“lib/x86/LeapCSharp.dll”三个文件,并设置三个文件“始终复制”到输出目录,如图。

Step5:创建用户界面,在MainWindow上,放一个Canvas,两个Button,一个Ellipse,如图。

设置好相应的属性。Canvas的大小和窗口一样。

Step6:编写“连接设备”按钮的单击事件。在该事件中,我们需要让Leap Motion工作起来。不放看看“samples/Sample.cs”中是如何实现的。

该类实现的是一个控制台应用程序。我们从main开始看。代码如下:

     public static void Main ()
{
// Create a sample listener and controller
SampleListener listener = new SampleListener ();
Controller controller = new Controller (); // Have the sample listener receive events from the controller
controller.AddListener (listener); // Keep this process running until Enter is pressed
Console.WriteLine ("Press Enter to quit...");
Console.ReadLine (); // Remove the sample listener when done
controller.RemoveListener (listener);
controller.Dispose ();
}

文档2中说,“The Controller class provides the main interface between the Leap and your application. When you create a Controller object, it connects to the Leap software running on the computer and makes hand tracking data available through Frame objects. You can access these Frame objects by instantiating a Controller object and calling the Controller.Frame method”,即应用程序使用Controller对象来访问Leap硬件,追踪到的数据封装在Frame对象中的,这个对象可以通过Controller.Frame获取。

文档2中还说,“If your application has a natural update loop or frame rate, then you can call Controller.Frame as part of this update. Otherwise, you can add a listener to the controller object. The controller object invokes the callback methods defined in your Listener subclass whenever a new frame of tracking data is available (and also for a few other Leap events)”。如果开发的应用程序本身有个大循环的话(类似XNA应用程序的update,或是单片机程序的loop),可以在这个大循环中通过Controller.Frame获取Frame对象。否则,我们可以给Controller对象提供一个Listener,当Controller准备好新的Frame时会回调Listener,之后我们在进行处理。

这样来看,前三行代码就比较好理解了。

在我们的项目中,“连接设备”按钮的单击事件的代码如下:

         private void Button_Click_1(object sender, RoutedEventArgs e)
{
listener = new MyLeapListener();
controller = new Controller();
controller.AddListener(listener); btn1.IsEnabled = false;//btn1表示“连接设备”
btn2.IsEnabled = true;//btn2表示“断开设备”
}

Step7:“断开设备”的点击事件的代码自然也比较容易写出,代码如下:

         private void Button_Click_2(object sender, RoutedEventArgs e)
{
controller.RemoveListener(listener); btn1.IsEnabled = true;
btn2.IsEnabled = false;
}

Step8:仿照例程的Main方法,我们还需要销毁Controller对象。如下:

         private void Window_Closing_1(object sender, System.ComponentModel.CancelEventArgs e)
{
controller.Dispose();
}

Step9:实现自己的监听器。先来看看SampleListener是如何实现的呢?其骨架如下。

 class SampleListener : Listener
{
public override void OnInit (Controller controller)
{
} public override void OnConnect (Controller controller)
{
} public override void OnDisconnect (Controller controller)
{
} public override void OnExit (Controller controller)
{
} public override void OnFrame (Controller controller)
{
}
}

同样是在文档2中有详细的说明,我就不粘贴原文了。我们自己创建的监听器需要继承Listener,可以根据需要重写上面几个方法。对于我们而言,需要关注的是OnFrame方法,因为当一个新的Frame准备好后会调用这个方法。

在LeapMotion1_WPF命名空间中添加一个新类MyLeapListener,其实现如下:

     class MyLeapListener : Listener
{
public override void OnFrame(Controller ctl)
{
}
}

Ok,非常好。我们可以在OnFrame方法中获得Frame对象,然后获取关于指尖的数据,然后进行一些操作,就如例程中那样。但是,在这个方法中,我们是无法改变Ellipse的位置的。我们需要多做一步操作,在MyLeapListener的OnFrame方法触发的时候,通知调用者进行处理。显然,使用事件可以完美的解决我们的问题。于是,我们修改了MyLeapListener的代码:

     class MyLeapListener : Listener
{
public event EventHandler OnFrameEvent = null;
public override void OnFrame(Controller ctl)
{
if (OnFrameEvent != null)
{
OnFrameEvent.Invoke(ctl, null);
}
}
}

在OnFrame方法中触发OnFrameEvent事件。那么,相应的,在实例化MyLeapListener的时候,就应该加一个事件处理方法进去。在Button_Click_1方法中作如下修改:

         private void Button_Click_1(object sender, RoutedEventArgs e)
{
listener = new MyLeapListener();
listener.OnFrameEvent += listener_OnFrameEvent;

controller = new Controller();
controller.AddListener(listener); btn1.IsEnabled = false;
btn2.IsEnabled = true;
}

Step10:实现listener_OnFrameEvent方法。先把方法声明写出来。

         void listener_OnFrameEvent(object sender, EventArgs e)
{
}

按照之前的说法,追踪的数据是封装在Frame对象中的,因此,我们首先获取该对象。

             //获取帧数据
LeapFrame frame = controller.Frame();//using LeapFrame = Leap.Frame;

再往下就需要用到文档3的知识了。Leap可以同时检测到若干只手,并用Hand对象封装数据,建议最多2只手进入Leap的检测区域。需要注意的是Leap无法区分左右手。我们判断一下Leap是否检测到手,如果检测到的话,就获取第一个。

             //如果能够获取手部数据
if (!frame.Hands.IsEmpty)
{
//获取手部数据
Hand hand = frame.Hands[];
}

有了Hand对象,我们就能够知道手相对于Leap的位置。

                 //获取手部的位置,判断检测的范围
LeapVector palmPosition = hand.PalmPosition;//using LeapVetcor = Leap.Vector;
float palmHeight = palmPosition.y;

这里的高度为什么是y,不是z?文档3中有介绍的啊。Leap的坐标系如下图所示。

我们要在窗口中绘制Ellipse表示指尖在Leap检测区域中的位置,Leap检测的坐标是毫米,窗口绘制的时候是像素,这就涉及到了坐标的转换。

我曾看到一篇文章,其说Leap的检测角度为150度,因此,在不考虑z轴的情况下,我们可以计算出来手所在的高度检测的宽度是多少,并将指尖的位置映射到窗口上。文档3说明了有效的检测区域是设备上方25毫米-600毫米的范围,故可以将指尖的高度映射到窗口上。

                 float detectionWidth = (float)(palmHeight * Math.Tan(75.0 / 180.0 * Math.PI) * );

有了手的数据,我们接下来获取指尖的信息。Leap检测时,并不是每一帧都包括指尖的信息,例如当握拳时就无法得到指尖的数据。所以,在使用指尖数据时,我们需要判断一下。

                 //获取指尖的数据
FingerList fingers = hand.Fingers;
if (!fingers.IsEmpty)
{
Finger f1 = fingers[];
}

获取指尖的位置数据,并计算其在窗口上的位置。

                     LeapVector position = f1.TipPosition;

                     float x = position.x;
float y = position.y; //下面将x、y映射到屏幕上
double screenWidth = canvas1.ActualWidth;
double screenHeight = canvas1.ActualHeight; x = x / detectionWidth * screenWidth + (screenWidth / );
y = screenHeight - y / ( – ) * screenHeight;

最后,需要设置Ellipse的位置。

                     this.Dispatcher.BeginInvoke(new Action(delegate {
Canvas.SetLeft(ellipse, x);
Canvas.SetTop(ellipse, y);
}), null);

注意,不能直接调用Canvas.SetLeft会出错的。

好了,运行程序,看看效果吧。

注意:

1、using Leap;

2、注意代码的缩进。

LeapMotion(1):环境配置、简单测试、理解对象的更多相关文章

  1. YOLOv4 资源环境配置和测试样例效果

    YOLOv4 资源环境配置和测试样例效果 基本环境:cuda=10.0,cudnn>=7.0, opencv>=2.4 一.下载yolov4 git clone https://githu ...

  2. Python+Selenium笔记(一):环境配置+简单的例子

    #环境配置基于windows操作系统 #学习selenium要有一些HTML和xpth的基础,完全不会的建议先花点时间学点基础(不然元素定位,特别是xpth可能看的有点懵) #HTML :  http ...

  3. Tomcat环境配置部署测试环境及架构

    Tomcat环境配置已经在前面介绍过了,这边就为童鞋们介绍下对于Tomcat的架构是怎么样的! Tomcat的架构包含(bin.conf.lib.logs.temp.wenapps.work)等文件夹 ...

  4. nodejs安装、环境配置和测试

    nodejs下载 https://nodejs.org/en/ nodejs安装 双击下载的nodejs,可自定义安装路径,安装模块部分直接next即可安装. 检查是否安装 win+R输入cmd,打开 ...

  5. Windows10 + Visual Studio 2017 + CMake +OpenCV编译、开发环境配置及测试

    由于最近需要使用OpenCV,本人需要在自己的PC上使用OpenCV,因此最近一直在研究如何使用Visual Studio编译OpenCV源代码并搭建开发环境,折腾了很长时间,查阅了很多相关资料,终于 ...

  6. ionic+angularjs开发hybrid App(环境配置+创建测试项目)

    本文使用的系统是win10 因为后期需要使用nodejs 所以先把node装好 https://nodejs.org/download/ 下载JDK并配置Java运行环境 http://www.ora ...

  7. C连接MySQL数据库开发之Xcode环境配置及测试

    一.开发环境 Mac OS X 10.9.2 64位.Xcode5.1.MySQL5.5.37 64位 MySQL安装目录为:/usr/local/mysql 二.配置xcode连接mysql的编译选 ...

  8. C连接MySQL数据库开发之Windows环境配置及测试

    一.开发环境 Win8.1 64位.VS2013.MySQL5.5.3764位 MySQL安装目录为:C:\Program Files\MySQL\MySQL Server 5.5 二.配置工程环境 ...

  9. Eclipse Maven profiles 多环境配置,测试环境与开发环境分开打包

    1.将开发环境.测试环境.生产环境的配置文件分开存放,如下图: 2.在Maven中配置不同的环境打包配置文件的路径,配置如下: <profiles> <profile> < ...

  10. Java Jdk 环境配置和测试

    测试jdk:1.6 安装完jdk1.6以后,在我的电脑中找到环境变量配置 在系统变量的Path 中输入 ;E:\Program Files (x86)\Java\jdk1.6.0_01\bin(路径根 ...

随机推荐

  1. 《MFC游戏开发》笔记八 游戏特效的实现(二):粒子系统

    本系列文章由七十一雾央编写,转载请注明出处. http://blog.csdn.net/u011371356/article/details/9360993 作者:七十一雾央 新浪微博:http:// ...

  2. 剑指Offer25 二叉搜索树转换为排序双向链表

    /************************************************************************* > File Name: 25_BSTCon ...

  3. Java中创建操作文件和文件夹的工具类

    Java中创建操作文件和文件夹的工具类 FileUtils.java import java.io.BufferedInputStream; import java.io.BufferedOutput ...

  4. hdu 3585 二分+最大团

    题目:给出平面上n个点,现在找m个点,并且使得这m个点最近的两个最远. 分析:显然这满足二分的性质,二分答案,根据点距离需要大于等于二分值重新构造新图,则问题变成了:在新图中找出满足所有点对之间的距离 ...

  5. CF 208E - Blood Cousins dfs序+倍增

    208E - Blood Cousins 题目:给出一棵树,问与节点v的第k个祖先相同的节点数有多少个. 分析: 寻找节点v的第k个祖先,这不就是qtree2简化版吗,但是怎么统计该祖先拥有多少个深度 ...

  6. 用jquery 实现 超出字符 截断加上省略号并且可以提示全部内容

    1.test.jsp Java代码 <%@ page language="java" pageEncoding="UTF-8"%> <html ...

  7. DynamicObject数据包操作

    DynamicObject的结构非常简单明了,就是一个字典,类似于一个Dictionary<string, object>,其中的object可能是一个简单值(普通字段),可能是一个复杂值 ...

  8. 2015英特尔® 实感™ (Intel® RealSense™) 动手开发实验课

    2015年英特尔® 全球实感技术动手实验课路演来到中国, 这次在中国将有北京和广州两站,包括一天的动手实验室活动 - 面向对感知计算.3D 开发和虚拟现实兴趣浓厚的开发人员.英特尔专家将会指导您如何借 ...

  9. dataAdapter与dataSet和dataTable的填充

    对于dataAdapter与dataSet和dataTable的填充,可以分为1对1,1对n,n对n,3种情况. 以SqlDataAdapter为例. //(1)1对1 SqlDataAdapter ...

  10. 《iOS开发指南》正式出版-源码-样章-目录,欢迎大家提出宝贵意见

    智捷iOS课堂-关东升老师最新作品:<iOS开发指南-从0基础到AppStore上线>正式出版了 iOS架构设计.iOS性能优化.iOS测试驱动.iOS调试.iOS团队协作版本控制.... ...