使用opencv找圆(非霍夫法)

目标图片如下:

在这里插入图片描述

基本思路为:

1.使用开闭运算,对图像进行处理,因为该图像如果直接使用轮廓检测的话,会有许多杂乱的轮廓线

cv::Mat element_open = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(17, 17)); // 这里的size根据图像情况设定
cv::morphologyEx(image, image, cv::MORPH_OPEN, element_open);
cv::Mat element_close = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(7, 7));
cv::morphologyEx(image, image, cv::MORPH_CLOSE, element_close);

处理后的图像是这样的
在这里插入图片描述

2.然后使用阈值分割

cv::threshold(image, image, 120, 255, cv::THRESH_BINARY);

在这里插入图片描述

3.使用Laplace变换找到轮廓线

cv::Mat kenerl = (cv::Mat_<float>(3, 3) << 0, 1, 0, 1, -4, 1, 0, 1, 0);
cv::filter2D(image, image, image.type(), kenerl);

在这里插入图片描述

4.最后对轮廓线进行筛选

float targetArea = 3.14 * 1400 * 1400;
std::vector<std::vector<cv::Point>> reslutContours;
// 计算轮廓的面积
for (size_t i = 0; i < contours.size(); i++) {
	// 计算轮廓的面积和周长
	double area = contourArea(contours[i]);
	double perimeter = arcLength(contours[i], true);
	// 计算圆形度
	double circularity = (4 * 3.1415926 * area) / (perimeter * perimeter);
	// 如果圆形度不满足要求或者面积不在targetArea*[0.5,1.2]区间内,则跳过
	//if (circularity < 0.8) {
	//	continue;
	//}
	if (!(targetArea * 0.25 <= area && area <= targetArea * 1.44)) {
		continue;
	}
	reslutContours.push_back(contours[i]);
}
cv::Mat result = cv::Mat::zeros(image.size(), CV_8UC3);
cv::drawContours(result, reslutContours, -1, cv::Scalar(0, 0, 255), 2);

在这里插入图片描述

5. 最后进行圆拟合

if (reslutContours.empty()) { return -1; }
for (auto contour : reslutContours) {
	cv::RotatedRect ellipse = cv::fitEllipse(contour);
	if (origin.channels() == 1)
		cv::cvtColor(origin, origin, cv::COLOR_GRAY2BGR);
	cv::Scalar color(rand() % 256, rand() % 256, rand() % 256);
	cv::ellipse(origin, ellipse, color, 2);
}

在这里插入图片描述
完整代码如下:

void ShowImage(cv::Mat img, bool re = true) {
	cv::namedWindow("Image", cv::WINDOW_AUTOSIZE);
	if (re) {
		cv::resize(img, img, cv::Size(1920, 1080));
	}

	cv::resizeWindow("Image", 1920, 1080);
	cv::imshow("Image", img);

	cv::moveWindow("Image", 0, 0);
	cv::waitKey(0);
}

int main() {
	cv::Mat image = cv::imread("你的图片路径", 0); // 以灰度模式读取图像
	if (image.empty()) { return -1; }
	cv::Mat origin = image.clone();
	ShowImage(image);

	auto start = std::chrono::high_resolution_clock::now();
	cv::Mat element_open = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(17, 17));
	cv::morphologyEx(image, image, cv::MORPH_OPEN, element_open);
	auto end = std::chrono::high_resolution_clock::now();
	std::cout << "open image time: " << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << "ms" << std::endl;
	ShowImage(image);

	start = std::chrono::high_resolution_clock::now();
	cv::Mat element_close = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(7, 7));
	cv::morphologyEx(image, image, cv::MORPH_CLOSE, element_close);
	end = std::chrono::high_resolution_clock::now();
	std::cout << "close image time: " << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << "ms" << std::endl;
	ShowImage(image);

	start = std::chrono::high_resolution_clock::now();
	cv::threshold(image, image, 120, 255, cv::THRESH_BINARY);
	end = std::chrono::high_resolution_clock::now();
	std::cout << "threshold image time: " << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << "ms" << std::endl;
	ShowImage(image);

	start = std::chrono::high_resolution_clock::now();
	cv::Mat kenerl = (cv::Mat_<float>(3, 3) << 0, 1, 0, 1, -4, 1, 0, 1, 0);
	cv::filter2D(image, image, image.type(), kenerl);
	end = std::chrono::high_resolution_clock::now();
	std::cout << "filter2D image time: " << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << "ms" << std::endl;
	ShowImage(image);

	std::vector<std::vector<cv::Point>> contours;
	start = std::chrono::high_resolution_clock::now();
	cv::findContours(image, contours, cv::RETR_TREE, cv::CHAIN_APPROX_SIMPLE);
	end = std::chrono::high_resolution_clock::now();
	std::cout << "findContours image time: " << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << "ms" << std::endl;
	cv::Mat img_contours;
	cv::cvtColor(image, img_contours, cv::COLOR_GRAY2BGR);
	start = std::chrono::high_resolution_clock::now();
	cv::drawContours(img_contours, contours, -1, cv::Scalar(0, 255, 0), 1); // 画出所有轮廓
	end = std::chrono::high_resolution_clock::now();
	std::cout << "drawContours image time: " << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << "ms" << std::endl;
	ShowImage(img_contours);

	float targetArea = 3.14 * 1400 * 1400;
	std::vector<std::vector<cv::Point>> reslutContours;
	start = std::chrono::high_resolution_clock::now();
	// 计算轮廓的面积
	for (size_t i = 0; i < contours.size(); i++) {
		// 计算轮廓的面积和周长
		double area = contourArea(contours[i]);
		double perimeter = arcLength(contours[i], true);
		// 计算圆形度
		double circularity = (4 * 3.1415926 * area) / (perimeter * perimeter);
		// 如果圆形度不满足要求或者面积不在targetArea*[0.5,1.2]区间内,则跳过
		//if (circularity < 0.8) {
		//	continue;
		//}
		if (!(targetArea * 0.25 <= area && area <= targetArea * 1.44)) {
			continue;
		}

		reslutContours.push_back(contours[i]);
	}
	cv::Mat result = cv::Mat::zeros(image.size(), CV_8UC3);
	cv::drawContours(result, reslutContours, -1, cv::Scalar(0, 0, 255), 2);
	end = std::chrono::high_resolution_clock::now();
	std::cout << "draw resultContours image time: " << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << "ms" << std::endl;
	ShowImage(result);

	//cv::RotatedRect ellipse = cv::fitEllipse(contours[maxScoreIndex]);
	if (reslutContours.empty()) { return -1; }
	for (auto contour : reslutContours) {
		cv::RotatedRect ellipse = cv::fitEllipse(contour);
		if (origin.channels() == 1)
			cv::cvtColor(origin, origin, cv::COLOR_GRAY2BGR);
		cv::Scalar color(rand() % 256, rand() % 256, rand() % 256);
		cv::ellipse(origin, ellipse, color, 2);
		ShowImage(origin);
	}

	return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值