2012-11-28 134 views
2

我想缩放骨架以匹配另一个骨架的大小。 我algoritm请执行以下操作:Kinect骨架缩放奇怪的行为

  • 寻找原点骨架的两个关节,并使用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

我有我自己的骨架在我身上,还有我的骨架sc对另一个人的大小,但手和脚仍然疯狂。 (但代码看起来不错)

任何建议?

+1

刚刚意识到这个年龄......非常迟到了!我认为你的问题源于试图在运行中缩放骨架,同时仍然使用它来计算原始距离。创建一个可以在最后返回的第三个缩放骨骼。不要修改循环中的原始关节位置,因为您需要它们保持正确的距离计算。 – zeFrenchy

回答

1

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

我虽然验证什么,是你的

if (distanciaOrigem > 0 && distanciaDestino > 0) 

如果distanciaOrigem非常接近0,但即使只是epsilon0了,它会不会被if拾起,然后

fator = (distanciaDestino/distanciaOrigem); 

会造成一个非常大的数字!

+0

感谢您的回答。看起来不错,稍后会尝试并给你反馈。 – Ewerton

+0

我是一个坏英语巴西人,对不起,什么是epsilon,一些分数? – Ewerton

+0

@Ewerton epsilon可以用来表示一个非常小的数字 - 请参阅此线程http://stackoverflow.com/questions/2411392/double-epsilon-for-equality-greater-than-less-than-less-than-or -equal-to-gre – emartel

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倍)。

我希望它有帮助!