OpenCV單kinect多幀靜止情境的深度映像去噪

來源:互聯網
上載者:User

老闆kinect去噪的任務下達已經有半個多月了,前期除了看了幾天文獻之外就打醬油了,好像每天都很忙,可是就是不知道在忙什麼。這幾天為了交差,就胡亂湊了幾段代碼,得到一個結果,也知道不行,先應付一下,再圖打算。

程式思想很簡單,先對靜止的情境連續採樣若干幀,然後對所有點在時間域取中值,對取完中值之後的無效點在空間域取最近鄰,勉強將黑窟窿填上了。由於代碼較長,現在奉上關鍵的幾個片段:

#include<cv.h>#include<highgui.h>#include<iostream>using namespace std;#ifndef _DENOISE#define _DENOISEconst int nFrames = 9;   // number of consecutive framesconst int width = 640;   // frame widthconst int height = 480;  // frame heightclass 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中的映像的幀數,結果由於偷懶就用了一個定長的數組。

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 32FC1cvConvertScale(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 freecvReleaseImage(&bitImage);cvReleaseImage(&image8u);cvReleaseMat(&rowReduced);cvReleaseMat(&colReduced);}}

這是計算深度映像的濾波範圍。由於深度映像和彩色映像的視點不一致,導致了將深度影像地圖到彩色映像上時有效像素會縮小,典型的現象就是在深度映像的四周會出現黑色的地區。這個函數就是用來將四周的黑色框框去掉。用OpenCV的投影的方法。由於cvReduce()函數要進行累積和的計算,為了不使資料溢出,目標數組應該用32位的浮點型(此函數只支援8位unsigned char型和32位float型)。

void kinectDenoising::medianFiltering(){// set result image zerocvSetZero(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);}

最後是中值濾波,從最內層開始,一層層往外擴,直到找到有效值為止。

運行結果:

源映像:


結果映像:

附註:本來這個程式是在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

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.