我正在尝试缩放骨架以匹配另一个骨架的大小。 我的算法做了以下几点:
这是我的实际代码:
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;
}
除了手脚之外,每一件似乎都能正常工作
看看这个图片
我有自己的骨架,我的骨架缩小到另一个人的大小,但手脚仍然疯狂。 (但代码看起来正确)
有什么建议吗?
答案 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
联合职位的示例:
weight
已设为500
。结果factor
应该在2
左右(因为基础骨架特意缩减了2倍)。
我希望它有所帮助!