生活随笔
收集整理的这篇文章主要介绍了
深度图的实时平滑
小编觉得挺不错的,现在分享给大家,帮大家做个参考.
from: http://blog.csdn.net/jiaojialulu/article/details/53192887?locationNum=12&fps=1
深度图的实时平滑
一、背景
英文原文,使用的是第一代kinect
youtube上的演示效果
二、深度数据存在的问题
下图是我简单处理后的深度图:
蓝色表示采到深度值为0的点,而其他点用颜色来标识,颜色越深表示离相机越近。数据中的噪声表现为蓝色斑点在画面上不断出现和消失。一些噪点是由于红外在遇到物体表面时发生散射造成的,另一些是由于离得kinect较近的物体的遮挡。
另一个限制深度数据的地方在于kinect的工作范围(0.8m-4m)。在这个范围之外的物体就会表现为无数据,即深度值为0。
三、解决办法
作者提出了像素滤波器和加权移动平均两种方法,并且能在实时的要求下达到深度图平滑的效果。
3.1 像素滤波器
3.1.1 原理及步骤
第一步是将深度数据帧转换为我们方便处理的形式,比如UINT16[]。
UINT16 *depthData =
new UINT16[
424 *
512];
m_pDepthFrame->CopyFrameDataToArray(nDepthBufferSize,
reinterpret_cast<UINT16*>(depthData));
下面就是对一帧上的每个像素搜索,找到深度值为0的位置,我们希望除去这样的像素,但是又不会影响精度和数据的其他特性。那么应该如何去做呢?
我们先把深度值为0的像素定为候选滤波对象,然后看看它究竟是否符合我们滤去它的标准。我们利用它周围的一些像素对应的深度值来定义这个标准。我们以候选滤波像素为中心定义一个一个两“层”的滤波器,同时用它来寻找这个滤波器框内其他深度值非零的像素。滤波器将这些深度值做一个分布,并关注每层框内这种像素的数量。然后将每层内非零像素个数与一个阈值比较,进而决定这个候选像素是否应该被滤波。如果任意层内非零像素的数目超过了阈值,就要将所有非零像素深度值对应的统计众数(数目最多一个深度值)应用到候选滤波像素上,使其深度值不为0。滤波器如下图所示:
下图主要表明了采用众数,即滤波器框内频数最高的一个深度值来作为候选像素的深度值,要比直接采用框内所有深度值的平均要更加符合实际(我觉得如果改成内层的众数更好)。
原文使用的是C#,我这里改为C++:
unsigned
short* smoothDepthArray = (unsigned
short*)i_result.data;
int widthBound =
512 -
1;
int heightBound =
424 -
1;
int innerBandThreshold =
3;
int outerBandThreshold =
7;
for (
int depthArrayRowIndex =
0; depthArrayRowIndex<
424;depthArrayRowIndex++){
for (
int depthArrayColumnIndex =
0; depthArrayColumnIndex <
512; depthArrayColumnIndex++){
int depthIndex = depthArrayColumnIndex + (depthArrayRowIndex *
512);
if (depthArray[depthIndex] ==
0){
int x = depthIndex %
512;
int y = (depthIndex - x) /
512;unsigned
short filterCollection[
24][
2] = {
0};
int innerBandCount =
0;
int outerBandCount =
0;
for (
int yi = -
2; yi <
3; yi++){
for (
int xi = -
2; xi <
3; xi++){
if (xi !=
0 || yi !=
0){
int xSearch = x + xi;
int ySearch = y + yi;
if (xSearch >=
0 && xSearch <= widthBound &&ySearch >=
0 && ySearch <= heightBound){
int index = xSearch + (ySearch *
512);
if (depthArray[
index] !=
0){
for (
int i =
0; i <
24; i++){
if (filterCollection[i][
0] == depthArray[
index]){filterCollection[i][
1]++;
break;}
else if (filterCollection[i][
0] ==
0){filterCollection[i][
0] = depthArray[
index];filterCollection[i][
1]++;
break;}}
if (yi !=
2 && yi != -
2 && xi !=
2 && xi != -
2)innerBandCount++;
elseouterBandCount++;}}}}}
if (innerBandCount >= innerBandThreshold || outerBandCount >= outerBandThreshold){
short frequency =
0;
short depth =
0;
for (
int i =
0; i <
24; i++){
if (filterCollection[i][
0] ==
0)
break;
if (filterCollection[i][
1] > frequency){depth = filterCollection[i][
0];frequency = filterCollection[i][
1];}}smoothDepthArray[depthIndex] = depth;}
else{smoothDepthArray[depthIndex] =
0;}}
else{smoothDepthArray[depthIndex] = depthArray[depthIndex];}}}
3.1.2 滤波效果
我这里再次把原图贴上,左图是滤波后的效果图:可以看到物体边缘散乱的深度值为0的点已经减少了不少。
3.1.3 代码
因为只是为了理论上了解像素滤波器平滑的机制,因此我选择静态的读取kinect采集的原始图片,然后进行平滑。
代码下载链接
请自行配制环境–kinect 2.0SDK和OpenCV。
下一节将继续讲解平滑中的加权移动机制
《新程序员》:云原生和全面数字化实践50位技术专家共同创作,文字、视频、音频交互阅读
总结
以上是生活随笔为你收集整理的深度图的实时平滑的全部内容,希望文章能够帮你解决所遇到的问题。
如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。