kinect 深度图像去噪算法
算法设计思路
(1)读取16位深度图像到待处理图像帧组;
(2)ROI区域计算
由于kinect 彩色摄像头和红外深度摄像头是存在视角偏差的,经过视角对齐后,得到的深度图像是有黑边的。此处通过取帧组第一帧图像计算感兴趣区域ROI(注:kinect的摄像头视角是固定的,ROI区域也是固定的,所以只需要计算一次就够了,后续处理只需要使用计算好的就可以了)。ROI计算好,我们便可以在ROI区域做相应的图像处理操作了。
(3)多帧中值滤波
如果当前帧(i, j)处灰度不为0,不进行处理;如果为0,对图像帧组的各帧图像(i, j)位置的不为0的像素取出放入的data数组中,插入排序,取中值,代替(i, j)位置像素值。经过中值滤波后,很多黑洞已经被填充好了。
(4)空间1_近邻滤波
对待处理的图像帧,此时依然存在黑洞(由于数据集采集时,每一帧相差不是很远,有些地方在帧组的所有帧中都是黑洞。)。此时,采用的是空间近邻滤波方法,在(i, j)位置周围寻找像素值不为0的点来填充黑洞。【可以采取更好的方法】
主要代码实现
1. ROI区域计算
void kinectDenoising::setImageROI(bool isUpdate)
{
if (!isUpdate) // 若为false,定义ROI区域范围。
{
imageROI = cvRect(, , , );
}
else // 若为true,表示计算出ROI区域范围
{
IplImage* image8u = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, ); // 灰度图像格式
IplImage* bitImage = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, );// 二值图像格式 // cvShowImage("0", frameSet[0]); // 查看像素--正确
for(int i=;i<height;i++)
{
for(int j=;j<width;j++)
{
double ImgPixelVal = cvGetReal2D( frameSet[], i, j );
//输出像素值
cout <<ImgPixelVal<<" ";
}
cout << "\n"<<endl;
}
cout << "\n"<<endl;
cout << "\n"<<endl; // 像素约束到[0, 255]空间中
cvConvertScale(frameSet[], image8u, 255.0 / 4096.0, ); // 输入,输出,比例因子,平移因子
// cvThreshold只对单通道数组进行固定阈值操作【8UC1(8位无符号整型单通道矩阵)、32FC1(32位浮点型单通道矩阵)】
// 典型应用:对灰度图像进行阈值操作得到二值图像
cvThreshold(image8u, bitImage, , , CV_THRESH_BINARY); // 二值化--> bitImage // 分配矩阵空间---必须为CV_32FC1,因为16U和8U不能满足cvReduce()结果的空间需求
CvMat* rowReduced = cvCreateMat(, bitImage->width, CV_32FC1); // 行数、列数、预定义类型
CvMat* colReduced = cvCreateMat(bitImage->height, , CV_32FC1); // 将二维数组转化为向量
// 参数:输入矩阵、输出矩阵、维数(0表示矩阵处理成1行,1表示处理成1列)、输出矩阵的所有行/列的和。
cvReduce(bitImage, rowReduced, , CV_REDUCE_SUM);
cvReduce(bitImage, colReduced, , CV_REDUCE_SUM); // compute imageROI.x
for (int i = ; i<rowReduced->cols; i++) // 1行,cols列
{
// CV_MAT_ELEM参数:(输入矩阵、提取元素类型、行、列)---> 从Mat矩阵中获取元素
float temp = CV_MAT_ELEM(*rowReduced, float, , i);
// 判断条件:当bitImage整列元素和大于其高度的1/3时,视为所需的点。
if (temp > bitImage->height / )
{
imageROI.x = i;
break;
}
} // compute imageROI.width
for (int i = rowReduced->cols; i > ; i--)
{
float temp = CV_MAT_ELEM(*rowReduced, float, , i - );
if (temp > bitImage->height / )
{
imageROI.width = i - imageROI.x;
break;
}
} // compute imageROI.y
for (int i = ; i<colReduced->rows; i++)
{
float temp = CV_MAT_ELEM(*colReduced, float, i, );
if (temp>bitImage->height / )
{
imageROI.y = i;
break;
}
} // compute imageROI.height
for (int i = colReduced->rows; i > ; i--)
{
float temp = CV_MAT_ELEM(*colReduced, float, i - , );
if (temp > bitImage->height / )
{
imageROI.height = i - imageROI.y;
break;
}
} // 释放内存
cvReleaseImage(&bitImage);
cvReleaseImage(&image8u);
cvReleaseMat(&rowReduced);
cvReleaseMat(&colReduced);
}
}
2. 多帧中值滤波
void kinectDenoising::medianFiltering()
{
// set result image zero
cvSetZero(denoisedImage); unsigned short data[nFrames];
int total;
// x : 4 width : 591
// y : 36 height: 442
// 行
for (int i = imageROI.y; i < imageROI.y + imageROI.height; i++)
{
// denoiseImageData[j]表示的是image图像中第i行第j列的像素值
unsigned short* denoisedImageData = (unsigned short*)(denoisedImage->imageData + i * denoisedImage->widthStep);
// 列
for (int j = imageROI.x; j < imageROI.x + imageROI.width; j++)
{
if(CV_IMAGE_ELEM(frameSet[], unsigned short, i, j) != ){
denoisedImageData[j] =CV_IMAGE_ELEM(frameSet[], unsigned short, i, j);
}
else
{ total = ; // 表示长度
for (int k = ; k < nFrames; k++)
{
// cout << CV_IMAGE_ELEM(frameSet[k], unsigned short, i, j)<< " " ;
// 多帧图像
// CV_IMAGE_ELEM(数据指针, 数据类型,像素行坐标、像素列坐标) --> 访问图像帧组(i,j)位置的数据
insertSort(data, total, CV_IMAGE_ELEM(frameSet[k], unsigned short, i, j));
}
if (total != )
{
// 将(i,j)位置的像素值设置为时间域取中值
denoisedImageData[j] = data[total / ];
// cout << denoisedImageData[j] << " " ;
}
}
}
cout << "\n" << endl;
}
} // 插入排序
void insertSort(unsigned short* data, int& len, unsigned short newData)
{
if (newData != )
{
if (len == )
{
data[len++] = newData;
}
else
{
int i = len;
while ((i > ) && (data[i - ] > newData) )
{
data[i] = data[i - ];
i--;
}
data[i] = newData;
len++;
}
}
}
3. 空间1_近邻滤波
void kinectDenoising::nearestFiltering()
{
CvPoint topLeft, downRight;
IplImage* tempImage = cvCloneImage(denoisedImage); // 复制整个IplImage结构,连同ROI等参数
// 行 [y, y + height]
for (int i = imageROI.y; i < imageROI.y + imageROI.height; i++)
{
// denoiseImageData[j]表示的是image图像中第i行第j列的像素值
unsigned short* data = (unsigned short*)(denoisedImage->imageData + denoisedImage->widthStep*i);
// 列 [x, x + width]
for (int j = imageROI.x; j < imageROI.x + imageROI.width; j++)
{
// 如果(i, j)位置像素值为0,视为无效点,向周围查找有效点!!
for (int k = ; data[j] == ; k++) // k从1逐渐增大,直到data[j] != 0 是一个有效点
{
// 左上点和右下点
// (j-k,i-k) ( j ,i-k) (j+k,i-k)
// (j-k, i ) ( j , i ) (j+k, i )
// (j-k,i+k) ( j ,i+k) (j+k,i+k)
topLeft = cvPoint(j - k, i - k); // j为列数 i为行数【注意分别】
downRight = cvPoint(j + k, i + k); /************************************************************/
for (int m = topLeft.x; (m <= downRight.x) && (data[j] == ); m++)
{
if (m<) continue;
if (m >= width) break;
if (topLeft.y >= )
{
// 获取中心点(j,i)左上角(topLeft.y,m)位置数据
unsigned short temp = CV_IMAGE_ELEM(tempImage, unsigned short, topLeft.y, m);
if (temp > ) // 从该像素左上角查找,找到有效的点,代替中心点的像素
{
data[j] = temp;
break;
}
}
if (downRight.y < height)
{
// 获取中心点(j,i)右下角(downRight.y,m)位置数据
unsigned short temp = CV_IMAGE_ELEM(tempImage, unsigned short, downRight.y, m);
if (temp > )
{
data[j] = temp;
break;
}
}
}
// (j-k,i-k) ( j ,i-k) (j+k,i-k)
// (j-k, i ) ( j , i ) (j+k, i )
// (j-k,i+k) ( j ,i+k) (j+k,i+k)
for (int m = topLeft.y; (m<downRight.y) && (data[j] == ); m++)
{
if (m<) continue;
if (m >= height) break;
if (topLeft.x>)
{
unsigned short temp = CV_IMAGE_ELEM(tempImage, unsigned short, m, topLeft.x);
if (temp > )
{
data[j] = temp;
break;
}
} if (downRight.x<width)
{
unsigned short temp = CV_IMAGE_ELEM(tempImage, unsigned short, m, downRight.x);
if (temp > )
{
data[j] = temp;
break;
}
}
}
/************************************************************/
}
}
}
cvReleaseImage(&tempImage);
}
算法实现效果
1. 原图
彩色图

