查看原文
其他

体感“神器” Leapmotion 使用小结

2016-11-08 Wenzy InsLab

“神器”之所以要打引号,是因为这个形容词放在几年前,是当之无愧的。但现在的体感设备层出不穷,相比之下。它的技术和体验早已不新鲜。

Leapmotion 早在 2013 年正式上市,却始终没有成为一款大众的产品。这里介绍它,是因为对创意编程而言,是个非常好的拓展工具,练习工具。相比鼠标,键盘,可以带来更新的交互体验。激发灵感的同时,能帮助你更好地理解三维空间。

Leapmotion 是什么?

Leapmotion 和 Kinect 一样,都可以归类为体感设备。前者于 13 年上市,后者是微软在 09 年推出的产品。

体感设备说得直白一点,就是传感器。像温度计测温度,湿度计测湿度。只是体感设备测量的东西不一样而已。无论 Leapmotion 还是 Kinect,它们最终会把测量到的信息传到电脑,这样就可以与程序产生各种交互。

测什么?

Leapmotion 的强项是用来识别手势。网上宣称的数据精度可达 0.01 mm。理论上支持识别多个手掌。但实际使用时,只有在单手或双手的情况下,效果才最稳定。


( Leapmotion 及其使用场景 )

而 Kinect 主要用于做骨架识别,人脸识别,以及简单的手势识别。能识别多人,适合捕捉更大范围的运动,如手臂的挥动等。


( Kinect 1 代 )


( Kinect 2 代 )

Leapmotion 的优势

相比 Kinect ,Leapmotion 有如下优点

  • 小巧便携

  • 灵敏,精度高

  • 偏向“桌面”操作

32g 的重量,可以让你可以和笔记本一起,随时随地带到身上。连接也仅要一根数据线,十分轻便。

可以做什么

  • 玩游戏


对于一般的用户,这可能是它最有吸引力的地方。Leapmotion 的官网有一个应用商店。() 你可以从中下载到各种免费或付费的应用和游戏,而且大部分能同时支持 mac 和 pc。

这里推荐一个富有禅意的游戏,可以用手指来捏造型。有点像玩软陶,它能充分展现 leapmotion 的特性。


  • 控制电脑

除了游戏之外,leapmotion 可以作为一个“鼠标替代器”。通过 Mudra Mouse 等应用,就能将它用于浏览网页,文档,播放切换音乐等。另外,比较有趣的是插件 Ethereal,它能让你在 Photoshop 中使用 leapmotion,由此在空中作画。


以上功能看似酷炫,但并不实用,不要妄想把它当作可以提高效率的生产工具

  • 开发游戏、应用

在官网的 appstore 上架的应用数量非常少,不到 300 个。如果你是会编程的 geek 玩家,那福利就来了。若不满足现有内容,可以自己动手,丰衣足食。


