c++ - 如何使用 OpenCV 检测白色 Blob

标签 c++ opencv image-processing object-detection

我画了一张图来测试: enter image description here

我想知道黑色圆圈中有多少 Blob 以及每个 Blob 的大小(所有 Blob 都是白色的)。

例如,在本例中我有 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 可以是对角线等)。

所以,最重要的是,我需要帮助:如何定义 blob?

谢谢

最佳答案

以下代码为所有白点找到边界矩形( Blob )。

备注:如果我们可以假设白点真的是白色的(即灰度图像中的值为 255),您可以使用此代码段。考虑将它放在某个类中以避免将不必要的参数传递给函数 Traverse。虽然它有效。这个想法基于DFS。除了灰度图像,我们还有 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。

关于c++ - 如何使用 OpenCV 检测白色 Blob ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22805349/

相关文章:

c++ - 如何为单元测试 stub 命名空间

c++ - 在 C++ 中检测到堆损坏

c++ - Xerces-c 和跨平台字符串文字

android - imread在Android的OpenCV中不起作用

将图像矩阵大小复制到 OpenCV 中的另一个矩阵

algorithm - 如何从头开始完全实现 PNG 解码器

c++成员函数声明问题w/class

c++ - OpenCv:翻译图像,将像素环绕边缘 (C++)

c++ - opencv 使用 mask 和修复将一幅图像覆盖在另一幅图像上

python - 将 PythonMagick Image 对象转换为 numpy 数组(用于 OpenCV),然后转换为 PIL 图像对象