How to detect white blobs using OpenCV

前端 未结 1 682
离开以前
离开以前 2021-01-14 14:38

I paint a picture to test: \"enter

And I want to know how much blobs I have in the bla

1条回答
  •  攒了一身酷
    2021-01-14 15:13

    Following code finds bounding rects (blobs) for all white spots.

    Remark: if we can assume white spots are really white (namely have values 255 in grayscaled image), you can use this snippet. Consider putting it in some class to avoid passing uncecessary params to function Traverse. Although it works. The idea is based on DFS. Apart from the gryscaled image, we have ids matrix to assign and remember which pixel belongs to which blob (all pixels having the same id belong to the same blob).

    void Traverse(int xs, int ys, cv::Mat &ids,cv::Mat &image, int blobID, cv::Point &leftTop, cv::Point &rightBottom) {
        std::stack 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(y,x) == 0 || ids.at(y,x) > 0)
                continue;
    
            ids.at(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 &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(y,x) > 0 && ids.at(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: I fixed a bug, lowered threshold level and now the output is given below. I think it is a good start point.

    Output

    EDIT2: I get rid of recursion in Traverse(). In bigger images recursion caused Stackoverflow.

    0 讨论(0)
提交回复
热议问题