2012-10-18 155 views
13

我想從kinect獲取的深度圖像減去背景。當我知道什麼是otsu閾值時,我認爲它可以和它一起使用。將深度圖像轉換爲灰度,我希望可以應用otsu閾值來對圖像進行二值化處理。Otsu深度圖像閾值

但是我用OpenCV 2.3實現(試圖實現)它,它是徒勞的。然而,輸出圖像是非常意外的二值化。我連續進行了閾值處理(即將結果打印到屏幕上以分析每幀),並且發現對於某些幀,發現閾值爲160且有時發現爲0.我不明白爲什麼會發生這種情況。這可能是由於kinect返回的深度圖像中0的數量很大,這對應於無法測量的像素。有沒有一種方法可以讓算法忽略具有值0的像素?或者otsu閾值對我正在嘗試做的事不好?

以下是相關代碼的一些輸出和片段。你可能會注意到第二個截圖看起來可以做一些很好的二值化,但是我想要實現一個能夠區分對應於場景中的椅子和背景的像素。

謝謝。

  cv::Mat1s depthcv(depth->getHeight(), depth->getWidth()); 
      cv::Mat1b depthcv8(depth->getHeight(), depth->getWidth()); 
      cv::Mat1b depthcv8_th(depth->getHeight(), depth->getWidth()); 
      depthcv.data =(uchar*) depth->getDepthMetaData().Data(); 
      depthcv.convertTo(depthcv8,CV_8U,255/5000.f); 

      //apply otsu thresholding 
      cv::threshold(depthcv8, depthcv8_th, 128, 255, CV_THRESH_BINARY|CV_THRESH_OTSU); 
      std::ofstream output; 
      output.open("output.txt"); 
      //output << "M = "<< endl << " " << depthcv8 << endl << endl; 
      cv::imshow("lab",depthcv8_th); 
      cv::waitKey(1); 

Image 1 this second screenshot looks like it could do some good binarization

+2

要在Ubuntu按'ALT + prtsc'單一窗口的屏幕截圖。 – ArtemStorozhuk

+0

我只熟悉官方的Windows SDK,所以不能直接回答這個問題。但是,如果您安裝了Windows,則Kinect for Windows SDK Toolkit示例中會有「綠色屏幕」示例。你可能會從那裏得到一些想法。也許... ? –

+0

請輸入圖片 – nkint

回答

13

大津是可能是你正在嘗試做的不夠好,但你需要計算與Otsu算法最佳閾值之前掩蓋了零個值,否則分配強度值的偏差會比你想要的低。

OpenCV不提供cv::threshold函數的掩碼參數,因此您必須自己刪除這些值。我建議將所有非零值放在1乘N矩陣中,然後用CV_THRESH_OTSU調用cv::threshold函數並保存返回值(這是估計的最佳閾值),然後在原始圖像上再次運行cv::threshold函數只是CV_THRESH_BINARY標誌和計算的閾值。

這裏是一個可能的實現:

// move zeros to the back of a temp array 
cv::Mat copyImg = origImg; 
uint8* ptr = copyImg.datastart; 
uint8* ptr_end = copyImg.dataend; 
while (ptr < ptr_end) { 
    if (*ptr == 0) { // swap if zero 
    uint8 tmp = *ptr_end; 
    *ptr_end = *ptr; 
    *ptr = tmp; 
    ptr_end--; // make array smaller 
    } else { 
    ptr++; 
    } 
} 

// make a new matrix with only valid data 
cv::Mat nz = cv::Mat(std::vector<uint8>(copyImg.datastart,ptr_end),true); 

// compute optimal Otsu threshold 
double thresh = cv::threshold(nz,nz,0,255,CV_THRESH_BINARY | CV_THRESH_OTSU); 

// apply threshold 
cv::threshold(origImg,origImg,thresh,255,CV_THRESH_BINARY_INV);