使用Leap Motion SDK V2检测拳头

6 javascript math leap-motion

我想检查Leap Motion Frame中的Hand当前是否是拳头.

通常建议的方法是hand.grabStrength使用值1 来查找.问题是,即使使用"爪状"手,或者手指非常轻微卷曲的任何其他值,该值也会跳至1.

另一种方法是检查每个手指是否是extended.但是这有一个类似的问题,如果手指完全笔直,手指只算延长.因此,即使我检查所有手指没有延长,也会出现与上述相同的问题(爪状手被识别为抓住).

结合这两种方法也无法解决问题,因为它们都遇到同样的问题并不奇怪.

现在,我们确实拥有每个手指的所有骨骼,包括位置和一切.但我不知道从哪里开始用数学来检测手指是否卷曲.

基本上我现在有这个设置:

var controller = Leap.loop(function(frame){
   if(frame.hands.length>0){
       //we only look at the first available hand
       var hand = frame.hands[0];
       //we get the index finger only, but later on we should look at all 5 fingers.
       var index = hands.fingers[1];
       //after that we get the positions of the joints between the bones in a hand
       //the position of the metacarpal bone (i.e. the base of your hand)
       var carp = index.carpPosition;
       //the position of the joint on the knuckle of your hand
       var mcp = index.mcpPosition;
       //the position of the following joint, between the proximal and the intermediate bones
       var pip = index.pipPosition;
       //the position of the distal bone (the very tip of your finger)
       var dip = index.dipPosition;

       //and now we need the angle between each of those positions, which is where i'm stuck
   }
});
Run Code Online (Sandbox Code Playgroud)

那么,我如何得到两个位置之间的角度(鲤鱼到mcp,mcp到pip,pip到dip)?有任何想法吗?

小智 3

好吧,我想我找到了一种检测实际拳头而不是爪子的工作方法。

首先,我们需要每个骨骼的距离向量,而不是关节的位置。

然后我们计算掌骨和近端骨之间的点积,以及近端骨和中间骨之间的点积。我们可以忽略远端骨骼,它不会对结果产生太大影响。

我们将所有计算出的点积相加(总共 10 个)并计算平均值(除以 10)。这将为我们提供一个介于 0 和 1 之间的值。拳头低于 0.5,而高于该值的所有内容基本上都不是拳头。

此外,您可能还想检查手上伸出的手指数量,并检查它是否为 0。这将确保“竖起大拇指”和类似的 1 位数姿势不会被识别为拳头。

这是我的实现:

const minValue = 0.5;

var controller = Leap.loop(function(frame){
   if(frame.hands.length>0)
   {
      var hand = frame.hands[0];
      var isFist = checkFist(hand);
   }
});

function getExtendedFingers(hand){
   var f = 0;
   for(var i=0;i<hand.fingers.length;i++){
      if(hand.fingers[i].extended){
         f++;
      }
   }
   return f;
}

function checkFist(hand){
   var sum = 0;
   for(var i=0;i<hand.fingers.length;i++){
      var finger = hand.fingers[i];
      var meta = finger.bones[0].direction();
      var proxi = finger.bones[1].direction();
      var inter = finger.bones[2].direction();
      var dMetaProxi = Leap.vec3.dot(meta,proxi);
      var dProxiInter = Leap.vec3.dot(proxi,inter);
      sum += dMetaProxi;
      sum += dProxiInter
   }
   sum = sum/10;

   if(sum<=minValue && getExtendedFingers(hand)==0){
       return true;
   }else{
       return false;
   }
}
Run Code Online (Sandbox Code Playgroud)

虽然这可以正常工作,但我怀疑这是检测拳头的正确且最佳的方法。所以,如果您知道更好的方法,请发布。


解决方案非常完美,您能否解释一下为什么除以 10 以及为什么 minValue 是 0.5?谢谢!

嗯,说实话,效果不太好。我很快就会开始从事一个小项目,其目标是通过 Leap Motion 改进拳头检测。

关于您的问题,我们将总和除以 10,因为我们有 5 个手指,每个手指有 2 个骨关节。我们需要所有这些计算总和的平均值,因为并非所有手指都会以相同的方式倾斜。因此,我们需要一个将所有这些值包含在一个值中的值:平均值。鉴于我们总共有 10 次计算(每个手指 2 次,5 根手指),我们将这些计算的总和除以就可以了。我们将得到一个介于 0 和 1 之间的值。

关于 minValue:尝试与错误。在我的一个项目中,我使用了 0.6 的值。这是这种方法的另一个问题:理想情况下,平手的值应接近 0,而拳头的值应为 1。