2014-04-02 26 views
3

檢測白色斑點我畫一幅畫來測試: enter image description here如何使用OpenCV的

而且我想知道我是多麼的斑點有黑圈,什麼是每個斑點的大小(所有的斑點是〜白色)。

例如,在這種情況下,我有12點: enter image description here

我知道如何發現白色像素,並可以輕鬆地從左邊的驗證序列:

int whitePixels = 0; 
for (int i = 0; i < height; ++i) 
{ 
    uchar * pixel = image.ptr<uchar>(i); 
    for (int j = 0; j < width; ++j) 
    { 
     if (j>0 && pixel[j-1]==0) // to group pixels for one spot 
      whitePixels++; 
    } 
} 

,但很顯然,這個代碼不夠好(斑點可能是對角的,等等)。

所以,底線,我需要幫助:我該如何定義blob?

謝謝

+1

我真的不會那樣做,看看http://docs.opencv.org/modules/core/doc/operations_on_arrays.html#inrange –

+0

@DavidKernin:非常感謝!我會深入 – AsfK

+0

嘗試使用谷歌搜索「Blob分析」http://en.wikipedia.org/wiki/Blob_detection –

回答

5

以下代碼發現所有白點的邊界反射(斑點)。

備註:如果我們可以假設白點真的是白色(即在灰度圖像中的值爲255),您可以使用此片段。考慮將它放在某個類中以避免傳遞不需要的參數來實現Traverse功能。雖然它有效。這個想法是基於DFS的。除了gryscaled圖像,我們有ids矩陣來分配和記住哪個像素屬於哪個blob(具有相同id的所有像素都屬於同一個blob)。

void Traverse(int xs, int ys, cv::Mat &ids,cv::Mat &image, int blobID, cv::Point &leftTop, cv::Point &rightBottom) { 
    std::stack<cv::Point> S; 
    S.push(cv::Point(xs,ys)); 

    while (!S.empty()) { 
     cv::Point u = S.top(); 
     S.pop(); 

     int x = u.x; 
     int y = u.y; 

     if (image.at<unsigned char>(y,x) == 0 || ids.at<unsigned char>(y,x) > 0) 
      continue; 

     ids.at<unsigned char>(y,x) = blobID; 
     if (x < leftTop.x) 
      leftTop.x = x; 
     if (x > rightBottom.x) 
      rightBottom.x = x; 
     if (y < leftTop.y) 
      leftTop.y = y; 
     if (y > rightBottom.y) 
      rightBottom.y = y; 

     if (x > 0) 
      S.push(cv::Point(x-1,y)); 
     if (x < ids.cols-1) 
      S.push(cv::Point(x+1,y)); 
     if (y > 0) 
      S.push(cv::Point(x,y-1)); 
     if (y < ids.rows-1) 
      S.push(cv::Point(x,y+1)); 
    } 


} 

int FindBlobs(cv::Mat &image, std::vector<cv::Rect> &out, float minArea) { 
    cv::Mat ids = cv::Mat::zeros(image.rows, image.cols,CV_8UC1); 
    cv::Mat thresholded; 
    cv::cvtColor(image, thresholded, CV_RGB2GRAY); 
    const int thresholdLevel = 130; 
    cv::threshold(thresholded, thresholded, thresholdLevel, 255, CV_THRESH_BINARY); 
    int blobId = 1; 
    for (int x = 0;x<ids.cols;x++) 
     for (int y=0;y<ids.rows;y++){ 
      if (thresholded.at<unsigned char>(y,x) > 0 && ids.at<unsigned char>(y,x) == 0) { 
       cv::Point leftTop(ids.cols-1, ids.rows-1), rightBottom(0,0); 
       Traverse(x,y,ids, thresholded,blobId++, leftTop, rightBottom); 
       cv::Rect r(leftTop, rightBottom); 
       if (r.area() > minArea) 
        out.push_back(r); 
      } 
     } 
    return blobId; 
} 

編輯:我固定的一個錯誤,降低了閾值水平,現在的輸出如下。我認爲這是一個很好的起點。

Output

EDIT2:我得到Traverse()擺脫遞歸。在更大的圖像遞歸導致Stackoverflow。

+0

非常感謝!這真的非常有用 – AsfK

+0

我檢查你的代碼。這個想法真的很好,但我收到的答案(櫃檯)是163644 ..可能在條件中的問題:'if(r.area()> minArea)'。需要驗證我們不算在同一個blob中。 – AsfK

+0

我修復了這個錯誤。如果降低閾值級別,仍然有一個,所以輪廓在閾值過濾器中被過濾爲白色像素。但我認爲這對你來說是一個很好的起點。 – marol