官方文档(

Leapmotion 能使用各种语言和平台进行开发。如网站开发常用的 Js,游戏开发中常用的游戏引擎 Unity 、Unreal。当然,最重要的是还支持两种创意编程工具, Processing 和 Openframeworks.

他们两者都有相关的 leapmotion 插件,使用方法都是相通的。下面会基于 Openframeworks 并结合插件 ofxLeapmotion2 进行展开。

开发准备工作

下载插件 ofxLeapmotion2

首先可以到如下地址下载插件,作者是 genekogan。

()


下载后将整个文件夹放到 OF 的 addon 目录中,并把末尾的“-master ”去掉。

接着把 Leapmotion 通过数据线连接到电脑,并且平放到屏幕前方。


这时打开并运行插件中提供的 example,就能直接使用,从中可以预览识别效果。


现在,你能看到 leapmotion 在 OF 中跑起来是什么样子的

理解插件 ofxLeapmotion2

人们之所以会写各种各样的插件(addons),最终目的都是为了偷懒。把相对底层的代码封装起来,以此简化流程,提高效率。

ofxLeapmotion2 是一个专门在 OF 中使用的插件,使用它我们就无需阅读官方的 API 文档,快速上手开发。

下载任何一个插件,第一步就是要读懂它。不清除是作者们大多比较懒,还是认为例子已经足够简单,无需解释。其实大部分下载下来的范例都不会很细致地交代每句代码的含义。这时就需要你自行解读。

这里提供一些读代码的思路,不仅限于理解插件。

  • 寻根溯源

一般顺序最好先从头文件 ofApp.h 开始,看看声明中用到了哪些插件中特有的数据类型。在这里就是 ofxLeapMotion 和 ofxLeapMotionSimpleHand。根据命名,以及后面的用法,就能大致猜出功能

  • 区分功能块

既然有这些数据类型,自然会声明并使用相应的对象。上一步相当于找到了几个主干,往下看就要到源文件 ofApp.cpp 中观察它们是怎么延伸出枝叶的。

对象的许多功能和 OF 程序的主结构是很像的,互相呼应。有的用于初始化,有的用于更新,有的用于获取数据,处理数据。由于每个部分是由若干行代码组成的,数量或多或少。因而更更整体地看待它,很多细节无需彻底搞懂,只要确定对应的功能即可。可以把代码当作积木,头脑中要有体块意识

  • 分块理解,逐个击破

若不能完全理解,可以先从一个对象,一个主干开始往下看。逐步梳理。当不确定函数的作用时,可以多使用注释符做排除。对于变量和参数则可以多使用 cout,从控制台上观察数据。等到理解了局部,再转战到其他部分,问题也就迎刃而解

  • 从结果推测功能

在插件提供的例子中,可以看到手掌,但仔细观察会发现。其实并不存在一个绘制手掌的函数。所有的手指关节,都是由最基本的球体和直线组成的,用到了我们熟知的 ofDrawSphere 和 ofDrawLine 函数。由此可以推断,这些函数的参数部分填写的就是关节的顶点。我们之后也能调用它,来做各种各样的东西

ofxLeapmotion2 常用函数具体含义

根据上面思路,结合作者的注释。下面选一些关键概念进行说明

1.在 ofApp.h 中可以看到这样一句声明

vector <ofxLeapMotionSimpleHand> simpleHands;

里面就用到了一个很重要的类 ofxLeapMotionSimpleHand。这句代码的作用是声明了一个 vector 对象 simpleHands,它用于储存手掌关节的顶点信息。通过
simpleHands.size(),则可以获取当前识别手掌的数量。

2.update() 函数中的 setMappingX,setMappingY,setMappingZ。作用是将识别到的物理坐标,映射到程序中的空间坐标。前两个参数一般不用调整。若想修改手掌的显示比例可以修改后两个参数

3.for 循环中的 f 从 0 到 4,会影响 simpleHands[i].fingers[ fingerTypes[f]] 获取的坐标,分别对应拇指,食指,中指,无名指,小指。而每根手指,分别有四个节点。从顶部的指尖到根部,在程序中分别命名为 tip,dip,pip,mcp


根据相应的索引,我们就能在 simpleHands 对象中,调取所需的顶点坐标。假如我们希望在所有手掌的食指指尖上,绘制一个正方体。就可以在 draw 中加入如下代码。


“fingerTypes[1]”代表食指,“.tip” 代表指尖关节。


值得注意的是,它必须要写在上面的 for 循环中。而不能将下面的代码直接写在 draw 之内,否则会报错。

ofDrawBox(simpleHands[0].fingers[ fingerTypes[1] ].tip,100)

这是因为当手掌不在设备上方时,simpleHands 会为“空”,也就是数量为 0。所以通过任何下标来调取数据都会出错。除非施加一个判断条件

  if(simpleHands.size() > 0){       ofSetColor(255);       ofDrawBox(simpleHands[0].fingers[ fingerTypes[1] ].tip,100);    }

这样就会使得识别的第一个手掌的食指位置,出现一个正方体


常规计算

要用 Leapmotion 开发交互程序,仅仅知道节点坐标是不够的。我们还要对它进行各种运算

  • 记录运动轨迹

可通过创建 vector对象来记录轨迹。结合 push_back 就能储存系列点坐标。若是希望记录多个手指及其节点的运动轨迹,可考虑使用二维 vector,结构更清晰

  • 计算运动速度

与二维情况下的计算方式是一致的,通过前后两帧坐标的位置差,就可得出速度。但需要将储存上一帧点坐标的变量赋值,写在 draw 函数的末尾。lastPos 代表上一坐标,newPos 代表当前坐标,speed 为该点运行速度

... speed = newPos - lastPos; lastPos = newPos; ...
  • 计算手指的伸出距离

在某些应用中,我们需要了解每根手指离掌心的距离。这时可以创建一个 vector对象来进行储存。由于手指的数量是会随着识别状态而改变的,所以一开始可以不用在 setup 中,固定 vector对象的容量大小。可以考虑把 push_back 写在  update 或 draw 中。并且把 clear 函数提前,这样数据的容量就会实时变化。

数据更新部分:


绘图部分:

ofSetColor(255); for(int i = 0;i < handDist.size();i++){   ofDrawRectangle(100 * i - 200, 0, 50, handDist[i]); }

运行效果:


如果你想开发一个猜拳游戏,那么只要比较各个手指之间的距离,就能知道是剪刀,还是石头布了

  • 拾取,触碰判断

原理相当的简单,通过计算两点间的距离做判断。由于理论上手指节点的坐标是不可能完全重叠的,所以需要设定一个距离阀值。当两点间距离小于此值,则表示为拾取或触碰。假如要识别击掌动作,就可以计算两掌的 handPos 距离。

OF 中的计算距离可使用函数 distance.

dist = A.distance(B); // A,B 表示点坐标

Leapmotion 练习

结合上面的计算技巧,就足以满足大多数的创作需求。下面是使用结合 leapmotion 做的一些实验,文末会附带下载链接

练习01: 3D 画板


思路:

  • 创建一个名为 brushPos 的 vector

    对象,用于储存点坐标
  • 设定一个名为 brushDist 的 float 变量,用于设置录入的最小间距。当前后两点坐标小于 brushDist,才在 brushPos 中 push_back 顶点。以此保证轨迹均匀

  • 绘制部分,使用 sin 函数控制球体的大小变化

  • 可通过方向键控制球体大小,并切换光照模式

绘图部分代码:

ofBeginShape(); for(int i = 0;i < brushPos.size();i++){  ofSetColor(ofColor::fromHsb(i * 30 % 255,255,255));  ofCurveVertex(brushPos.size[i]);  ofSetSphereResolution(12);  ofFill();  ofDrawSphere(brushPos.size[i],sphereR * sin(ofGetFrameNum()/10.0 + i * 0.2)); } ofNoFill(); ofEndShape();

练习02: 3D 钢琴


演示视频:

https://v.qq.com/txp/iframe/player.html?vid=x0343q4b2j7&width=500&height=375&auto=0

思路:

练习03: 宇宙粒子


演示视频:

https://v.qq.com/txp/iframe/player.html?vid=u0343xamyhy&width=500&height=375&auto=0

思路:

  • 这里使用了常规的粒子系统

  • 食指指尖有一个朝向判断,通过对指尖的第一关节(tip)和第二关节(dip)的 y 坐标进行相减。就能根据正负值来了解指尖是朝上或是朝下

  • 指尖朝上时,释放粒子,开始绘制。朝下时,停止绘制

练习04: 传送门


近期的《 Doctor Strange 》,视觉方面非常出彩。参考里面传送门,尝试用 leapmotion 实现了一个简单的交互程序。用食指来画传送门。

演示视频:

https://v.qq.com/txp/iframe/player.html?vid=s0343hbcbry&width=500&height=375&auto=0

思路:

  • 为了让轨迹更靠近圆形。所以对坐标进行了约束,手指只能影响关键点的角度

总结

有关 leapmotion 的介绍就到此结束了。如果你正在学习创意编程。个人非常推荐这一工具。它能突破二维屏幕的限制,在空间作画。有了它,即使不购买昂贵的VR硬件。也能直观地体验在虚拟空间中创作的快感。所以若想 cosplay 一下造物主,不妨考虑入手一个


下载链接

以上实例的下载地址:

若过期可点击左下方的阅读原文


您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存