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();

}

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要从 PNG 文件读取图像并提取轮廓线,您可以使用 OpenCvSharp 库的函数。以下是一个示例代码,演示如何读取 PNG 文件、提取轮廓线并合并多个轮廓线: ```csharp using OpenCvSharp; // 读取 PNG 文件 Mat image = Cv2.ImRead("image.png", ImreadModes.Color); // 将图像转换为灰度图像 Mat grayImage = new Mat(); Cv2.CvtColor(image, grayImage, ColorConversionCodes.BGR2GRAY); // 阈值化处理 Mat binaryImage = new Mat(); Cv2.Threshold(grayImage, binaryImage, 127, 255, ThresholdTypes.Binary); // 查找轮廓 Point[][] contours; HierarchyIndex[] hierarchy; Cv2.FindContours(binaryImage, out contours, out hierarchy, RetrievalModes.List, ContourApproximationModes.ApproxSimple); // 合并多个轮廓线 List<Point[]> mergedContours = new List<Point[]>(); for (int i = 0; i < contours.Length; i++) { // 合并相邻的轮廓线 Cv2.ApproxPolyDP(contours[i], out Point[] approxCurve, Cv2.ArcLength(contours[i], true) * 0.02, true); mergedContours.Add(approxCurve); } // 处理合并后的轮廓线 // ... ``` 请注意,这只是一个示例代码,您可能需要根据具体的需求进行调整。在代码,首先通过 `Cv2.ImRead` 函数读取 PNG 文件,然后将图像转换为灰度图像。接下来,通过阈值化处理将灰度图像转换为二值图像。然后,使用 `Cv2.FindContours` 函数查找轮廓线。最后,通过循环遍历每个轮廓线,并使用 `Cv2.ApproxPolyDP` 函数对相邻的轮廓线进行合并。 请根据您的具体需求对代码进行修改和适应。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值