OpenCV - 在二进制图像中查找最大 blob 的边界框

18

如何使用OpenCV在二进制图像中找到最大blob的边界框?不幸的是,OpenCV没有特定的blob检测功能。我应该只使用findContours()并在列表中搜索最大的吗?


2
这取决于您之后想要用blob做什么,但您的方法是有效的 :) - Quentin Geissmann
如果你说明了你使用的编程语言,你可能会得到更具体的答案。 - Geoff
我刚刚了解了一些相关内容。如果您已经有了一个二进制图像,使用铃木方法(findContours)似乎非常适合。您还可以逐步查找第一个白色像素,然后使用floodFill查找该区域的其余部分,以此类推。但我不确定这样做是否会更快。 - Geoff
2
我只想找到blob的边界框。我正在使用OpenCV for Android,但所有版本的OpenCV基本上具有相同的功能。 - 1''
5个回答

8
这里是代码: (提示:尽量不要懒惰,自己理解下面函数的作用。)
cv::Mat findBiggestBlob(cv::Mat & matImage){
    int largest_area=0;
    int largest_contour_index=0;

    vector< vector<Point> > contours; // Vector for storing contour
    vector<Vec4i> hierarchy;

    findContours( matImage, contours, hierarchy,CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE ); // Find the contours in the image

    for( int i = 0; i< contours.size(); i++ ) {// iterate through each contour. 
        double a=contourArea( contours[i],false);  //  Find the area of contour
        if(a>largest_area){
            largest_area=a;
            largest_contour_index=i;                //Store the index of largest contour
            //bounding_rect=boundingRect(contours[i]); // Find the bounding rectangle for biggest contour
        }
    }

    drawContours( matImage, contours, largest_contour_index, Scalar(255), CV_FILLED, 8, hierarchy ); // Draw the largest contour using previously stored index.
    return matImage;
}

这不是我自己的答案的重复吗? - 1''
不,我的答案是用C++编写的,这是OpenCV的核心语言。就像我说的,它是为懒人准备的。 - TimZaman
@TimZaman,你能帮我找到drawContours()的Java等效方法吗? - Prasanna Aarthi

4
如果你想使用OpenCV库,请查看OpenCV的SimpleBlobDetector。以下是另一个stack overflow,展示了它的小教程: 如何使用OpenCV SimpleBlobDetector
然而,这只给出了关键点。你可以将其用作查找所需blob的初始搜索,然后可能在最有可能的blob周围使用findContours算法。
此外,您越了解自己的blob,就可以提供参数以过滤掉不需要的blob。您可能希望测试SimpleBlobDetector的面积参数。可能可以根据图像区域的大小计算出面积,如果算法未检测到任何blob,则迭代允许更小的blob。
这是主要的OpenCV文档链接: http://docs.opencv.org/modules/features2d/doc/common_interfaces_of_feature_detectors.html#simpleblobdetector

谢谢提供链接,这看起来是一个很好的findContours替代方案。不幸的是它没有在OpenCV4Android中,所以我会坚持我的原始计划。 - 1''

2
为了找到最大 blob 的边界框,我使用了 findContours 函数,并跟随以下代码:
double maxArea = 0;
for (MatOfPoint contour : contours) {
    double area = Imgproc.contourArea(contour);
    if (area > maxArea) {
        maxArea = area;
        largestContour = contour;
    }
}
Rect boundingRect = Imgproc.boundingRect(largestContour);

1
如果轮廓内部有一个洞,我们想要最大面积的斑点怎么办? - Koray

2

由于没有人发布完整的OpenCV解决方案,这里提供一种简单的方法,使用阈值处理和轮廓面积过滤。


输入图像

enter image description here

最大的斑点/轮廓用绿色突出显示

enter image description here

import cv2

# Load image, grayscale, Gaussian blur, and Otsu's threshold
image = cv2.imread('1.png')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]

# Find contours and sort using contour area
cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
cnts = sorted(cnts, key=cv2.contourArea, reverse=True)
for c in cnts:
    # Highlight largest contour
    cv2.drawContours(image, [c], -1, (36,255,12), 3)
    break

cv2.imshow('thresh', thresh)
cv2.imshow('image', image)
cv2.waitKey()

0

TimZaman,你的代码有一个bug,但我无法评论,所以我开始了一个新的并且正确的答案。这是基于1和TimZaman的想法的我的解决方案:

Mat measure::findBiggestBlob(cv::Mat &src){
int largest_area=0;
int largest_contour_index=0;
Mat temp(src.rows,src.cols,CV_8UC1);
Mat dst(src.rows,src.cols,CV_8UC1,Scalar::all(0));
src.copyTo(temp);

vector<vector<Point>> contours; // storing contour
vector<Vec4i> hierarchy;

findContours( temp, contours, hierarchy,CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE );

for( int i = 0; i< contours.size(); i++ ) // iterate
{
    double a=contourArea( contours[i],false);  //Find the largest area of contour
    if(a>largest_area)
    {
        largest_area=a;
        largest_contour_index=i;
    }

}

drawContours( dst, contours,largest_contour_index, Scalar(255), CV_FILLED, 8, hierarchy ); 
// Draw the largest contour
return dst;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接