# 骨骼追踪模型概述

2.0 版本的 LeapMotion API 引入了一个全新的骨骼追踪模型来提供更多的手部和手指信息，同时还改善了整体的追踪数据。

通过对人手的建模，LeapMotion 可以更好地在不够清晰的环境中预测手指和手部的位置。一只手始终可以显示五根手指，两只手在交叉的过程中也能够被继续被追踪到。当然，控制器依然需要能够检测到一个手指或者手部才可能获得精确的位置，设计你应用程序的交互行为时要时刻注意这点。避免复杂的手势或者非常精细的动作，尤其是那些要求不伸开手指的动作。

![在诊断可视化工具中探索全新手模型的行为](https://3708604558-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LmAGnx6ThZjQnyNN4Sg%2F-LmAGpETZPiOMDijInN-%2F-LmAGyq0Nt7v57UzxvtE%2FVisualizer_Hand_Model.png?generation=1565704849636690\&alt=media)

API 的变化可能并不如你所期望的那么大，之前的 API 无论你是否使用新特性都很相似。

增加的内容有：

* 返回基于内部手模型和观测数据的的可信度评级(Confidence Rating)
* 左右手的判定
* 手指的判定
* 返回每一根手指骨头的位置和指向
* 返回手的抓取特征，用于表示用户是在捏还是在抓
* 返回一只手的五根手指
* 返回一只手是伸开与否

也许对于现有程序最为明显的变化是提升了手和手指的连续性。这个将使得支持 LeapMotion 应用的 App 可用性大大提高然而，如果你依赖使用手指弯曲时的消失或触摸特性，那么你需要做一些修改。比如，如果你要统计可见的手指的数目或者区分手指的向外伸展及向内收缩，你需要使用新的 ~~`Pointalbe.isExtended`~~ 属性来得知手指是否伸出。另一方面，如果你依赖于手指互相接触时的消失，你则需要设置指尖的最小的距离阈值，因为手指不会再小时了。

**注意**：`Finger.joint_position()` (在 `Bone` 类中支持)可能会在以后的 SDK 版本中被移除。

## 全新的 Tracking API

新的追踪模型中 API 的变化如下：

### Hand 类

* Hand.confidence
* Hand.is\_left
* Hand.is\_right
* Hand.grab\_strength
* Hand.pinch\_strength
* Hand.palm\_width
* Hand.basis
* Hand.arm

`Hand.confidence` 是一个 0 到 1 之间的值，表明了内建手部模型和检测数据的匹配程度。数值较低时表示有明显差异；手指位置甚至手部判定都很有可能不正确。可信度这个值对于你程序的价值是随着场景二变化的。手势和动作即使美欧搞的可信度时也能够有效。另一方面，你应该确保，执行由某些手势或者手部属性所触发的程序之前，可信度的值足够高。

`Hand.is_left`以及`is_right`的含义是正如它们名字的表示的那样。它们成对出现而且总是有其中一个是`true`。然而 LeapMotion 控制器需要检测到足够的手部信息来获得一个准确的定义。比如，如果你把握紧的拳头放到控制器的视野内，软件可能会出现计算错误。如果软件意识到它的对手的判断出现了错误，则当前这只手会被一个具有新的`id`（以及正确的手指识别）的 Hand 对象所替代。

`Hand.grab_strength`和`pinch_strength`属性值为 0 到 1 之间。表明了你的手是否是两指间的pinch还是全部手指的 grab 姿势。强度(strength)值接近 0 时说明手是平的，全部手指伸开。对于 grab 姿势而言，强度值增加到 1 说明手已经握成了拳头。而对于 pinch 而言，强度值的增加说明你在把大拇指和某个其他指捏在一起。当强度值超过一定阈值时，你可以使用这些强度属性在你的应用中触发 grabs 或者选择的行为。

`Hand.palm_width`给出了一个对于手处于平放状态时的手掌宽度的估计。`Hand.basis`是一个方便的用于获取定义手的朝向的标准正交基向量。这三个向量在基矩阵中分贝为手掌法线、手方向、以及它们的向量叉乘。

`Hand.arm`提供了有关与手连接的手臂信息。这个属性在整个手臂没有进入检测范围内时，是根据人体解剖学估算出来的。

### PointalbeList 和 FingerList 类

* PointableList.extended()
* FingerList.extended()
* FingerList.finger\_type()

这个扩展功能返回了被考虑扩展成员的当前序列。这包含了哪些或多或少有指向性的手指及任何的工具。在 `PointableList` 对象中，任何工具都在一个列表中。`finger_type()`函数返回了一个包含所有某类手指的列表（比如所有小拇指、所有食指等）。

### Pointable 和 Finger 类

* Finger.type
* Finger.bone()
* ~~Pointable.isExtended~~

`Finger.type`函数判定手指的名称。返回一个列举数字\[0, ..., 4]，分别表示大拇指、食指、中指、无名指以及小拇指。 `Finger.type`函数则返回的 Bone 对象是手指上的某一根骨头。每一个手指，包括拇指，都有四块骨头（即便拇指在解剖学上只有三块骨头）。

![](https://github.com/changkun/leapmotion_v2_cn/tree/7bc30e3330cee5b47b2724bd9233dd3adf7456d3/js/images/Finger_Bone.png)

注意，`Pointable.direction`平行于指根和指尖的连线之间的连线。它不一定平行于手指这个手指的最后一根骨头（Distal Phalanx）。手指越弯曲，两个方向的差异就越大。这个计算 `Pointable.direction`的方法和早期版本的 API 保持一致，但是如果你的的项目是从手沿`Pointable.direction`方向发射一条射线，会有点诡异。

### Bone 类

Bone 类描述了手指上的每一个骨头的位置和朝向，包括连接了手指和手掌根部的 Metacrapal。

* Bone.basis
* Bone.direction
* Bone.invalid
* Bone.is\_valid
* Bone.length
* Bone.prev\_joint
* Bone.next\_joint
* Bone.type
* Bone.width

### Arm 类

Arm 类和 Bone 类相似，给出了手前臂的物理位置以及基向量，具体描述了手臂在空间中的指向。

* Arm.basis
* Arm.direction
* Arm.elbow\_position
* Arm.invalid
* Arm.is\_valid
* Arm.width
* Arm.wrist\_position

### JSON 数据变化

新的追踪模型可以通过 LeapMotion WebSocket 界面来反应追踪。和本地 API相比，你可能注意到了最大的不同就在于现在的手始终有五根手指了。

使用 `v6.json` 端点(ws\://127.0.0.1:6437/v6.json)可以访问新的 API 特性。

一帧中手的数组的每只手都有以下属性：

* `armWidth` ——手前臂的平均宽度
* `confidence` ——骨骼模型和观测数据的吻合度
* `elbow` ——胳膊肘的位置
* `grabStrength` —— 0 到 1 之间的一个值
* `pinchStrength` —— 0 到 1 之间的一个值
* `type` ——表明一个手是左手还是右手
* `wrist` ——手腕的位置

一帧中的可指向物数组中的每一个手指都有以下属性：

* `type` ——表示手指名称的整数
* `bases` ——每个骨头的基向量，索引顺序从手腕到指尖
* `btipPosition` —— Distal Phalanx 的最远端位置（指尖？），是一个包含三个浮点数的数组。
* `carpPosition` —— Metacarpal 基点的位置，得到的是一个包含三个浮点数的数组。
* `dipPosition` —— Distal Phalanx 的基点的位置，得到一个包含三个浮点数的数组。
* `pipPosition` ——包含三个浮点数的位置向量
* `mcpPosition` ——包含三个浮点数的位置向量
* `extended` ——某根手指指向与否的布尔值。
