kinect 2.0 SDK学习笔记(六)--深度图的实时平滑之加权移动平均机制

上一节我们介绍了像素滤波器,下面介绍另一个实时平滑深度图的机制–加权移动平均机制。

3.2 加权移动平均机制

我们通过观察可以发现,即使kinect采集的是一个静止的场景,在得到的深度图上,同一个像素位置对应的深度值也是在不断变化的,这被称为闪动效应(flickering effect),它是由于随机噪声引起的。
如果要求稳定的深度值,就要尽量避免这种闪动效应。我们的办法是这样的:
- 首先,用一个队列存储当前深度帧的前N个深度帧。因为队列是一个FIFO(先进先出)的集合对象,非常适合处理一系列时间离散的数据集。
- 然后,我们根据时间给这N个帧权值,时间最近的深度值权值最大,表示最重要,距离时间最远的帧权值最小,表示最不重要。
- 最后,新的深度帧就由队列中的这些深度帧加权平均得到。注意,这个方法对于静止的场景效果很好,但是当有人物在场景中运动时,因为新的深度帧要依据之前的深度帧,所以我们可能会看到一些动作的残影,这时你需要调整一下权值参数和N的大小。

3.2.1 代码

// 前帧数量N
int N = 5;
// 各个像素深度值总和
UINT16 sumDepthData[424 * 512] = { 0 };
// 初始化,将前N帧入队列
if (queDepthArrays.size() < N)
{
    UINT16 *temp = new UINT16[424 * 512];
    memcpy(temp, depthData, 424 * 512 * 2);
    queDepthArrays.push_back(temp);
}
else
{
    if (queDepthArrays.size() == N)
    {
        // 队列中加入当前帧
        UINT16 *temp = new UINT16[424 * 512];
        memcpy(temp, depthData, 424 * 512 * 2);
        queDepthArrays.push_back(temp);
    }
    else
    {
        // 队列中加入当前帧,queDepthArrays.back()相当于当前帧,因此只需要更新它
        memcpy(queDepthArrays.back(), depthData, 424 * 512 * 2);
    }

    // 队列中已存满N个前帧+一个当前帧
    // Denominator表示分母,count表示权值的分子
    int Denominator = 0;
    int Count = 1;

    // 我们首先创建一个空的深度图,每个像素位置上储存前N帧加当前帧深度值加权之和
    // 最后每个像素除以权值之和
    for each (auto item in queDepthArrays)
    {
        // 处理每行像素
        for (int depthArrayRowIndex = 0; depthArrayRowIndex < 424; depthArrayRowIndex++)
        {
            // 处理每个像素
            for (int depthArrayColumnIndex = 0; depthArrayColumnIndex < 512; depthArrayColumnIndex++)
            {
                int index = depthArrayColumnIndex + (depthArrayRowIndex * 512);
                sumDepthData[index] += item[index] * Count;
            }
        }
        Denominator += Count;
        Count++;
    }

    // 除以权值之和
    for (int i = 0; i<512 * 424;i++) 
    {
        queDepthArrays.back()[i] = depthData[i];
        averagedDepthData[i] = (short)(sumDepthData[i] / Denominator);
    }
    // 相当于queue.pop()
    auto temp = queDepthArrays.begin();
    for (auto iter = queDepthArrays.begin(); iter !=queDepthArrays.end()-1; iter++)
    {
        *iter = *(iter + 1);
    }
    queDepthArrays.back() = *temp;
}

3.2.2 显示效果

为了方便对比,我将N调的比较大,可以看到我手臂挥动的残影。
如果在实时采集深度图的情况下,可以看到背景上像素的闪动效应明显减小了。

完整的实时深度图平滑(像素滤波+加权移动平均)代码链接

请自行配制环境–kinect 2.0SDK和OpenCV。

你可能感兴趣的:(Kinect2)