霍夫变换激光线中心提取(基于opencv)

霍夫变换激光线中心提取(基于opencv)

  • 更新:
  • 效果:
  • 步骤:
    • 1.图片预处理,参数可以自己调整
    • 2.霍夫变换,画直线
    • 3.获取四个坐标
    • 4.计算交点
    • 5.画圆圈
  • 不足:
    • 1.可以看到一些误差
    • 2.无直线没有判断
  • 参考博客:

更新:

2018.11.16:
代码已上传:https://download.csdn.net/download/qq_38269418/10788619
平台:
VS2017
C++
OPENCV3库

效果:

原图
霍夫变换激光线中心提取(基于opencv)_第1张图片
结果:
霍夫变换激光线中心提取(基于opencv)_第2张图片
原图:
霍夫变换激光线中心提取(基于opencv)_第3张图片
结果:
霍夫变换激光线中心提取(基于opencv)_第4张图片

步骤:

1.图片预处理,参数可以自己调整

	//边缘检测
	Canny(srcImage, dstImage, 210, 250, 3);
	//灰度化
	cvtColor(midImage, dstImage, CV_GRAY2BGR);

霍夫变换激光线中心提取(基于opencv)_第5张图片

2.霍夫变换,画直线

// 定义矢量结构存放检测出来的直线
	vector<Vec2f> lines;
	//通过这个函数,我们就可以得到检测出来的直线集合了
	HoughLines(midImage, lines, 1, CV_PI / 180, 300, 0, 0);
	//这里注意第五个参数,表示阈值,阈值越大,表明检测的越精准,速度越快,得到的直线越少(得到的直线都是很有把握的直线)
	//这里得到的lines是包含rho和theta的,而不包括直线上的点,所以下面需要根据得到的rho和theta来建立一条直线

	//依次画出每条线段
	for (size_t i = 0; i < lines.size(); i++)
	{
		double rho = lines[i][0]; //就是圆的半径r
		double theta = lines[i][1]; //就是直线的角度
		Point pt1, pt2;
		double a = cos(theta), b = sin(theta);
		double x0 = a * rho, y0 = b * rho;
		/*cout << pt1.y << "asd" << pt2.y<<"jiaodu"<< theta<<"zhi"<
		pt1.x = cvRound(x0 + 800 * (-b));   // + - 800是为了我换下面的线
		pt1.y = cvRound(y0 + 800 * (a));
		pt2.x = cvRound(x0 - 800 * (-b));
		pt2.y = cvRound(y0 - 800 * (a));

		line(dstImage, pt1, pt2, Scalar(0, 100, 195), 2); 
	}

霍夫变换激光线中心提取(基于opencv)_第6张图片

3.获取四个坐标

很简单,横着的线theta>1.57, 竖着的0 把值赋给坐标

		if (theta > 0 && theta < 1.57)
		{

			y1 = pt1.y;
			y2 = pt2.y;
			x1 = pt1.x;
			x2 = pt2.x;
		}
		if (theta >= 1.57 || theta == 0)
		{
			/*cout << pt1;
			cout << pt2;
			cout << pt2.x;*/
			x3 = pt2.x;
			x4 = pt1.x;
			y3 = pt2.y;
			y4 = pt1.y;
		}

在这里插入图片描述

4.计算交点

虽然是八个坐标,但我只用了其中四组,后面会讲到。
输入四组点,就可以返回交点了

CvPoint CrossPoint(const CvPoint line1, const CvPoint line2, const CvPoint line3, const CvPoint line4) //交点
{
	double x_member, x_denominator, y_member, y_denominator;
	CvPoint cross_point;
	x_denominator = line4.x*line2.y - line4.x*line1.y - line3.x*line2.y + line3.x*line1.y
		- line2.x*line4.y + line2.x*line3.y + line1.x*line4.y - line1.x*line3.y;

	x_member = line3.y*line4.x*line2.x - line4.y*line3.x*line2.x - line3.y*line4.x*line1.x + line4.y*line3.x*line1.x
		- line1.y*line2.x*line4.x + line2.y*line1.x*line4.x + line1.y*line2.x*line3.x - line2.y*line1.x*line3.x;

	if (x_denominator == 0)
		cross_point.x = 0;
	else
		cross_point.x = x_member / x_denominator;

	y_denominator = line4.y*line2.x - line4.y*line1.x - line3.y*line2.x + line1.x*line3.y
		- line2.y*line4.x + line2.y*line3.x + line1.y*line4.x - line1.y*line3.x;

	y_member = -line3.y*line4.x*line2.y + line4.y*line3.x*line2.y + line3.y*line4.x*line1.y - line4.y*line3.x*line1.y
		+ line1.y*line2.x*line4.y - line1.y*line2.x*line3.y - line2.y*line1.x*line4.y + line2.y*line1.x*line3.y;
		+ line1.y*line2.x*line4.y - line1.y*line2.x*line3.y - line2.y*line1.x*line4.y + line2.y*line1.x*line3.y;

	if (y_denominator == 0)
		cross_point.y = 0;
	else
		cross_point.y = y_member / y_denominator;

	return cross_point;  //平行返回(0,0)
}

5.画圆圈

	Point e1, e2, e3, e4, u;
	e1 = Point(x1, y1);
	e2 = Point(x2, y2);
	e3 = Point(x3, y3);
	e4 = Point(x4, y4);
	u = CrossPoint(e1, e2, e3, e4);
	circle(srcImage, u, 25, (53, 91, 233), 4, 3);
	imshow("result", srcImage);

霍夫变换激光线中心提取(基于opencv)_第7张图片
完成

不足:

1.可以看到一些误差

理想状态是只有两条线,直接取得中点,但是有时候激光太粗了。每条激光有2条直线,我都取得最后一条,所以导致结果实际中点在这里(黑点处)
霍夫变换激光线中心提取(基于opencv)_第8张图片

2.无直线没有判断

如果没有检测到直线,程序就崩了,想改进可以加一个没检测到直线后的操作就ok
如果要改进的画的精度有很多办法,比如:
1.找到四个交点,取四个交点的中心
2.或者去多条平行直线的中线再,剩2条直线再做计算

参考博客:

https://www.cnblogs.com/skyfsm/p/6881686.html
https://blog.csdn.net/Tron_future/article/details/77828665

博主只是选修课,就不继续费心改进了。
有问题可以评论区交流。
过几天放代码

你可能感兴趣的:(opencv)