Kinect for Unity检测身高方法

Kinect for Unity自身好像并没有附带检测身高的API可以直接使用。
但Kinect可以获得24个骨骼点,这足够让我们自行根据距离写计算出身高代码。

当然也有别的方法,因为可以获得人体轮廓,然后计算地面距离和头顶距离..


Unity的AssetStore里有个的Kinect的unitypackage,
直接搜Kinect就可以 叫"Kinect with MS-SDK"
下载导入这个包后,
其中有一个检测骨骼点并在三维世界里生产的代码 --- "SkeletonOverlayer.cs"

这个代码:
会根据Kinect的高度和角度 自动调整你的MainCamera的位置和角度,
以至于和Kinect在现实中的角度高度一致。

获得Kinect的Camera看到的彩色图像。
根据Kinect检测到的骨骼数据得到各个骨点的距离,
在unity的三维世界相应地产生一个绿球作为骨骼点的示意。
自动生成25个球和N条线连接这些球
再用unity Line Renderer一一根据人的肢体连接起来。
结果就得到了一个附在图像看到的现实世界的人体上的绿球与线做成的人偶。


脚本示图(我把骨骼点也显示在面板,方便大家看到)


Kinect for Unity检测身高方法_第1张图片

然后根据我们的需要,选取骨骼点,可以计算双腿的平均值,这里我只计算了左腿:)

所以,所要计算的骨骼就是Head到Neck到SpineShoulder到SpineMid到SpineBase到KneeLeft到AnkleLeft。
也就分别是数组中的[3],[2 ] [2],[20] [20],[1] [1],[0] [0],[13] [13],[14] 。


具体实现代码:
我们在skeletonoverlayer.cs里新增一个自定义方法HeightCalculation()来计算身高

1.直接计算法:

void HeightCalculation(){
  //************距离计算*************//
  kinectHeight = Vector3.Distance(joints[3].transform.position,joints[2].transform.position) +
      Vector3.Distance(joints[2].transform.position,joints[20].transform.position) +
      Vector3.Distance(joints[20].transform.position,joints[1].transform.position) +
      Vector3.Distance(joints[1].transform.position,joints[0].transform.position) +
      Vector3.Distance(joints[0].transform.position,joints[13].transform.position) +
      Vector3.Distance(joints[13].transform.position,joints[14].transform.position);
      //**********直接计算**********//
      UIHeight.text = kinectHeight.ToString();
}

这个方法虽然能实现,在不断测试中发现了有许多问题:
1、Kinect的距离、高度、角度,也许会对检测也有小许影响。
2、弯腰和伸展动作会对检测到的距离有一定影响
3、由于检测到的头和脚的骨点是中央,得出的身高和小于实际身高
4、稳定性不算高,偶尔还会有丢失骨点情况。


问题1和2:
都是Kinect骨点检测不十分精确的后果,相差可能最大有10CM.

问题3:
我会采用对最后身高进行一个常量的乘法。具体我用Kinect多次测量得到的头骨点(其实就是头的中心),到脚骨点的距离稳定为1.66左右,而我的准确身高是1.76。
所以我在得到Kinect检测到的头骨点和脚骨点的距离上乘以一个常量1.066(=1.76/1.66),
最后得到的当然就是我的准确身高啦。
之后在CSDN某大神的点赞后,我发现某大神的处理是加上了估算头的距离,
也就是7~10cm左右,我认为他写的更好更科学。

2.常量相乘得实际身高:

voidHeightCalculation(){
  if(GameObject.Find("KinectObject"))
  {
  //**********直接计算**********//
  kinectHeight = Vector3.Distance(joints[3].transform.position,joints[2].transform.position) + 
    Vector3.Distance(joints[2].transform.position,joints[20].transform.position) + 
      Vector3.Distance(joints[20].transform.position,joints[1].transform.position)  + 
        Vector3.Distance(joints[1].transform.position,joints[0].transform.position) +
           Vector3.Distance(joints[0].transform.position,joints[13].transform.position) + 
            Vector3.Distance(joints[13].transform.position,joints[14].transform.position);
    UIHeight.text = (kinectHeight * 1.06667F).ToString();
  }
}

问题4:
各种情况让骨骼点不是一直在每一帧都会存在或在一个正常的位置上,这一点作为开发着的我是非常的头痛头痛头痛(太头痛 所以说3次。。)
然后我决定测量自己的每个骨骼点的距离,防止它检测不到然后距离为0的情况,遇到距离为0,我便以我的骨骼距离为标准给玩家补上。
我得到我的由头到脚的骨骼点距离稳定值分别为:
头到脖子:0.12 | 脖子到肩膀中心:0.07 | 肩膀中心到脊髓中心:0.22 | 脊髓中心到脊髓根部:0.3 | 脊髓根部到左膝盖:0.35 | 左膝盖到左脚踝:0.5
事实证明,我的腿很长
。。当然,上面的那些骨点名称我瞎翻译的,大家意会就好。



这里顺便给大家一个彩蛋,Kinect的检测原理是根据红外线反射到的深度,
然后识别到像人一样的肢体的东西就觉得是人,图中人偶便被识别了。由于本人太帅 就不上镜了:)


Kinect for Unity检测身高方法_第2张图片

然后,
为了防止玩家乱动,摆奇怪的姿势(我也是服了,第一次玩Kinect的人总喜欢乱动。。上头就说我做的东西怎么这么不稳定,Kinect是有范围的好吗,真想打断他们腿)

我做了一个多次测量取得平均值的循环~ 让最后身高数据取平均值。

3.平均值计算身高:

voidHeightCalculation(){
  if(GameObject.Find("KinectObject"))
  {
    //**********平均值**************//
    headToNeck.text = Vector3.Distance(joints[3].transform.position,joints[2].transform.position).ToString();
    neckToSpineShoulder.text = Vector3.Distance(joints[2].transform.position,joints[20].transform.position).ToString();
    spineShoulderToSpineMid.text = Vector3.Distance(joints[20].transform.position,joints[1].transform.position).ToString();
    spineMidToSpineBase.text = Vector3.Distance(joints[1].transform.position,joints[0].transform.position).ToString();
    spineBaseToKneeLeft.text = Vector3.Distance(joints[0].transform.position,joints[13].transform.position).ToString();
    kneeLeftToAnkleLeft.text = Vector3.Distance(joints[13].transform.position,joints[14].transform.position).ToString();
    if(i<10)
    {
      if(kinectHeight < 0.6F)
      kinectHeight = 1.7F;
      Height[i] = kinectHeight  * 1.07F;
      UIHeight.text ="第"+ i +"次:"+ Height[i].ToString();
      playerHeight = playerHeight + Height[i];
      i++;
     Debug.Log("次数:"+ i);
      Invoke("HeightCalculation",0.8F);
    }
    else
    {
      playerHeight = playerHeight/10;
      UIHeight.text ="高度:"+ playerHeight.ToString();
      Debug.Log("高度:"+ playerHeight);
    }
  }
}

这里我没加上骨点距离不正常的判断了。。。其实不正常分很多种情况balbala的起码有3种情况,不是几句话就能写完,我就懒得写了,人生哪有那么多时间造轮子,喜欢写代码你们自己写去啊。。。


---------end-----------

你可能感兴趣的:(Kinect for Unity检测身高方法)