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

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

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

  • 前言
  • 一、检测对象
  • 二、检测方法
    • 1.检测圆心和半径
    • 2.求解直线与圆的交点
    • 3.计算圆环残缺比例


前言

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


一、检测对象

点胶区域识别由前序深度学习软件识别,并在示意图中画出深度学习识别的点胶部分,如下图红色连通域。
C++求解圆心、半径、直线与圆交点_第1张图片

二、检测方法

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;
		}
	}

检测效果如下:
C++求解圆心、半径、直线与圆交点_第2张图片

2.求解直线与圆的交点

即计算每一点与圆心连线与圆的交点,可由数字知识推理如下。
C++求解圆心、半径、直线与圆交点_第3张图片
在求解的过程中还需要考虑一些特殊的情况。
比如当直线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));
			}
		}
	}

检测效果如下:
C++求解圆心、半径、直线与圆交点_第4张图片

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;

检测效果如下:
C++求解圆心、半径、直线与圆交点_第5张图片
在这里插入图片描述


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

你可能感兴趣的:(数字图像处理,数学,c++,算法,开发语言)