使用Leap Motion SDK V2检测拳头

6

我想检查Leap Motion框架中的手是否当前为握拳状态。

通常建议的方法是查找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
   }
});

那么,我如何获得这些位置之间的角度(从carp到mcp,从mcp到pip,从pip到dip)?有什么想法吗?

3个回答

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;
   }
}

虽然这样可以正常工作,但我怀疑这是否是检测拳头的正确和最佳方法。如果您知道更好的方法,请发布出来。
解决方案完美运行,有机会您能解释一下为什么要除以10,以及为什么minValue是0.5吗?谢谢!
老实说,它并不工作得那么好。我很快就会开始一个小型项目,旨在改善使用Leap Motion检测拳头的效果。
关于您的问题,我们将计算结果除以10,因为每个手指有2个骨骼连接点,而有5个手指。我们希望从所有这些计算的总和中获得平均值,因为不是所有的手指都会以同样的方式弯曲。因此,我们想要一个包含所有这些值的值:平均值。由于我们总共有10个计算(每个手指2个,5个手指),因此我们将这些计算的总和除以10。我们将得到一个介于0和1之间的值。
关于minValue:尝试和错误。在我的一个项目中,我使用了0.6的值。这是这种方法的另一个问题:理想情况下,平手应该是接近0的值,而握拳应该是1。

这是否也会通过手指在关节处折断,指向角度相反的方向,以制作拳头(好像完全不受关节范围的限制)? :D。 尴尬 - Zéychin
我想可能是这样,但这个数学对我来说有点太复杂了。 :P - user2655904
我找到了一个好的解决方案,使用每个手指和手掌之间的距离。计算这些距离的总和,并检查是否低于某个特定阈值。 - whoabackoff
@whoabackoff 发布你所做的东西,这对未来的读者可能会有用! - FutureCake

0

我知道这是一个老话题,但如果你们还在的话,答案可能更简单,只需使用sphereRadius();


-1
我发现 "grabStrength" 很好。

他非常明确地表示,grabStrength不是他的要求的好方法。这个问题也相当古老了。如果自2014年以来有什么变化,请具体说明为什么现在可以工作。现在你的答案太简短了,对其他人没有帮助... - Pauloco

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接