上一篇文章,我们实现了Leap Motion的简单测试。追踪其中一个手指并用红色圆形表示其在空间的位置。

这篇文章,我们来实现五指的追踪。

其实,能够实现一指的追踪,那么五指的追踪自然不成问题。但是,还是有几个问题我们需要考虑一下。

1、并不是每一帧都会包含五指的全部信息。

比如,当前帧包含了五指信息,那么,窗口上就会显示五个红色圆。如果此时用户握拳,那么,下一帧就可能只会有一指的信息。此时,就应从窗口中移除多余的四个红色圆。

2、手指如何和红色圆对应。

因为Hand.Fingers集合对应的不一定是拇指、食指、中指、无名指、小指(可能对应的是小指、无名指、中指),所以,得想个办法把某个指尖和某个红色圆对应起来。幸好,Leap为每个对象都定义了ID。这样,我们就可以将指尖的ID和红色圆绑定在一起。自然地,我们会想到用Dictionary<int, Ellipse>。

还有一点,假设上一帧检测到了拇指(id为5)、这一帧没检测到拇指,而下一帧又检测到了拇指,那么,它的id可能是5,但也有可能不是5。

3、如何删除上一帧有的而这一帧中没有的红色圆。

这个问题相对简单,做一个List<int>,把这一帧中id一次加进去,然后,再从Dictionary<int, Ellipse>的Keys里面删除那些不在List<int>中的id所对应的红色圆。

OK,大部分问题都有了思路,那么,我们开始写代码吧。记得,一定要先看看上一篇文章啊。

Step1:构造下面的用户界面。

Step2:声明MyLeapListener类和窗口Closing事件。代码和LeapMotion(1)中的一样。

Step3:添加成员变量Dictionary<int, Ellipse>表示手指ID和红色圆的对应,添加成员变量List<int>表示当前帧追踪到的手指编号。代码如下:

         private Dictionary<int, Ellipse> ellipses;
private List<int> fingerIds;

Step4:编写“连接设备”的单击事件和“断开设备”的单击事件。与之前不同的是,在“连接设备”的单击事件中,需要初始化ellipses成员变量,在“断开设备”的单击事件中,需要清空ellipses成员变量。

         private void connect_device_button_Click(object sender, RoutedEventArgs e)
{
listener = new MyLeapListener();
listener.OnFrameEvent += listener_OnFrameEvent;
controller = new Controller();
controller.AddListener(listener); connect_device_button.IsEnabled = false;
disconnect_device_button.IsEnabled = true; ellipses = new Dictionary<int, Ellipse>();
fingerIds = new List<int>();
} private void disconnect_device_button_Click(object sender, RoutedEventArgs e)
{
controller.RemoveListener(listener); connect_device_button.IsEnabled = true;
disconnect_device_button.IsEnabled = false; ellipses.Clear();
}

Step5:编写OnFrameEvent事件。还是先放上事件声明。

         void listener_OnFrameEvent(object sender, EventArgs e)
{ }

和之前一样,在事件中,我们首先要获取追踪到的手部的信息。

             LeapFrame frame = controller.Frame();//获取当前帧