深度图

2. 中值处理

3. 近邻处理

完整代码,待更新。
耗时统计
medianFiltering timeUsed = 13.263
nearestFiltering timeUsed = 12.807
filter timeUsed = 26.07
点云效果
载入点云:pcl_viewer ./data/pointcloud.pcd
原点云图
> Loading ./data/pointcloud.pcd [done, 963 ms : 236836 points]
去噪点云图
Loading ./data/pointcloud.pcd [done, 1065 ms : 258867 points]
kinect 深度图像去噪算法的更多相关文章
- paper 132:图像去噪算法:NL-Means和BM3D
这篇文章写的非常好,确定要~认真~慎重~的转载了,具体请关注本文编辑作者:http://wenhuix.github.io/research/denoise.html 我不会告诉你这里的代码都是f ...
- 如何用70行Java代码实现深度神经网络算法
http://www.tuicool.com/articles/MfYjQfV 如何用70行Java代码实现深度神经网络算法 时间 2016-02-18 10:46:17 ITeye 原文 htt ...
- 利用python深度学习算法来绘图
可以画画啊!可以画画啊!可以画画啊! 对,有趣的事情需要讲三遍. 事情是这样的,通过python的深度学习算法包去训练计算机模仿世界名画的风格,然后应用到另一幅画中,不多说直接上图! 这个是世界名画& ...
- win10+anaconda+cuda配置dlib,使用GPU对dlib的深度学习算法进行加速(以人脸检测为例)
在计算机视觉和机器学习方向有一个特别好用但是比较低调的库,也就是dlib,与opencv相比其包含了很多最新的算法,尤其是深度学习方面的,因此很有必要学习一下.恰好最近换了一台笔记本,内含一块GTX1 ...
- SSE图像算法优化系列二十一:基于DCT变换图像去噪算法的进一步优化(100W像素30ms)。
在优化IPOL网站中基于DCT(离散余弦变换)的图像去噪算法(附源代码) 一文中,我们曾经优化过基于DCT变换的图像去噪算法,在那文所提供的Demo中,处理一副1000*1000左右的灰度噪音图像耗时 ...
- 基于深度学习的恶意样本行为检测(含源码) ----采用CNN深度学习算法对Cuckoo沙箱的动态行为日志进行检测和分类
from:http://www.freebuf.com/articles/system/182566.html 0×01 前言 目前的恶意样本检测方法可以分为两大类:静态检测和动态检测.静态检测是指并 ...
- 图像去噪算法:NL-Means和BM3D
图像去噪是非常基础也是非常必要的研究,去噪常常在更高级的图像处理之前进行,是图像处理的基础.可惜的是,目前去噪算法并没有很好的解决方案,实际应用中,更多的是在效果和运算复杂度之间求得一个平衡,再一次验 ...
- "如何用70行Java代码实现深度神经网络算法" 的delphi版本
http://blog.csdn.net/hustjoyboy/article/details/50721535 "如何用70行Java代码实现深度神经网络算法" 的delphi ...
- AI系统——机器学习和深度学习算法流程
终于考上人工智能的研究僧啦,不知道机器学习和深度学习有啥区别,感觉一切都是深度学习 挖槽,听说学长已经调了10个月的参数准备发有2000亿参数的T9开天霹雳模型,我要调参发T10准备拿个Best Pa ...
随机推荐
- 使用 Hexo + github 搭建个人博客
来自:http://www.cnblogs.com/fengzheng/p/8031518.html Hexo 是什么 Hexo 是一个快速.简洁且高效的博客框架.Hexo 使用 Markdown(或 ...
- Android服务重启
现在有这样的需求,防止自己的app被其他的应用程序(比如qq手机管家)杀死,该怎么实现呢.我们知道app都是运行在进程中的,android是怎样管理这些进程的呢.要想app不被杀死,只要做到进程不被结 ...
- TortoiseGit-2.0.0.0-64bit问题
使用TortoiseGit拉取一个项目时,提示: disconnected no supported authentication methods available(server sent: pub ...
- h5 页面点击添加添加input框
h5 页面点击添加添加input框 前段时间有个需求,页面要能点击添加按钮控制input框的个数,当时感觉有点难,就没做,这两个又遇到了,没办法写了个简单的 效果图,加号增加,减号减少 直接上代码, ...
- Zynq-7000 FreeRTOS(二)中断:PL中断请求
总结Zynq-7000的PL发送给PS一个中断请求,为FreeRTOS中断做准备. UG585的P225显示了系统的中断框图,如下图所示. 图:ZYNQ器件的中断框图 UG585的P227画出来中断控 ...
- 浏览器页面的显隐对js的setInterval()执行所产生的bug
前段时间,所写的一个”js无间隙滚动效果“,当页面离开后,重新返回时,会出现动画的错乱.我以为是因为我代码逻辑的原因导致的,但是,当在火狐浏览器上进行浏览时却没有动画错乱的问题. 于是乎,在网上查找是 ...
- Flutter框架概览
前言:进入新框架的开发前,有必要整体了解框架设计及特点,对该框架初步认识,此文对Flutter框架进行浅显梳理,以备查阅: Flutter框架 从该架构图可知,Flutter框架可分为Framew ...
- shiro学习笔记_0300_jdbcRealm和认证策略
使用shiro框架来完成认证工作,默认是iniRealm,如果需要使用其他的realm,需要配置. ini配置文件详解,官方文档的说明如下: [main] section 是你配置应用程序的 Secu ...
- Apache无法启动报错查看
wampserver橙色图标 查找原因 1.测试80端口 . 如已被占用,则改别的端口在启动apache.怎么改apache的的端口去百度一下都有. 2.找到httpd.exe的目录.在cmd命令行下 ...
- Freemarker不显示对象的属性
Freemarker不显示对象的属性 今天使用Freemarker在springboot项目中通过模板生成一些html文件.但是发现没有显示对象的属性. 找了很长时间,终于发现不显示对象的属性可能是两 ...