以下代碼發現所有白點的邊界反射(斑點)。
備註:如果我們可以假設白點真的是白色(即在灰度圖像中的值爲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;
}
編輯:我固定的一個錯誤,降低了閾值水平,現在的輸出如下。我認爲這是一個很好的起點。
EDIT2:我得到Traverse()
擺脫遞歸。在更大的圖像遞歸導致Stackoverflow。
我真的不會那樣做,看看http://docs.opencv.org/modules/core/doc/operations_on_arrays.html#inrange –
@DavidKernin:非常感謝!我會深入 – AsfK
嘗試使用谷歌搜索「Blob分析」http://en.wikipedia.org/wiki/Blob_detection –