2012-11-28 127 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倍)。

我希望它有幫助!