SharpNow Vidoo SDK  2.02
微动开发指南

定位

当手部处于设备检测范围内,微动可以实时对物体进行检测,并以帧为单位更新定位信息。

手指

微动可以在三维空间中对手指进行定位。在 Finger 结构体中,包含以下定位信息:

手掌

微动可以在三维空间中识别手掌姿态与位置。在 Hand 结构体中,包含以下定位信息:

骨架识别

微动可以对手部关节点进行定位,并计算手部骨架姿态。在 Finger 结构体中包含以下骨架信息:

其中 joint0 至 joint3 可由手掌的位姿与骨架的关节角度使用运动学(Kinematics)计算而得,详细计算方法可见SDK提供的源代码。

skelenton.png
骨架示意图
注解
拇指的模型相比其他手指缺少第一指关节,joint0与joint1的位置重合。

跟踪

跟踪ID

手指的跟踪状态由 track_id 进行标识,若 track_id 保持不变,则代表手指的角色未发生改变。 若在连续的帧数据中,一直存在某手指(或手掌)具有不变的 track_id ,则表示该手指目标持续出现于视野中,并被持续跟踪中。

焦点

在很多应用中,我们只需使用一个目标的位置信息控制屏幕光标,或游戏角色移动等。微动中提供了焦点的跟踪机制,解决这类需求。 当微动检测到手指或手掌目标,会对其中的一个进行持续跟踪,并将其设定为焦点目标。当该目标未离开视野范围,其将持续具有焦点身份。 使用申请标识 finger_focused 与 hand_focused 可获得焦点手指与手掌。
以下程序展示了如何使用焦点手指控制屏幕光标位置:

{
const Frame* frame = GetFrameInfo();
const Finger* finger = GetFinger(frame->finger_focused, 0);
if (frame->updated && finger)
{
SetCursorPos(
int(finger->cursor.x * ::GetSystemMetrics(SM_CXSCREEN)),
int(finger->cursor.y * ::GetSystemMetrics(SM_CYSCREEN)));
}
}
注解
获取手指焦点与手掌焦点时,若返回空指针则表示目前不存在焦点目标。请使用前先进行检测,以保证目标存在。

手势

微动可以对您的手部姿态加以辨识,并使用检测结果在应用程序中进行交互控制。有两类手势可以被识别, 一类为静态手势,即设备通过对您手部形态的分析,确定您正在使用的手势;另一类为动态手势, 即记录您连续的手部动作,确定您的操作意图。

静态手势

左右手判定

在具有一定判定信息时,设备可以确认您正在使用哪只手操控设备。通过查询 Hand 结构体中的 side 成员, 可获取手掌的类型。如果设备没有足够线索分辨手掌,则返回“无法确认(HS_Unknown)”。

手型识别

微动可以通过手部形状判断当前手型。下图列举了可加以辨认的15种常用手势姿态:

gesture.png
15种静态手势

通过查询 Hand 结构体中的 gesture 成员,可获取手势类型。若设备没有足够线索分辨手势姿态,则返回“无法确认(HG_Unknown)”。
以下代码检测焦点手部的手势,并在其静止一段时间后(参见下一章节:动态手势),启动相应应用程序:

const Frame* frame = GetFrameInfo();
const Hand* hand = GetHand(frame->hand_focused);
if (hand && hand->gesture_counter == 25)
{
switch (hand->gesture)
{
case HG_Phone:
// 打开语音聊天软件 ...
break;
case HG_Fork:
// 打开浏览器软件 ...
break;
}
}

动态手势

微动可以通过记录手部一段时间的动作,辨别动态手势。目前支持的手势包括:

悬停

stop.png
悬停手势

当微动检测到手指目标相对静止(或以极慢的速度运动)时,结构体 Finger 的 stop 成员会从1开始逐渐累加。 您可以给定一目标值,当 stop 计数器超过这个数值时,确认完成一次“悬停确认”操作。此外,计数器的数值还可用于进度条的绘制。
以下代码为使用悬停确认的常规流程:

const Frame* frame = GetFrameInfo();
const Finger* finger = GetFinger(frame->finger_focused);
if (finger && finger->stop > 0)
{
if (finger->stop <= 50)
{
std::cout << "确认已完成 " << finger->stop * 2 << "%" << std::endl;
}
if (finger->stop == 50)
{
// 完成操作 ...
}
}

指戳

poke.png
指戳手势

当用户的手指在短时间内向前戳动一段距离,微动会检测到这个动作,在相应 Finger 结构体中将 poke 成员变量置为 true
以下代码为使用指戳手势的常规流程:

const Frame* frame = GetFrameInfo();
const Finger* finger = GetFinger(frame->finger_focused);
if (finger && finger->poke)
{
Vector3 poke_position = finger->position;
// 进行指戳操作
}

敲击

tap.png
敲击手势

当用户的手指在短时间内,发生短距离的向下移动然后抬起,则认为该手指进行了一次敲击动作。 查询 Finger 结构体中的 tap 成员,可以得知手指是否进行了敲击动作。敲击动作的一种常见应用为下图的射击动作:

tap-shoot.png
敲击-射击手势

以下的代码检测焦点手指的敲击手势:

const Frame* frame = GetFrameInfo();
const Finger* finger = GetFinger(frame->finger_focused);
if (finger && finger->tap)
{
// 进行敲击操作
}

划动

slide.png
划动手势

当用户的手指在短时间内上下左右划动一段距离,微动会检测到这个动作,在相应 Finger 结构体中将 slide 成员变量置为 true,并将划动方向存入 slide_dir
以下代码为使用划动手势的常规流程:

const Frame* frame = GetFrameInfo();
const Finger* finger = GetFinger(frame->finger_focused);
if (finger && finger->slide)
{
Vector2 slide_dir = finger->slide_dir;
// 进行指戳操作
}

绕圈

circle.png
绕圈手势

当用户的手指在短时间以空间某点为中心,在竖直平面上绕圈,微动会检测到这个动作,在相应 Finger 结构体中将 circle_dir 成员变量置为绕圈方向,并将绕动中心存入 circle_center
以下代码为使用绕圈手势的常规流程:

const Frame* frame = GetFrameInfo();
const Finger* finger = GetFinger(frame->finger_focused);
if (finger && finger->circle_dir != 0)
{
Vector3 circle_center = finger->circle_center;
// 进行指戳操作
}
注解
手势动作只针对两只手的焦点手指进行检测。

遮盖

blindfold.png
遮盖手势

使用手部遮盖设备视野(无需接触顶层镜片),即开始遮盖手势。该手势通过计数器的方式展现, 当保持遮盖姿势, Frame 结构体中的 blindfold 遮盖计数器会持续累加。
以下代码为使用遮盖动作完成一次确认:

const Frame* frame = GetFrameInfo();
if (frame->blindfold > 0)
{
if (frame->blindfold <= 25)
{
std::cout << "遮盖确认 " << finger->stop * 4 << "%" << std::endl;
}
if (finger->blindfold == 25)
{
// 完成操作 ...
}
}


上一章: 接口一览
下一章: VR支持