OpenCV单kinect多帧静止场景的深度图像去噪

from: OpenCV单kinect多帧静止场景的深度图像去噪


老板kinect去噪的任务下达已经有半个多月了,前期除了看了几天文献之外就打酱油了,好像每天都很忙,可是就是不知道在忙什么。这几天为了交差,就胡乱凑了几段代码,得到一个结果,也知道不行,先应付一下,再图打算。

程序思想很简单,先对静止的场景连续采样若干帧,然后对所有点在时间域取中值,对取完中值之后的无效点在空间域取最近邻,勉强将黑窟窿填上了。由于代码较长,现在奉上关键的几个片段:

  1. #include<cv.h>  
  2. #include<highgui.h>  
  3. #include<iostream>  
  4. using namespace std;  
  5.   
  6. #ifndef _DENOISE  
  7. #define _DENOISE  
  8.   
  9. const int nFrames = 9;   // number of consecutive frames  
  10. const int width = 640;   // frame width  
  11. const int height = 480;  // frame height  
  12.   
  13. class kinectDenoising  
  14. {  
  15. private:                         
  16.     IplImage* denoisedImage;  
  17.     IplImage* frameSet[nFrames];  
  18.     unsigned int numOfFrames;  
  19.     CvRect imageROI;  
  20. public:  
  21.     kinectDenoising();  
  22.     ~kinectDenoising();  
  23.     void addFrame(IplImage* img);   
  24.     void setImageROI(bool isUpdate = true);  
  25.     void medianFiltering();   
  26.     void nearestFiltering();  
  27.     void updateFrameSet(IplImage* img);  
  28.     void showDenoiedImage(const char* window);  
  29.     void showCurrentImage(const char* window);  
  30. };  
  31.   
  32. void insertSort(unsigned short* data,int& len,unsigned short newData);  
  33.   
  34. #endif  

这是定义的头文件,装模作样的写了一个类,在构造函数里面,除了对denoisedImage分配内存之外其他都置0,析构函数需要释放denoisedImage和frameSet数组的内存。numOfFrames本来设计为frameSet中的图像的帧数,结果由于偷懒就用了一个定长的数组。

  1. void kinectDenoising::setImageROI(bool isUpdate)  
  2. {  
  3.     if(!isUpdate)   
  4.     {  
  5.         imageROI = cvRect(22,44,591,434);  
  6.     }  
  7.     else  
  8.     {  
  9.         IplImage* image8u = cvCreateImage(cvSize(width,height),IPL_DEPTH_8U,1);  
  10.         IplImage* bitImage = cvCreateImage(cvSize(width,height),IPL_DEPTH_8U,1);  
  11.   
  12.         // cvThreshold can only handle images of 8UC1 or 32FC1  
  13.         cvConvertScale(frameSet[0],image8u,255.0/4096.0);  
  14.         cvThreshold(image8u,bitImage,0,1,CV_THRESH_BINARY);  
  15.   
  16.         // the two mats rowReduced and colReduced have to be CV_32SC1 type  
  17.         // for function cvReduce() seems not to suitable for 16U type and   
  18.         // 8U type doesn't have enough room for the result.  
  19.         CvMat* rowReduced = cvCreateMat(1,bitImage->width,CV_32FC1);  
  20.         // bitImage->width represents number of cols, while bitImage->height stands for rows  
  21.         CvMat* colReduced = cvCreateMat(bitImage->height,1,CV_32FC1);  
  22.   
  23.         cvReduce(bitImage,rowReduced,0,CV_REDUCE_SUM);  
  24.         cvReduce(bitImage,colReduced,1,CV_REDUCE_SUM);  
  25.   
  26.         // compute imageROI.x  
  27.         for(int i=0;i<rowReduced->cols;i++)  
  28.         {  
  29.             float temp = CV_MAT_ELEM(*rowReduced,float,0,i);  
  30.             if(temp>bitImage->height/3)  
  31.             {  
  32.                 imageROI.x = i;  
  33.                 break;  
  34.             }  
  35.         }  
  36.   
  37.         // computer imageROI.width  
  38.         for(int i=rowReduced->cols;i>0;i--)  
  39.         {  
  40.             float temp = CV_MAT_ELEM(*rowReduced,float,0,i-1);  
  41.             if(temp>bitImage->height/3)  
  42.             {  
  43.                 imageROI.width = i-imageROI.x;  
  44.                 break;  
  45.             }  
  46.         }  
  47.   
  48.         // compute imageROI.y  
  49.         for(int i=0;i<colReduced->rows;i++)  
  50.         {  
  51.             float temp = CV_MAT_ELEM(*colReduced,float,i,0);  
  52.             if(temp>bitImage->height/3)  
  53.             {  
  54.                 imageROI.y = i;  
  55.                 break;  
  56.             }  
  57.         }  
  58.   
  59.         // compute imageROI.height  
  60.         for(int i=colReduced->rows;i>0;i--)  
  61.         {  
  62.             float temp = CV_MAT_ELEM(*colReduced,float,i-1,0);  
  63.             if(temp>bitImage->height/3)  
  64.             {  
  65.                 imageROI.height = i-imageROI.y;  
  66.                 break;  
  67.             }  
  68.         }  
  69.   
  70.         // set memory free  
  71.         cvReleaseImage(&bitImage);  
  72.         cvReleaseImage(&image8u);  
  73.         cvReleaseMat(&rowReduced);  
  74.         cvReleaseMat(&colReduced);  
  75.     }  
  76. }  

