OpenCV單kinect多幀靜止場景的深度圖像去噪

#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

相關文章
相關標籤/搜索