我正在构建Kinect SDK WPF应用程序并使用Kinect移动“光标”/手形对象。
我遇到的问题是,由于Kinect的精确度,每秒30帧,光标实际上会有点跳跃(即握住手时,物体在5px空间内移动)。
我打算编写一种算法,它不会简单地将我的“光标”冲刺的X / Y移动到屏幕上的正确位置,但表现得更像是“将手移向这个X / Y坐标“这是一个更平稳的运动。
有人能指出一个别人写的好的,所以我可以避免重新发明轮子。
我知道这可能很常见,但由于我更像是一个业务开发人员,我不确定这个功能的名称如果是一个n00b问题,请提前道歉。
答案 0 :(得分:4)
将您的输入值(跳跃位置)视为具有低频和高频部分的信号。低频表示粗略位置/运动,而高频部分表示较小距离内的快速跳跃。
所以你需要或寻找的是低通滤波器。如果您设法使用正确的参数设置它,那么过滤掉高频部分并留下粗糙(但与Kinect可以获得的准确度)位置。此参数是滤波器的交叉频率。你必须玩一下,你会看到。
时间离散值的实现示例来自here(最初来自wikipedia):
static final float ALPHA = 0.15f;
protected float[] lowPass( float[] input, float[] output ) {
if ( output == null ) return input;
for ( int i=0; i<input.length; i++ ) {
output[i] = output[i] + ALPHA * (input[i] - output[i]);
}
return output;
}
您可以将位置向量的X和Y分量的最后一个值放入此函数中以使其平滑(X为input[0]
,Y为input[1]
和output[0]
output[1]
是上一个函数调用的结果。)
就像我已经说过的那样,你必须找到平滑因子ALPHA
(0≤ALPHA≤1)的良好平衡:
(如果查看公式newout = out + alpha * (in - out)
,您会看到alpha值为0,您只需再次使用旧的out
值,因此值永远不会改变;而值为值1你有newout = out + in - out
这意味着你不要平滑任何东西,但总是采取最新的值)
答案 1 :(得分:4)
当我使用Kinect时,我只是使用了一些简单的数学运算(我认为称为线性回归)来移动到光标当前位置与其目标位置之间某个距离的点。获取光标的位置,获取用户手所在的位置(转换为屏幕坐标),然后将光标移动到这些位置之间的某个点。
float currentX = ..., currentY = ..., targetX = ..., targetY = ...;
float diffX = targetX - currentX;
float diffY = targetY - currentY;
float delta = 0.5f; // 0 = no movement, 1 = move directly to target point.
currentX = currentX + delta * diffX;
currentY = currentY + delta * diffY;
根据三角洲的不同,你仍会受到抖动的影响,但它会更加平滑,通常在一个较小的区域内。
在相关的说明中,您是否看过Kinect的骨架平滑参数?实际上,您可以让SDK处理一些过滤。
答案 2 :(得分:0)
解决这个问题的一个非常简单的想法是将光标显示在某个位置上,该位置是过去一些位置的平均值。例如,假设您跟踪手的最后五个位置,然后将光标显示在该位置。然后,如果用户的手相对静止,则帧与帧之间的急动应该相当低,因为最后五帧将使手处于大致相同的位置并且噪声应该抵消。如果用户然后在屏幕上移动光标,光标将从其旧位置移动到新位置时生成动画,因为当您考虑手的最后五个位置时,平均位置将在其新旧之间缓慢插值位置。
这种方法非常容易调整。您可以转换数据点,以便旧点的权重大于或小于新点,并可以调整您保留的历史记录的长度。
希望这有帮助!