2012年11月12日星期一

使用Kinect测量身高

使用Kinect测量身高

    使用Kinect测量身高的方法其实有很多种:

    第一种方式是使用Kinect的视场角以及结合一些三角形几何运算,就可以大致测量出物体的高度,这一点在之前介绍深度影像处理的时候有提到。

    第二种方式是使用Kinect骨骼追踪提供的20个关节点的相关坐标,在根据一定的算法测量出人体的身高。在Channel9上面的这个例子的一个分享,在这里拿过来和大家分享一下。在这里,根据臂展和身高有相似的关系,我对这个例子做了一点扩展,计算臂展来粗略计算身高,用臂展计算身高其实有个好处就是既可以使用正常模式(Normal model,20个关节点),可以使用坐姿模式(Seat model,10 个关节点),这样您坐着就可以测量身高,不过精度不保证哈。这里只是提供这么一个思路。

一. 计算身高的算法

    Kinect获取的骨骼数据包含20个关节点的X,Y,Z坐标信息。您可能会想,为什么不直接使用头部(head)关节点和脚趾(foot)关节点之间的距离来直接计算身高。这样不准确,因为用户可能并没有站直,如果这样算的话,误差比较大。

    另一个问题是,头部关节点给出的是头部中心点的位置,如果使用这个位置,您需要额外增加9至11厘米,但是即使这样,也不能达到百分之一百的准确,如果要更精确一点的话,可能需要使用深度影像值来提取头部的顶部位置。也不需要那么麻烦,现在来看看我们怎样使用骨骼关节点来计算高度信息。

    仔细观察下面的骨骼点,可以看到,身高可以由下面几部分组成(如图中红色部分):

• 头部(Head) –肩膀中心(ShoulderCenter)

• 肩膀中心(ShoulderCenter) – 脊柱中心(Spine)

• 脊柱中心(Spine) – 髋部中心(HipCenter)

• 髋部中心(HipCenter) – 左或右膝关节(KneeLeft or KneeRight)

• 左膝关节KneeLeft(右膝关节KneeRight) – 左踝关节leLeft (右踝关节AnkleRight)

• 左踝关节leLeft (右踝关节AnkleRight)- 左脚FootLeft (右脚FootRight)

KinectMeasureHeightw

使用臂展计算身高,也可以计算图中绿色所示的关节点:

• 左手(HeadLeft) –左手腕(Wrist Left)

• 左手腕(Wrist Left) – 左胳膊肘(Elbow Left)

• 左胳膊肘(Elbow Left) – 左肩膀(Shoulder Left)

• 左肩膀(Shoulder Left)–肩膀中心(Shoulder Center)

• 肩膀中心(Shoulder Center)-右肩膀(Shoulder Right)

• 右肩膀(Shoulder Right)- 右胳膊肘 (Elbow Right)

• 右胳膊肘 (Elbow Right)- 右手腕(Wrist Right)

•右手腕(Wrist Right)- 右手 (Hand Right)

   原理就是这样,下面来编代码实现。

二. 实现

    程序界面很简单,展示20个关节点,然后显示计算结果。有几点需要说明:

    首先,关节点的位置信息是三维的,下面公式用来计算两个关节点的距离

public static double Length(Joint p1, Joint p2){    return Math.Sqrt(        Math.Pow(p1.Position.X - p2.Position.X, 2) +        Math.Pow(p1.Position.Y - p2.Position.Y, 2) +        Math.Pow(p1.Position.Z - p2.Position.Z, 2));}

    上面的代码很直接。第二步,我们应该使用左腿还是右腿还进行测量更加准确呢,我们使用那个追踪的最好的。下面的代码用来计算腿部处于追踪状态的点的数量。如果那个数量多,那么就用那一个。

public static double Length(params Joint[] joints){    double length = 0;    for (int index = 0; index < joints.Length - 1; index++)    {        length += Length(joints[index], joints[index + 1]);    }    return length;}

    使用上面的函数,我们就可以判断是使用左腿还是右腿了。

// Find which leg is tracked more accurately.int legLeftTrackedJoints = NumberOfTrackedJoints(hipLeft, kneeLeft, ankleLeft, footLeft);int legRightTrackedJoints = NumberOfTrackedJoints(hipRight, kneeRight, ankleRight, footRight);double legLength = legLeftTrackedJoints > legRightTrackedJoints ? Length(hipLeft, kneeLeft, ankleLeft, footLeft) : Length(hipRight, kneeRight, ankleRight, footRight);

     然后我们使用扩展方法,来计算骨骼的高度。下面是方法的代码:

