OpenCV合并图像中轮廓

如果一个图像轮廓数量比较多比较复杂,常常需要根据轮廓的面积以及相邻轮廓的距离进行过滤以及合并, 即将距离相对比较接近的轮廓进行合并,对于面积相对较小,周围又没有比较接近的轮廓将给予删除。
计算轮廓之间的距离,根据图像可选择以下方法:
1、如果轮廓各种形状都有可能存在,使用轮廓形心的距离作为两个轮廓之间距离进行合并;
2、如何轮廓均是凸包形状,则用两个轮廓最接近Point元素点的距离作为两个轮廓距离进行合并;

//根据轮廓形心之间距离是否小于阈值,进行图像轮廓合并
void mergeContoursByCentre(cv::Mat &grayImage) {

// 寻找轮廓
std::vector<std::vector<cv::Point>> contours;
cv::findContours(grayImage, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
// 合并距离非常接近的轮廓
double mergeDistanceThreshold = 10.0;        // 距离阈值,根据需要调整
for (size_t i = 0; i < contours.size(); ++i) {
	for (size_t j = i + 1; j < contours.size(); ++j) {
		// 计算轮廓i和轮廓j的形心
		cv::Moments moments_i = cv::moments(contours[i]);
		cv::Moments moments_j = cv::moments(contours[j]);
		cv::Point2f center_i(moments_i.m10 / moments_i.m00, moments_i.m01 / moments_i.m00);
		cv::Point2f center_j(moments_j.m10 / moments_j.m00, moments_j.m01 / moments_j.m00);
		// 计算形心之间的距离
		double distance = cv::norm(center_i - center_j);
		// 如果距离小于阈值,合并轮廓
		if (distance < mergeDistanceThreshold) {
			contours[i].insert(contours[i].end(), contours[j].begin(), contours[j].end());
			contours.erase(contours.begin() + j);
			--j; // 由于删除了一个轮廓,需要减少j的值
		}
	}
}
//绘制图像
int contours_area = g_inputdata.contours_area_min;
Mat convex_hull_img = Mat::zeros(grayImage.size(), CV_8U);
int contours_f_size = contours.size();
vector<vector<Point> > pointHull(contours.size());

for (size_t i = 0; i < contours.size(); i++)
{
	// 输出结果为Point类型的凸包检测
	convexHull(Mat(contours[i]), pointHull[i], false);
}

for (int i = 0; i < contours_f_size; i++)
{
	cv::Scalar color(255); // 白色
	drawContours(convex_hull_img, pointHull, i, color, -1, 8, vector<Vec4i>(), 0, Point());
}
imshow("", convex_hull_img);
waitKey();

}

//根据轮廓之间最近距离是否小于阈值,进行图像轮廓的合并
void mergeContoursByEdge(cv::Mat &grayImage) {

cv::Mat binaryImage = grayImage;
Mat convex_hull_img = Mat::zeros(grayImage.size(), CV_8U);
// 查找轮廓
std::vector<std::vector<cv::Point>> contours;
cv::findContours(binaryImage, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);

// 设置距离阈值,用于决定合并哪些轮廓
double distanceThreshold =  10.0;                // 距离阈值,根据需要调整

// 合并轮廓
std::vector<bool> merged(contours.size(), false);
int contours_size = contours.size();
for (int i = 0; i < contours_size; i++) {
	if (!merged[i]) {
		// 寻找距离足够近的轮廓并合并它们
		std::vector<cv::Point> mergedContour = contours[i];
		int contours_size = contours.size();
		for (int j = i + 1; j < contours_size; j++) {
			if (!merged[j]) {
				double distance = cv::pointPolygonTest(contours[j], mergedContour[0], true);
				if (std::abs(distance) < distanceThreshold) {
					mergedContour.insert(mergedContour.end(), contours[j].begin(), contours[j].end());
					merged[j] = true;
				}
			}
		}

		// 计算凸包
		std::vector<cv::Point> convexHull;
		cv::convexHull(mergedContour, convexHull);

		// 在图像上绘制凸多边形
		std::vector<std::vector<cv::Point>> convexHullContours{ convexHull };
		cv::Scalar color(255); // 白色
		cv::drawContours(convex_hull_img, convexHullContours, -1, color, -1);
	}
}

imshow("", convex_hull_img);
waitKey();

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值