OpenCV - 在二进制图像中找到最大斑点的边界框
Posted
技术标签:
【中文标题】OpenCV - 在二进制图像中找到最大斑点的边界框【英文标题】:OpenCV - find bounding box of largest blob in binary image 【发布时间】:2013-05-20 17:37:00 【问题描述】:使用 OpenCV 在二值图像中找到最大 blob 的边界框的最有效方法是什么?不幸的是,OpenCV 没有专门的斑点检测功能。我应该只使用findContours()
并搜索列表中最大的吗?
【问题讨论】:
这取决于你想对 blob 做什么,但你的方法是有效的 :) 如果您说出您使用的语言,您可能会得到更具体的答案。 我刚刚阅读了一些关于此的内容。如果您已经有了二值图像,听起来使用 Suzuki 的方法 (findContours
) 非常适合。您还可以逐步找到第一个白色像素,然后使用floodFill
找到该区域的其余部分,依此类推。但我不确定这会更快。
我只想找到blob的边界框。我正在使用适用于 android 的 OpenCV,但所有版本的 OpenCV 都具有几乎相同的功能。
【参考方案1】:
如果您想使用 OpenCV 库,请查看 OpenCVs SimpleBlobDetector。这是另一个堆栈溢出的小教程:How to use OpenCV SimpleBlobDetector
不过,这只会为您提供关键点。您可以将其用作初始搜索以找到所需的 blob,然后可能使用 findContours 算法围绕最可能的 blob。
此外,您对 blob 的了解越多,您可以提供参数来过滤掉您不想要的 blob。您可能想要测试 SimpleBlobDetector 的区域参数。可能可以根据图像区域的大小计算区域,然后如果算法未检测到任何斑点,则迭代地允许更小的斑点。
这里是主要 OpenCV 文档的链接:http://docs.opencv.org/modules/features2d/doc/common_interfaces_of_feature_detectors.html#simpleblobdetector
【讨论】:
感谢您的链接,这看起来是findContours
的不错替代品。不幸的是它不在 OpenCV4Android 中,所以我会坚持我原来的计划。【参考方案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);
【讨论】:
如果轮廓内有一个洞,我们想要面积最大的斑点怎么办?【参考方案3】:这里。它。是。 (仅供参考:尽量不要偷懒,弄清楚下面我的函数会发生什么。
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;
【讨论】:
这不是我自己的答案的重复吗? 不,我的答案是 C++,这是 OpenCV 的核心语言。正如我所说,这是为懒惰的人准备的。 @TimZaman 你能帮我处理一下drawContours()的java等价物吗【参考方案4】:TimZaman,您的代码有错误,但我无法发表评论,所以我开始一个新的正确答案。 这是我基于 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;
【讨论】:
【参考方案5】:由于没有人发布完整的OpenCV解决方案,这里有一个使用阈值+轮廓区域过滤的简单方法
输入图像
以绿色突出显示的最大斑点/轮廓
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()
【讨论】:
以上是关于OpenCV - 在二进制图像中找到最大斑点的边界框的主要内容,如果未能解决你的问题,请参考以下文章
如何在 C++ 中使用 OpenCV 4.2 计算二进制图像的周长