C++求解圆心、半径、直线与圆交点

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

最近测试了一个检测项目,需要检测出手机后置摄像头孔洞圆环周边是否全部点胶,并计算点胶完成的百分比。


一、检测对象

点胶区域识别由前序深度学习软件识别,并在示意图中画出深度学习识别的点胶部分,如下图红色连通域。
在这里插入图片描述

二、检测方法

1.检测圆心和半径

主要方法是调用霍夫圆检测函数,并根据机械定位和先验信息约束正解。

	Mat src = imread("..\\data\\0.jpg", 1);//输入图
	Mat srcdisplay = Mat::zeros(src.rows, src.cols, CV_8UC1);
	vector<Mat> channels;
	split(src, channels);
	Mat heightMapRed = channels.at(2);
	//1检测圆心半径
	Mat srcgray;
	cvtColor(src, srcgray, COLOR_RGB2GRAY);
	double circle_R = 0;
	double perimeter = 0;
	double circlearea = 0;
	vector<Vec3f> circles;
	Point circle_center;
	HoughCircles(srcgray, circles, HOUGH_GRADIENT, 1, 200, 100, 30, 800, 1200);
	for (size_t i = 0; i < circles.size(); i++)
	{
		Point center((circles[i][0]), (circles[i][1]));
		int radius = (circles[i][2]);
		if (center.x <2200 && center.x > 1800 && center.y < 1900 && center.y > 1500 && radius > 900 && radius < 1100)
		{
			circle_R = radius + 12;
			circle_center = center;
			cout << "圆心X=" << center.x << "   " << "圆心Y=" << center.y << "   " << "半径R=" << radius << endl;
			circle(src, center, 3, Scalar(255, 255, 255), -1, 8, 0);
			perimeter = 6.28 * circle_R;
			circlearea = 3.14 * circle_R * circle_R;
		}
	}

检测效果如下:
在这里插入图片描述

2.求解直线与圆的交点

即计算每一点与圆心连线与圆的交点,可由数字知识推理如下。

在求解的过程中还需要考虑一些特殊的情况。
比如当直线k值不存在,即x坐标等于圆心坐标时,y坐标可由圆心y坐标和半径直接计算;
当有两个坐标解时,可根据x坐标与圆心坐标大小来判断哪个是需要的解。
具体实现代码如下:

//2读取坐标文件
	vector <Point> circlepoint;
	for (int x = 0; x < srcgray.rows; x++)
	{
		for (int y = 0; y < srcgray.cols; y++)
		{
			if (heightMapRed.at<uchar>(x, y) == 255)
				circlepoint.push_back(Point(y, x));
		}
	}
	//3求圆和线交点
	vector <Point> reflectepoint;
	double k = 0;
	double b = 0;
	double a = 0;
	double b1 = 0;
	double c = 0;
	double dlta = 0;
	double x1, y1, x2, y2;
	for (int i = 0; i < circlepoint.size(); i++)
	{
		if (circlepoint[i].x < circle_center.x)
		{
			k = (double)(circlepoint[i].y - circle_center.y) / (circlepoint[i].x - circle_center.x);
			b = (circle_center.y - k * circle_center.x);
			a = k * k + 1;
			b1 = 2 * k * b - 2 * k * circle_center.y - 2 * circle_center.x;
			c = circle_center.x * circle_center.x - circle_R * circle_R + (b - circle_center.y) * (b - circle_center.y);
			dlta = b1 * b1 - 4 * a * c;
			if (dlta >= 0)
			{
				x1 = (-b1 - sqrt(dlta)) / (2 * a);
				x2 = (-b1 + sqrt(dlta)) / (2 * a);
				y1 = k * x1 + b;
				y2 = k * x2 + b;
				if (x1 < circle_center.x)
				{
					reflectepoint.push_back(Point(x1, y1));
				}
				if (x2 < circle_center.x)
				{
					reflectepoint.push_back(Point(x2, y2));
				}
			}
		}
		else if (circlepoint[i].x > circle_center.x)
		{
			k = (double)(circlepoint[i].y - circle_center.y) / (circlepoint[i].x - circle_center.x);
			b = (circle_center.y - k * circle_center.x);
			a = k * k + 1;
			b1 = 2 * k * b - 2 * k * circle_center.y - 2 * circle_center.x;
			c = circle_center.x * circle_center.x - circle_R * circle_R + (b - circle_center.y) * (b - circle_center.y);
			dlta = b1 * b1 - 4 * a * c;
			if (dlta >= 0)
			{
				x1 = (-b1 - sqrt(dlta)) / (2 * a);
				x2 = (-b1 + sqrt(dlta)) / (2 * a);
				y1 = k * x1 + b;
				y2 = k * x2 + b;
				if (x1 > circle_center.x)
				{
					reflectepoint.push_back(Point(x1, y1));
				}
				if (x2 > circle_center.x)
				{
					reflectepoint.push_back(Point(x2, y2));
				}
			}
		}
		else
		{
			if (circlepoint[i].y < circle_center.y)
			{
				reflectepoint.push_back(Point(circlepoint[i].x, circle_center.y - circle_R));
			}
			if (circlepoint[i].y > circle_center.y)
			{
				reflectepoint.push_back(Point(circlepoint[i].x, circle_center.y + circle_R));
			}
		}
	}

检测效果如下:
在这里插入图片描述

3.计算圆环残缺比例

通过第二步计算得到参考圆上对应交点所围成的扇形面积与圆面积比例映射出残缺圆环所占比例

//4画出映射点
	for (int i = 0; i < reflectepoint.size(); i++)
	{
		line(src, reflectepoint[i], reflectepoint[i], Scalar(255, 255, 255), 3);
	}
	//imwrite("1.jpg", src);
	for (int i = 0; i < reflectepoint.size(); i++)
	{
		line(srcdisplay, reflectepoint[i], circle_center, Scalar(255, 255, 255), 1);
		line(src, reflectepoint[i], circle_center, Scalar(255, 255, 255), 1);

	}

	//5预处理 
	Mat element = getStructuringElement(MORPH_RECT, Size(7, 7));
	dilate(src, src, element);
	//imwrite("2.jpg", src);
	dilate(srcdisplay, srcdisplay, element);
	int bowarea = 0;
	int temp = 0;
	for (int x = 0; x < srcdisplay.rows; x++)
	{
		for (int y = 0; y < srcdisplay.cols; y++)
		{
			temp = srcdisplay.at<uchar>(x, y);
			if (temp == 255)
				bowarea++;
		}
	}
	double factor = bowarea / circlearea;
	cout <<"残缺圆环占比:"<< 1 - factor << endl;

检测效果如下:
在这里插入图片描述
在这里插入图片描述


总的来说,方法思路还是很简单普通的,但代码实现起来可能有点繁琐,需要考虑特殊情况来提高代码鲁棒性和计算的准确性。
相关图片和源代码可在https://github.com/chaochaojnu下载

  • 4
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值