这是计算深度图像的滤波范围。由于深度图像和彩色图像的视点不一致,导致了将深度图像映射到彩色图像上时有效像素会缩小,典型的现象就是在深度图像的四周会出现黑色的区域。这个函数就是用来将四周的黑色框框去掉。用OpenCV的投影的方法。由于cvReduce()函数要进行累积和的计算,为了不使数据溢出,目标数组应该用32位的浮点型(此函数只支持8位unsigned char型和32位float型)。

  1. void kinectDenoising::medianFiltering()  
  2. {  
  3.     // set result image zero  
  4.     cvSetZero(denoisedImage);  
  5.   
  6.     unsigned short data[nFrames];  
  7.     int total;  
  8.     for(int i=imageROI.y;i<imageROI.y+imageROI.height;i++)  
  9.     {  
  10.         unsigned short* denoisedImageData = (unsigned short*)(denoisedImage->imageData+denoisedImage->widthStep*i);  
  11.         for(int j=imageROI.x;j<imageROI.x+imageROI.width;j++)  
  12.         {  
  13.             total = 0;  
  14.             for(int k=0;k<nFrames;k++)  
  15.             {  
  16.                 insertSort(data,total,CV_IMAGE_ELEM(frameSet[k],unsigned short,i,j));  
  17.             }  
  18.             if(total != 0)  
  19.             {  
  20.                 denoisedImageData[j] = data[total/2];  
  21.             }  
  22.         }  
  23.     }  
  24. }  