if (!frame.Hands.IsEmpty)//判断是否追踪到手部
{
Hand hand = frame.Hands.FirstOrDefault();//获取追踪到的第一只手
LeapVector palmPosition = hand.PalmPosition;//获取手部位置
float palmHeight = palmPosition.y;
float detectionWidth = (float)(palmHeight * Math.Tan(75.0 / 180.0 * Math.PI) * );//计算当前高度的检测宽度 //将要放下面的代码 }

接下来,就需要找到追踪到的每一个指尖(是指尖,而不是笔之类的东西欧)。

                 foreach (Finger finger in hand.Fingers.Where(f => f.IsFinger))
{
//将要放下面的代码
}

获取指尖id放入List<int>,然后判断Dictionary<int, Ellipse>中是否有指定id对应的ellipse。代码如下:

                     //获取指尖ID,放入List<int>
fingerIds.Add(finger.Id); Ellipse ellipse = null;
if (ellipses.ContainsKey(finger.Id))//如果在Dictionary<int, Ellipse>中有,则用ellipse表示其
{
ellipse = ellipses[finger.Id];
}
else//Dictionary<int, Ellipse>中不存在,则创建一个ellipse
{
this.Dispatcher.Invoke(new Action(delegate
{
ellipse = new Ellipse();
ellipse.Width = ;
ellipse.Height = ;
ellipse.Fill = Brushes.Red;//10x10大小的红色圆
ellipses.Add(finger.Id, ellipse);
container_canvas.Children.Add(ellipse);
}), null);
}

然后,就是在Canvas中设置ellipse的位置了。代码比较简单(和上一篇中的代码类似),如下:

                     //设置ellipse的位置
LeapVector position = finger.TipPosition; double x = position.x;
double y = position.y; double screenWidth = container_canvas.ActualWidth;
double screenHeight = container_canvas.ActualHeight; x = x / detectionWidth * screenWidth + (screenWidth / );
y = screenHeight - y / * screenHeight; this.Dispatcher.BeginInvoke(new Action(delegate
{
Canvas.SetLeft(ellipse, x);
Canvas.SetTop(ellipse, y);
}), null);

这样,我们就完成了指尖位置的绘制。

但是,要记得,在Dictionary<int, Ellipse>中可能存在本帧中没有检测到的指尖的id。为此,我们需要移除Dictionary<int, Ellipse>中那些多余的Key。代码如下:

                 //去掉这一帧中没追踪到的手指
IEnumerable<int> deletedIds = ellipses.Keys.Except(fingerIds);
foreach (int id in deletedIds.ToList())//这里要记得ToList()一下,否则会出现异常。
{
Ellipse ellipse = ellipses[id]; this.Dispatcher.Invoke(new Action(delegate
{
container_canvas.Children.Remove(ellipse);
}), null); ellipses.Remove(id);
} //完成本次绘制,清空List<int>
fingerIds.Clear();

ok,这样就完成了。运行程序看看吧。

你会发现,基本上还是我们要的效果。但是,

当手越高,指尖距离越近,这是为什么呢?考虑一下。

附上源代码

LeapMotion(2):追踪五指的更多相关文章

  1. LeapMotion控制器 java语言开发笔记--(LeapMotion控制器简介)

    (1)LeapMotion系统识别和追踪手,手指,以及根手指类似的工具,这个设备运行在一个极小的范围,这个范围拥有个高精度,高跟踪频率可以记录离散的点,手势,和动作. (2)LeapMotion控制器 ...

  2. 基于OpenCV的车辆检测与追踪的实现

    最近老师布置了一个作业,是做一个基于视频的车辆检测与追踪,用了大概两周的时间做了一个简单的,效果不是很理想,但抑制不住想把自己的一些认识写下来,这里就把一些网络上的博客整理一下分享给大家,希望帮助到大 ...

  3. 基于Cat的分布式调用追踪

    Cat是美团点评出的一款APM工具,同类的产品也有不少,知名的开源产品如zipkin和pinpoint:国内收费的产品如oneapm.考虑到Cat在互联网公司的应用比较广,因此被纳入选型队列,我也有幸 ...

  4. Office 365 如何使用powershell查询邮件追踪

    如何使用Powershell 对office365的邮件进行查询追踪 1. 首先链接到Exchange Online 管理上面 $UserCredential = Get-Credential $Se ...

  5. java性能调优及问题追踪--Btrace的使用

    在生产环境中经常遇到格式各样的问题,如OOM或者莫名其妙的进程死掉.一般情况下是通过修改程序,添加打印日志:然后重新发布程序来完成.然而,这不仅麻烦,而且带来很多不可控的因素.有没有一种方式,在不修改 ...

  6. 追踪记录每笔业务操作数据改变的利器——SQLCDC

    对于大部分企业应用来用,有一个基本的功能必不可少,那就是Audit Trail或者Audit Log,中文翻译为追踪检查.审核检查或者审核记录.我们采用Audit Trail记录每一笔业务操作的基本信 ...

  7. 2016-1-30 Servlet中Session管理(Sesssion追踪)

    Session管理(Sesssion追踪)是Web应用程序开发中非常重要的一个主题.这是因为HTTP是无状态的,在默认情况下,Web服务器不知道一个HTTP请求是来自初次用户,还是来自之前已经访问过的 ...

  8. Metaio获取当前追踪的对象的方法

    重写 onTrackingEvent获取TrackingValues集合,然后通过TrackingValues的state属性的isTrackingState()方法判断是否为追踪状态,或者直接使用s ...

  9. 基于zipkin分布式链路追踪系统预研第一篇

    本文为博主原创文章,未经博主允许不得转载. 分布式服务追踪系统起源于Google的论文“Dapper, a Large-Scale Distributed Systems Tracing Infras ...

随机推荐

  1. maven安装仓库中不存在的jar包

    这里以ojdbc6.jar作为案例 首先我的ojdbc6.jar放在D盘的根目录D:\ojdbc6.jar 然后我们打开cmd命令窗口,运行命令:mvn install:install-file -D ...

  2. HDU 2571 命运 (DP)

    命运 Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit Status Pr ...

  3. Centos安装配置Postfix邮件服务器

    发布时间:July 6, 2012 // 分类:Mail // No Comments 在安装邮件服务器之前先了解几个名词,以后会用到: 1 2 3 4 5 6 MUA:用户代理端,即用户使用的写信. ...

  4. Android渠道汇总

    序号 渠道名  渠道说明 特殊渠道   1 googleplay  google市场 2 umeng  自动更新 3 office_web  官方网络 4 office_qrcode 官方二维码 硬件 ...

  5. ASP三种常用传值方式:

    ASP 页面(两个aspx页面)传值方式:背景: 两个aspx 页面valuepage.aspx tbusername tbpwdobtainvalue.aspx tbusername tbpwd 1 ...

  6. Linq To Csv 实例简说

    http://www.codeproject.com/Articles/25133/LINQ-to-CSV-library 详细源代码在这里 https://github.com/mperdeck/L ...

  7. Centos下LAMP环境搭建

    CentOs下环境搭建.2015.04.15.0001 Author:周凯 Time: 2015.04.15 版本号:2015.04.15.0001 安装过程 安装apache yum install ...

  8. Part 7Handling events in AngularJS

    Let us understand with an example. Here is what we want to do. 1. Display the list of technologies i ...

  9. java中初始化时机和顺序呢

    class Pupil{ Pupil(int age){ System.out.println("Pupil:"+age); } } class Teacher{ Pupil p1 ...

  10. 使用runtime给类动态添加方法并调用 - class_addMethod

    上手开发 iOS 一段时间后,我发现并不能只着眼于完成需求,利用闲暇之余多研究其他的开发技巧,才能在有限时间内提升自己水平.当然,“其他开发技巧”这个命题对于任何一个开发领域都感觉不找边际,而对于我来 ...