2014-04-02 4 views
3

를 사용하여 흰색 모양을 감지하는 방법은 테스트에 그림을 그릴 화이트).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++; 
    } 
} 

을하지만 분명이이 코드 (블롭은 대각선으로 볼 수 있습니다.).

결론적으로, 도움이 필요합니다. 어떻게 모양을 정의 할 수 있습니까?

+1

정말 그렇게하지 않을 것입니다. http://docs.opencv.org/modules/core/doc/operations_on_arrays.html#inrange –

+0

@DavidKernin : 대단히 감사합니다! 나는 안으로 깊숙이 들어갈 것이다 – AsfK

+0

인터넷 검색 시도 "얼룩 분석"http://en.wikipedia.org/wiki/Blob_detection –

답변

5

코드를 수행하면 모든 흰색 반점에 대한의 구형 (모양)을 경계 찾아 주셔서 감사합니다.

비고 : 흰 반점이 실제로 흰색 (즉, 회색 음영 이미지에서 255 값을 가짐)이라고 생각할 수 있다면이 스 니펫을 사용할 수 있습니다. 잠깐의 매개 변수를 트래버스 (Traverse) 함수로 전달하지 않도록 클래스에 두는 것을 고려하십시오. 그것은 작동하지만. 이 아이디어는 DFS를 기반으로합니다. gryscaled 이미지와 별개로, 우리는 어떤 픽셀이 어느 블롭에 속하는지 (동일한 블롭에 속한 모든 픽셀이 동일한 블롭에 속함) 할당하고 기억할 수있는 행렬을 가지고 있습니다.

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; 
} 

EDIT

: 난, 버그 수정 임계치 레벨을 낮출 현재 출력 이하 주어진다. 나는 그것이 좋은 출발점이라고 생각한다.

Output

EDIT2 : 나는 Traverse()에 재귀 제거. 더 큰 이미지 재귀 Stackoverflow가 발생했습니다.

+0

대단히 감사합니다! 정말 유용합니다. – AsfK

+0

코드를 확인합니다. 정말 좋은 생각이지만 내가받는 대답 (카운터)은 163644 .. 아마도 조건의 문제 :'if (r.area()> minArea)'. 우리는 같은 얼룩을 계산하지 않는지 확인해야합니다. – AsfK

+0

이 버그가 수정되었습니다. 임계 값 레벨을 낮추면 외곽선이 임계 필터의 흰색 픽셀로 필터링됩니다. 그러나 나는 그것이 당신을위한 좋은 출발점이라고 생각합니다. – marol