如何合并斑点/轮廓
Posted
技术标签:
【中文标题】如何合并斑点/轮廓【英文标题】:How can I merge blobs / contours 【发布时间】:2012-04-23 13:44:33 【问题描述】:我使用findContours
进行斑点检测。现在,我会将紧密且相似的 blob 合并在一起。
以下是一些示例图片:
普通的 Opencv 可以吗?
【问题讨论】:
如果您添加图像会更好。在 imageshack.us 中上传并在此处提供链接。还要说明你所说的相似是什么意思。形状相似吗?或者有类似的区域?等 好的,我想合并彼此相邻的相似形状。以下是三个例子(标记为黄色)谢谢帮助! Image 1Image 2Image 3 而那些二值图像都是经过形态学开-关操作的。 所以,基本上你是在找到每个 blob 之间的距离,如果距离 d 小于 25 则合并它? 但是还有一个问题,新合并的blob怎么处理?因为也许如果一个合并两个,第三个也应该合并.... 【参考方案1】:您提供给我们的输入图像非常易于使用:
第一步是将黄色斑点与其他所有东西分开,一个简单的颜色分割技术可以完成这项任务。您可以查看Segmentation & Object Detection by color 或Tracking colored objects in OpenCV 以了解如何操作。
然后,是时候合并 blob。一种特别有用的技术是bounding box,用于将所有 blob 放在一个矩形内。请注意,在下图中,斑点周围有一个绿色矩形:
之后,您需要做的就是用您选择的颜色填充矩形,从而连接所有的斑点。我把这个留给你作为作业。
这是我能想到的最快、最简单的方法。下面的代码演示了如何实现我刚才描述的:
#include <cv.h>
#include <highgui.h>
#include <iostream>
#include <vector>
int main(int argc, char* argv[])
cv::Mat img = cv::imread(argv[1]);
if (!img.data)
std::cout "!!! Failed to open file: " << argv[1] << std::endl;
return 0;
// Convert RGB Mat into HSV color space
cv::Mat hsv;
cv::cvtColor(img, hsv, CV_BGR2HSV);
// Split HSV Mat into HSV components
std::vector<cv::Mat> v;
cv::split(hsv,v);
// Erase pixels with low saturation
int min_sat = 70;
cv::threshold(v[1], v[1], min_sat, 255, cv::THRESH_BINARY);
/* Work with the saturated image from now on */
// Erode could provide some enhancement, but I'm not sure.
// cv::Mat element = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3));
// cv::erode(v[1], v[1], element);
// Store the set of points in the image before assembling the bounding box
std::vector<cv::Point> points;
cv::Mat_<uchar>::iterator it = v[1].begin<uchar>();
cv::Mat_<uchar>::iterator end = v[1].end<uchar>();
for (; it != end; ++it)
if (*it) points.push_back(it.pos());
// Compute minimal bounding box
cv::RotatedRect box = cv::minAreaRect(cv::Mat(points));
// Display bounding box on the original image
cv::Point2f vertices[4];
box.points(vertices);
for (int i = 0; i < 4; ++i)
cv::line(img, vertices[i], vertices[(i + 1) % 4], cv::Scalar(0, 255, 0), 1, CV_AA);
cv::imshow("box", img);
//cv::imwrite(argv[2], img);
cvWaitKey(0);
return 0;
【讨论】:
谢谢你的回答......但你误解了我一点。黄色斑点并不是真正的黄色。我只是给它们上色,向你展示我会尝试合并的女巫斑点。所以我不能使用颜色分割来隔离其他斑点。此外,区域之类的信息也不起作用,因为也许还有其他一些我不喜欢合并的更大的 blob... 呸! =\ 稍后会考虑其他事情。 不,我只对那些可能是从那里大小/比率/面积开始的流量唱歌的 blob 感兴趣。 您必须在问题中提供尽可能多的细节,否则我们将在黑暗中拍摄。这是一个复杂的问题!如果你不分享你迄今为止尝试过的东西,你可能不会得到任何答案。 让我这样说:从你给我们的图像中,你怎么知道哪个斑点是交通标志?在我看来,它们是这些图像中最大的斑点听起来合乎逻辑。我错了吗?【参考方案2】:我想我做到了,感谢您的程序详细信息,我找到了这个解决方案:(欢迎使用 cmets)
vector<vector<Point> > contours;
vector<vector<Point> > tmp_contours;
findContours(detectedImg, tmp_contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
vector<vector<Point> >::iterator it1;
it1 = tmp_contours.begin();
Mat test;
test = Mat(FImage.size(), CV_32FC3);
while (it1 != tmp_contours.end())
vector<Point> approx1;
approxPolyDP(Mat(*it1), approx1, 3, true);
Rect box1 = boundingRect(approx1);
float area1 = contourArea(approx1);
if ((area1 > 50) && (area1 < 13000) && (box1.width < 100) && (box1.height < 120))
vector<vector<Point> >::iterator it2;
it2 = tmp_contours.begin();
while (it2 != tmp_contours.end())
vector<Point> approx2;
approxPolyDP(Mat(*it2), approx2, 3, true);
Moments m1 = moments(Mat(approx1), false);
Moments m2 = moments(Mat(approx2), false);
float x1 = m1.m10 / m1.m00;
float y1 = m1.m01 / m1.m00;
float x2 = m2.m10 / m2.m00;
float y2 = m2.m01 / m2.m00;
vector<Point> dist;
dist.push_back(Point(x1, y1));
dist.push_back(Point(x2, y2));
float d = arcLength(dist, false);
Rect box2 = boundingRect(approx2);
if (box1 != box2)
if (d < 25)
//Method to merge the vectors
approx1 = mergePoints(approx1, approx2);
++it2;
Rect b = boundingRect(approx1);
rectangle(test, b, CV_RGB(125, 255, 0), 2);
contours.push_back(approx1);
++it1;
【讨论】:
以上是关于如何合并斑点/轮廓的主要内容,如果未能解决你的问题,请参考以下文章