#include<cv.h> #include<highgui.h> #include<iostream> using namespace std; #ifndef _DENOISE #define _DENOISE const int nFrames = 9; // number of consecutive frames const int width = 640; // frame width const int height = 480; // frame height class kinectDenoising { private: IplImage* denoisedImage; IplImage* frameSet[nFrames]; unsigned int numOfFrames; CvRect imageROI; public: kinectDenoising(); ~kinectDenoising(); void addFrame(IplImage* img); void setImageROI(bool isUpdate = true); void medianFiltering(); void nearestFiltering(); void updateFrameSet(IplImage* img); void showDenoiedImage(const char* window); void showCurrentImage(const char* window); }; void insertSort(unsigned short* data,int& len,unsigned short newData); #endif
這是定義的頭文件,裝模做樣的寫了一個類,在構造函數裏面,除了對denoisedImage分配內存以外其餘都置0,析構函數須要釋放denoisedImage和frameSet數組的內存。numOfFrames原本設計爲frameSet中的圖像的幀數,結果因爲偷懶就用了一個定長的數組。ios
void kinectDenoising::setImageROI(bool isUpdate) { if(!isUpdate) { imageROI = cvRect(22,44,591,434); } else { IplImage* image8u = cvCreateImage(cvSize(width,height),IPL_DEPTH_8U,1); IplImage* bitImage = cvCreateImage(cvSize(width,height),IPL_DEPTH_8U,1); // cvThreshold can only handle images of 8UC1 or 32FC1 cvConvertScale(frameSet[0],image8u,255.0/4096.0); cvThreshold(image8u,bitImage,0,1,CV_THRESH_BINARY); // the two mats rowReduced and colReduced have to be CV_32SC1 type // for function cvReduce() seems not to suitable for 16U type and // 8U type doesn't have enough room for the result. CvMat* rowReduced = cvCreateMat(1,bitImage->width,CV_32FC1); // bitImage->width represents number of cols, while bitImage->height stands for rows CvMat* colReduced = cvCreateMat(bitImage->height,1,CV_32FC1); cvReduce(bitImage,rowReduced,0,CV_REDUCE_SUM); cvReduce(bitImage,colReduced,1,CV_REDUCE_SUM); // compute imageROI.x for(int i=0;i<rowReduced->cols;i++) { float temp = CV_MAT_ELEM(*rowReduced,float,0,i); if(temp>bitImage->height/3) { imageROI.x = i; break; } } // computer imageROI.width for(int i=rowReduced->cols;i>0;i--) { float temp = CV_MAT_ELEM(*rowReduced,float,0,i-1); if(temp>bitImage->height/3) { imageROI.width = i-imageROI.x; break; } } // compute imageROI.y for(int i=0;i<colReduced->rows;i++) { float temp = CV_MAT_ELEM(*colReduced,float,i,0); if(temp>bitImage->height/3) { imageROI.y = i; break; } } // compute imageROI.height for(int i=colReduced->rows;i>0;i--) { float temp = CV_MAT_ELEM(*colReduced,float,i-1,0); if(temp>bitImage->height/3) { imageROI.height = i-imageROI.y; break; } } // set memory free cvReleaseImage(&bitImage); cvReleaseImage(&image8u); cvReleaseMat(&rowReduced); cvReleaseMat(&colReduced); } }
這是計算深度圖像的濾波範圍。因爲深度圖像和彩色圖像的視點不一致,致使了將深度圖像映射到彩色圖像上時有效像素會縮小,典型的現象就是在深度圖像的四周會出現黑色的區域。這個函數就是用來將四周的黑色框框去掉。用OpenCV的投影的方法。因爲cvReduce()函數要進行累積和的計算,爲了避免使數據溢出,目標數組應該用32位的浮點型(此函數只支持8位unsigned char型和32位float型)。數組
void kinectDenoising::medianFiltering() { // set result image zero cvSetZero(denoisedImage); unsigned short data[nFrames]; int total; for(int i=imageROI.y;i<imageROI.y+imageROI.height;i++) { unsigned short* denoisedImageData = (unsigned short*)(denoisedImage->imageData+denoisedImage->widthStep*i); for(int j=imageROI.x;j<imageROI.x+imageROI.width;j++) { total = 0; for(int k=0;k<nFrames;k++) { insertSort(data,total,CV_IMAGE_ELEM(frameSet[k],unsigned short,i,j)); } if(total != 0) { denoisedImageData[j] = data[total/2]; } } } }
中值濾波,統計有效點並排序,而後取中值。insertSort()函數用來將值按從小到大的順序進行插入,鑑於篇幅的關係,就不貼出來了。函數
void kinectDenoising::nearestFiltering() { CvPoint topLeft,downRight; IplImage* tempImage = cvCloneImage(denoisedImage); for(int i=imageROI.y;i<imageROI.y+imageROI.height;i++) { unsigned short* data = (unsigned short*)(denoisedImage->imageData+denoisedImage->widthStep*i); for(int j=imageROI.x;j<imageROI.x+imageROI.width;j++) { for(int k=1;data[j]==0;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]==0);m++) { if(m<0) continue; if(m>=width) break; if(topLeft.y>=0) { unsigned short temp = CV_IMAGE_ELEM(tempImage,unsigned short,topLeft.y,m); if(temp > 0) { data[j] = temp; break; } } if(downRight.y < height) { unsigned short temp = CV_IMAGE_ELEM(tempImage,unsigned short,downRight.y,m); if(temp > 0) { data[j] = temp; break; } } } for(int m=topLeft.y;(m<downRight.y) && (data[j]==0);m++) { if(m<0) continue; if(m>=height) break; if(topLeft.x>0) { unsigned short temp = CV_IMAGE_ELEM(tempImage,unsigned short,m,topLeft.x); if(temp > 0) { data[j] = temp; break; } } if(downRight.x<width) { unsigned short temp = CV_IMAGE_ELEM(tempImage,unsigned short,m,downRight.x); if(temp > 0) { data[j] = temp; break; } } } } } } cvReleaseImage(&tempImage); }
最後是中值濾波,從最內層開始,一層層往外擴,直到找到有效值爲止。ui
運行結果spa