Kinect骨架缩放奇怪的行为

时间:2012-11-28 01:32:04

标签: scale kinect scaling kinect-sdk

我正在尝试缩放骨架以匹配另一个骨架的大小。 我的算法做了以下几点:

  • 使用phytagorean teorem找到原始骨架和命运骨架的两个关节之间的距离
  • 将这两个距离分开以找到一个乘法因子。
  • 用这个因子乘以每个关节。

这是我的实际代码:

public static Skeleton ScaleToMatch(this Skeleton skToBeScaled, Skeleton skDestiny)
    {
        Joint newJoint = new Joint();

        double distanciaOrigem = 0;
        double distanciaDestino = 0;
        double fator = 1;
        SkeletonPoint pos = new SkeletonPoint();

        foreach (BoneOrientation bo in skToBeScaled.BoneOrientations)
        {
            distanciaOrigem = FisioKinectCalcs.Distance3DBetweenJoint(skToBeScaled.Joints[bo.StartJoint], skToBeScaled.Joints[bo.EndJoint]);
            distanciaDestino = FisioKinectCalcs.Distance3DBetweenJoint(skDestiny.Joints[bo.StartJoint], skDestiny.Joints[bo.EndJoint]);

            if (distanciaOrigem > 0 && distanciaDestino > 0)
            {
                fator = (distanciaDestino / distanciaOrigem);

                newJoint = skToBeScaled.Joints[bo.EndJoint]; // escaling only the end joint as the BoneOrientatios starts from HipCenter, i am scaling from center to edges.

                // applying the new values to the joint
                pos = new SkeletonPoint()
                {
                    X = (float)(newJoint.Position.X * fator),
                    Y = (float)(newJoint.Position.Y * fator),
                    Z = (float)(newJoint.Position.Z * fator)
                };

                newJoint.Position = pos;
                skToBeScaled.Joints[bo.EndJoint] = newJoint;
            }
        }

        return skToBeScaled;
    }

除了手脚之外,每一件似乎都能正常工作

看看这个图片

enter image description here enter image description here

我有自己的骨架,我的骨架缩小到另一个人的大小,但手脚仍然疯狂。 (但代码看起来正确)

有什么建议吗?

2 个答案:

答案 0 :(得分:1)

没有运行代码很难说,但它有点“看起来不错”。

我会验证的是你的

if (distanciaOrigem > 0 && distanciaDestino > 0)

如果distanciaOrigem非常接近0,但距离epsilon只有0,则if将无法接听fator = (distanciaDestino / distanciaOrigem); ,然后

{{1}}

会产生非常大的数字!

答案 1 :(得分:1)

我建议平滑因素,使其通常符合适当的比例。试试这段代码:

    private static Dictionary<JointType, double> jointFactors = null;
    static CalibrationUtils()
    {
        InitJointFactors();
    }
    public static class EnumUtil
    {
        public static IEnumerable<T> GetValues<T>()
        {
            return Enum.GetValues(typeof(T)).Cast<T>();
        }
    }
    private static void InitJointFactors()
    {
        var jointTypes = EnumUtil.GetValues<JointType>();
        jointFactors = new Dictionary<JointType, double>();
        foreach(JointType type in jointTypes)
        {
            jointFactors.Add(type, 0);
        }
    }
    private static double SmoothenFactor(JointType jointType, double factor, int weight)
    {
        double currentValue = jointFactors[jointType];
        double newValue = 0;
        if(currentValue != 0)
            newValue = (weight * currentValue + factor) / (weight + 1);
        else
            newValue = factor;
        jointFactors[jointType] = newValue;
        return newValue;
    }

当涉及到因子使用时,首先使用SmoothenFactor方法:

    public static Skeleton ScaleToMatch(this Skeleton skToBeScaled, Skeleton skDestiny, double additionalFactor = 1)
    {
        Joint newJoint = new Joint();

        double distanceToScale = 0;
        double distanceDestiny = 0;
        double factor = 1;
        int weight = 500;
        SkeletonPoint pos = new SkeletonPoint();
        Skeleton newSkeleton = null;
        KinectHelper.CopySkeleton(skToBeScaled, ref newSkeleton);
        SkeletonPoint hipCenterPosition = newSkeleton.Joints[JointType.HipCenter].Position;
        foreach(BoneOrientation bo in skToBeScaled.BoneOrientations)
        {
            distanceToScale = Distance3DBetweenJoints(skToBeScaled.Joints[bo.StartJoint], skToBeScaled.Joints[bo.EndJoint]);
            distanceDestiny = Distance3DBetweenJoints(skDestiny.Joints[bo.StartJoint], skDestiny.Joints[bo.EndJoint]);

            if(distanceToScale > 0 && distanceDestiny > 0)
            {

                factor = (distanceDestiny / distanceToScale) * additionalFactor;


                newJoint = skToBeScaled.Joints[bo.EndJoint]; // escaling only the end joint as the BoneOrientatios starts from HipCenter, i am scaling from center to edges.

                factor = SmoothenFactor(newJoint.JointType, factor, weight);

                pos = new SkeletonPoint()
                {
                    X = (float)((newJoint.Position.X - hipCenterPosition.X) * factor + hipCenterPosition.X),
                    Y = (float)((newJoint.Position.Y - hipCenterPosition.Y) * factor + hipCenterPosition.Y),
                    Z = (float)((newJoint.Position.Z - hipCenterPosition.Z) * factor + hipCenterPosition.Z)
                };
                newJoint.Position = pos;
                newSkeleton.Joints[bo.EndJoint] = newJoint;
            }
        }
        return newSkeleton;
    }

我也修改了你的ScaleToMatch方法。需要移动关于HipCenter位置的关节。此外,新位置也会保存到新的Skeleton实例中,因此不会在进一步的矢量计算中使用它们。

尝试使用weight,但由于我们的骨骼长度不变,您可以使用100或更大的数字,以确保错误的Kinect读数不会影响正确的比例。

以下是有关如何缩放HandRight联合职位的示例:

enter image description here

weight已设为500。结果factor应该在2左右(因为基础骨架特意缩减了2倍)。

我希望它有所帮助!