中值滤波,统计有效点并排序,然后取中值。insertSort()函数用来将值按从小到大的顺序进行插入,鉴于篇幅的关系,就不贴出来了。

  1. void kinectDenoising::nearestFiltering()  
  2. {  
  3.     CvPoint topLeft,downRight;  
  4.     IplImage* tempImage = cvCloneImage(denoisedImage);  
  5.     for(int i=imageROI.y;i<imageROI.y+imageROI.height;i++)  
  6.     {  
  7.         unsigned short* data = (unsigned short*)(denoisedImage->imageData+denoisedImage->widthStep*i);  
  8.         for(int j=imageROI.x;j<imageROI.x+imageROI.width;j++)  
  9.         {  
  10.             for(int k=1;data[j]==0;k++)  
  11.             {  
  12.                 topLeft = cvPoint(j-k,i-k);    // j为行数 i为列数  
  13.                 downRight = cvPoint(j+k,i+k);  
  14.                 for(int m=topLeft.x;(m<=downRight.x) && (data[j]==0);m++)  
  15.                 {  
  16.                     if(m<0) continue;  
  17.                     if(m>=width) break;  
  18.                     if(topLeft.y>=0)  
  19.                     {  
  20.                         unsigned short temp = CV_IMAGE_ELEM(tempImage,unsigned short,topLeft.y,m);  
  21.                         if(temp > 0)  
  22.                         {  
  23.                             data[j] = temp;  
  24.                             break;  
  25.                         }  
  26.                     }  
  27.                     if(downRight.y < height)  
  28.                     {  
  29.                         unsigned short temp = CV_IMAGE_ELEM(tempImage,unsigned short,downRight.y,m);  
  30.                         if(temp > 0)  
  31.                         {  
  32.                             data[j] = temp;  
  33.                             break;  
  34.                         }  
  35.                     }                     
  36.                 }  
  37.   
  38.                 for(int m=topLeft.y;(m<downRight.y) && (data[j]==0);m++)  
  39.                 {  
  40.                     if(m<0) continue;  
  41.                     if(m>=height) break;  
  42.                     if(topLeft.x>0)  
  43.                     {  
  44.                         unsigned short temp = CV_IMAGE_ELEM(tempImage,unsigned short,m,topLeft.x);  
  45.                         if(temp > 0)  
  46.                         {  
  47.                             data[j] = temp;  
  48.                             break;  
  49.                         }  
  50.                     }  
  51.   
  52.                     if(downRight.x<width)  
  53.                     {  
  54.                         unsigned short temp = CV_IMAGE_ELEM(tempImage,unsigned short,m,downRight.x);  
  55.                         if(temp > 0)  
  56.                         {  
  57.                             data[j] = temp;  
  58.                             break;  
  59.                         }  
  60.                     }  
  61.                 }  
  62.             }  
  63.         }  
  64.     }  
  65.     cvReleaseImage(&tempImage);  
  66. }  

最后是中值滤波,从最内层开始,一层层往外扩,直到找到有效值为止。

运行结果:

源图像:


结果图像:

附注:本来这个程序是在8位图像上进行的。先取得16位的unsigned short型深度图像,然后通过cvConvertScale()函数将其转化为8位的unsigned char型,结果在进行去噪的时候怎么都不对,将unsigned char型的数据放到matlab中一看,发现在unsigned short型数据中为0值的像素莫名其妙的在unsigned char型里有了一个很小的值(比如说1, 2, 3, 4, 5什么的,就是不为0)。很奇怪,不知道OpenCV中是怎么搞的。看来还是源数据靠谱,于是将其改为16位的unsigned short型,结果形势一片大好。

http://blog.csdn.net/chenli2010/article/details/7006573

dafu6693
  • dafu6693

    2017-08-21 19:54 9楼
  • 博主,最后的意思是不用转换图像的类型,是吗?

dafu6693
  • dafu6693

    2017-07-21 10:16 8楼
  • 一直图片加载失败!!!

dafu6693
  • dafu6693

    2017-07-20 21:28 7楼
  • 你好 ,我想问一下是要输入多张同一场景的图片吗?

相关文章推荐

自适应中值滤波(基于C++和OpenCV)Kinect深度图

自适应中值滤波(基于C++和OpenCV)Kinect深度图

opencv学习(7)图像的各种滤波函数的介绍

图像的滤波目的有两个: 一是抽出图像的特征作为图像识别的特征模式; 另一个是为适应图像处理的要求,消除图像数字化时所混入的噪声; 1、图像的平滑处理: 平滑滤波是指低频增强的空间滤...

程序员不追赶AI,会被淘汰吗?

燃爆!人工智能薪酬从起步2万到涨到3万,这种背景下,我该转型AI吗?未来会不会淘汰?这篇文章可以启发给所有的程序员...

OpenNI+OpenCV对Kinect采集的彩色图和深度图进行滤波

平台:Windows 7 x86,OpenCV2.4.9,OpenNI1.5.4.0,VS2010        采用了4种方式对彩色图和深度图进行滤波,分别为均值滤波、高斯滤波、中值滤波和双边滤波...

opencv 图像去噪学习总结

OpenCV图像处理篇之图像平滑图像平滑算法程序分析及结果图像平滑算法图像平滑与图像模糊是同一概念,主要用于图像的去噪。平滑要使用滤波器,为不改变图像的相位信息,一般使用线性滤波器...

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

上一节我们介绍了像素滤波器,下面介绍另一个实时平滑深度图的机制–加权移动平均机制。3.2 加权移动平均机制我们通过观察可以发现,即使kinect采集的是一个静止的场景,在得到的深度图上,同一个像素位置...

人人都能看懂的 AI 入门课

本课程将讲述人工智能的现状、应用场景和入门方法,并通过运用 TensorFlow,使得受众能清晰了解人工智能的运作方式。

关于kinect v2性能分析的一些论文

PERFORMANCE EVALUATION OF THE 1ST AND 2ND GENERATION KINECT FOR MULTIMEDIA APPLICATIONS首先介绍了两代kinect...

图像平均及其在降噪方面的应用

图像平均及其在降噪方面的应用图像平均以及图像平均在应对椒盐/高斯/相机噪声方面的对比分析概述:图像平均操作是减少图像噪声的一种简单方式。我们可以简单地从图像列表中计算出一幅平均图像...

VS2010配置opencv2.4.10,添加kinect的库

转载来自:http://blog.sina.com.cn/s/blog_a3c8055e0102vedf.html因为工作需要,小小的研究一下Opencv的图像处理,主要目的是对图像做锐化,高...

Delphi7高级应用开发随书源码

  • 2003年04月30日 00:00
  • 676KB
  • 下载

OpenCV学习笔记(20)Kinect + OpenNI + OpenCV + OpenGL 组合体验

1. 项目源码详见:http://www.opencv.org.cn/forum.php?mod=viewthread&tid=13042&extra=(2014-05-21 更新链接)2. ...

Kinect2.0+OpenCV获取骨骼图

在代码里进行了坐标转换,把CameraSpace转到DepthSpace。 然后用和示例代码(D2D的)里一样的方式进行绘制,但是由于Opencv里自带的显示图像的窗口默认以BGR3通道显示图像,A...

Kinect 2.0 + OpenCV 显示深度数据、骨架信息、手势状态和人物二值图

使用Kinect 2.0 + OpenCV 获取深度信息(Depth Data),骨架信息(Body Data),手势状态(Hand State)和人物二值图(Body Index Data)。

基于深度学习的图像去噪(论文总结)

2015深度学习、自编码器、低照度图像增强Lore, Kin Gwn, Adedotun Akintayo, and Soumik Sarkar. "LLNet: A Deep Autoencod...

OpenCV图像去噪

OpenCV图像去噪

openCV之中值滤波&均值滤波(及代码实现)

在开始我们今天的博客之前,我们需要先了解一下什么是滤波:首先我们看一下图像滤波的概念。图像滤波,即在尽量保留图像细节特征的条件下对目标图像的噪声进行抑制,是图像预处理中不可缺少的操作,其处理效果的...

【OpenCV入门教程之八】线性邻域滤波专场:方框滤波、均值滤波与高斯滤波

本系列文章由@浅墨_毛星云 出品,转载请注明出处。  文章链接: http://blog.csdn.net/poem_qianmo/article/details/22...

2 kinect for windows(k4w) sdk之提取深度图像并利用opencv显示

配置好环境后,其中打开传感器等函数及类都写在 Kinect.h里面,这个可以在c://program//microsoft sdk//kinect里面找到,接下来我们就可以利用它来编程开发了。 其中...

ubuntu 14.04 +Kinect+ openNI+ openCV+ Sensorkinect 配置 +获取深度图像及相关问题

1. 最初参考的是:http://blog.csdn.net/u011700636/article/details/41493645的教程过程,但是其中遇到诸多问题,主要是来自于git包的问题,好像是...

kinect2.0+opencv获取图像和深度图像

参考这篇博客的程序,http://blog.csdn.net/yongshengsilingsa/article/details/37935975//师兄写的获取深度信息的程序,并且将深度信息存储为...
  • lgdnr
  • lgdnr
  • 2015-12-26 17:11
  • 2240

KINECT+opencv(1)将骨骼图像转化为深度图像后姿势识别

KINECT+opencv将骨骼图像转化为深度图像后姿势识别环境:kinect1.7+opencv2.4+vc2015使用kinect获取三维空间内的骨骼图像并转换为深度图像坐标绘制对二维的图像进...



展开阅读全文

没有更多推荐了,返回首页