public static double Height(this Skeleton skeleton){    const double HEAD_DIVERGENCE = 0.1;    var head = skeleton.Joints[JointType.Head];    var neck = skeleton.Joints[JointType.ShoulderCenter];    var spine = skeleton.Joints[JointType.Spine];    var waist = skeleton.Joints[JointType.HipCenter];    var hipLeft = skeleton.Joints[JointType.HipLeft];    var hipRight = skeleton.Joints[JointType.HipRight];    var kneeLeft = skeleton.Joints[JointType.KneeLeft];    var kneeRight = skeleton.Joints[JointType.KneeRight];    var ankleLeft = skeleton.Joints[JointType.AnkleLeft];    var ankleRight = skeleton.Joints[JointType.AnkleRight];    var footLeft = skeleton.Joints[JointType.FootLeft];    var footRight = skeleton.Joints[JointType.FootRight];    // Find which leg is tracked more accurately.    int legLeftTrackedJoints = NumberOfTrackedJoints(hipLeft, kneeLeft, ankleLeft, footLeft);    int legRightTrackedJoints = NumberOfTrackedJoints(hipRight, kneeRight, ankleRight, footRight);    double legLength = legLeftTrackedJoints > legRightTrackedJoints ? Length(hipLeft, kneeLeft, ankleLeft, footLeft) : Length(hipRight, kneeRight, ankleRight, footRight);    return Length(head, neck, spine, waist) + legLength + HEAD_DIVERGENCE;}

     同样滴,我们使用手,手腕,胳膊肘,肩膀,等9个关节点来计算臂展,并使用臂展来近似计算身高,下面的名为ArmExtendWith的扩展方法即为计算臂展的方法。

public static double ArmExtendWith(this Skeleton skeleton){    var armWidthDeviation = 0.5;    var handRight = skeleton.Joints[JointType.HandRight];    var wristRight = skeleton.Joints[JointType.WristRight];    var elowRight = skeleton.Joints[JointType.ElbowRight];    var shoulderRight = skeleton.Joints[JointType.ShoulderRight];    var shoulderCenter = skeleton.Joints[JointType.ShoulderCenter];    var handleft = skeleton.Joints[JointType.HandLeft];    var wristleft = skeleton.Joints[JointType.WristLeft];    var elowleft = skeleton.Joints[JointType.ElbowLeft];    var shoulderleft = skeleton.Joints[JointType.ShoulderLeft];    // Calculate the left and right arm extends width    double rightArmExtendsWidth = Length(handRight, wristRight, elowRight, shoulderRight, shoulderCenter);    double leftArmExtendsWidth = Length(handleft, wristleft, elowleft, shoulderleft, shoulderCenter);    return rightArmExtendsWidth + leftArmExtendsWidth + armWidthDeviation;}

    最后,再SkeletonFrameReady事件中调用该方法即可。

void Sensor_SkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e){    using (var frame = e.OpenSkeletonFrame())    {        if (frame != null)        {            canvas.Children.Clear();            Skeleton[] skeletons = new Skeleton[frame.SkeletonArrayLength];            frame.CopySkeletonDataTo(skeletons);            var skeleton = skeletons.Where(s => s.TrackingState == SkeletonTrackingState.Tracked).FirstOrDefault();            if (skeleton != null)            {                // Calculate height.                double height = Math.Round(skeleton.Height(), 2);                double armExtendsWidth = Math.Round(skeleton.ArmExtendWith(), 2);                // Draw skeleton joints.                foreach (JointType joint in Enum.GetValues(typeof(JointType)))                {                    DrawJoint(skeleton.Joints[joint].ScaleTo(640, 480));                }                // Display height.                tblHeight.Text = String.Format("Height: {0} m", height);                tblArmExtendWidth.Text = String.Format("ArmWidth: {0} m", armExtendsWidth);            }        }    }}

    现在您可以运行代码查看结果了。

三. 结语

     本文介绍了两种利用Kinect测量身高的方法,一种是之前讲过的,利用Kinect的视场角和物体构成的三角关系,运用几何运算,测量物体身高,第二种是利用Kinect提供的骨骼数据,根据关节点直接的距离,来计算人体的身高。本文着重讲解了利用骨骼关节点之间的距离计算身高的两种方法,一种是Channel9上面分享的利用头部、脊柱、髋关节、膝关节、踝关节等8个关节点的长度来计算身高,还有一种就是使用与臂展相关的,手、手腕、胳膊肘、肩膀等9个关节点信息,叫第一种方法相比,该方法可以使用坐姿模式进行计算。当然,可能精度不是很准确,本文只是提供了一些Kinect在测量身高方面的思路,源代码点击此处下载,希望本文对您有帮助!




TAG: