利用OpenCV的霍夫变换线检测函数HoughLines()得到直线的ρ和θ值后绘制直线的原理详解

为了更好地看懂本文,大家可以先看下我写的另一篇博文,链接如下:
https://blog.csdn.net/wenhao_ir/article/details/51774444

OpenCV的霍夫变换线检测函数HoughLines()是利用极坐标下的参数ρ和θ值来表示直线的,我们在实际应用中往往要根据直线的参数ρ和θ值来绘制出直线,那么怎么绘制呢?
在OpenCV中绘制直线的函数为函数line(),它的原型如下:

void cv::line	(	InputOutputArray img,
					Point 	pt1,
					Point 	pt2,
					const Scalar & 	color,
					int 	thickness = 1,
					int 	lineType = LINE_8,
					int 	shift = 0 
				)	

从这个原型中,我们可以看出,如果要使用这个函数绘制线条,那么需要知道线条的两个端点,即参数中的pt1和pt2,所以问题就转化为根据参数ρ和θ值计算要绘制直线的两个端点。
在进行计算前,我们先要搞清楚利用函数HoughLines()得到的θ到底是哪个角的度数。
当直线为水平或垂直时θ的值分别为π/2(即90度)和0(即0度),这个在官方文档中已经说得很清楚了。如下面的截图所示:
在这里插入图片描述
至于其它的情况,我们用两幅图来试验证一下就知道了。
情况一的图片如下:
利用OpenCV的霍夫变换线检测函数HoughLines()得到直线的ρ和θ值后绘制直线的原理详解_第1张图片
情况二的图片如下:
利用OpenCV的霍夫变换线检测函数HoughLines()得到直线的ρ和θ值后绘制直线的原理详解_第2张图片
检测图中两条直线的代码如下:

//博主微信/QQ 2487872782
//有问题可以联系博主交流
//有图像处理需求也可联系博主
//图像处理技术交流QQ群 271891601

//OpenCV版本:3.0
//VS版本:2012

#include 
#include 
#include
#include 

#include 

using namespace cv;
using namespace std;

#define HOUGH_VOTE 100

int main()
{
	cv::Mat srcImg1 = cv::imread("F:/material/images/P0041-HoughLines-angle-01.bmp", 0);//读取原图像并同时转换为灰度图
	if (!srcImg1.data)   
	{
		cout<<"error load image"<<endl;
		return -1;
	}

	vector<Vec2f> lines;
	float pi180 = (float)CV_PI / 180;

	
	HoughLines(srcImg1, lines, 1, pi180, HOUGH_VOTE, 0, 0);
	int numLines = lines.size();

	for (int l = 0; l<numLines; l++)
	{
		float theta = lines[l][1];
		cout <<"检测到的第"<< l+1<<"条线的角度为"<<":" << theta* 180 / CV_PI<< endl;

	}

	waitKey(0);

	return 0;


}

两幅图的检测结果如下:
利用OpenCV的霍夫变换线检测函数HoughLines()得到直线的ρ和θ值后绘制直线的原理详解_第3张图片
这里说明一下为什么检测到多条直线,这是因为我们的直线是有宽度的,所以检测到了多条。
从这个运行结果我们可以看出两种情况下哪个角是θ。如下面两幅图所示:
利用OpenCV的霍夫变换线检测函数HoughLines()得到直线的ρ和θ值后绘制直线的原理详解_第4张图片
情况二:
利用OpenCV的霍夫变换线检测函数HoughLines()得到直线的ρ和θ值后绘制直线的原理详解_第5张图片
知道了哪个角是θ,我们再把其它已知量和待求点及一些辅助线标注在图上,如下面两幅图所示:
利用OpenCV的霍夫变换线检测函数HoughLines()得到直线的ρ和θ值后绘制直线的原理详解_第6张图片
利用OpenCV的霍夫变换线检测函数HoughLines()得到直线的ρ和θ值后绘制直线的原理详解_第7张图片

图中的r就是
由以上几何关系并结合三角函数的和差公式:
利用OpenCV的霍夫变换线检测函数HoughLines()得到直线的ρ和θ值后绘制直线的原理详解_第8张图片
不难得到在两种情况下都有pt1的坐标为:
p t 1. x = x 0 − L s i n ( θ ) = x 0 + ( − L s i n ( θ ) ) pt1.x = x0-Lsin(θ)=x0+(-Lsin(θ)) pt1.x=x0Lsin(θ)=x0+(Lsin(θ))
p t 1. y = y 0 + L c o s ( θ ) pt1.y = y0+Lcos(θ) pt1.y=y0+Lcos(θ)
两种情况下都有pt2的坐标为:
p t 2. x = x 0 + L s i n ( θ ) = x 0 − ( − L s i n ( θ ) ) pt2.x = x0+Lsin(θ)=x0-(-Lsin(θ)) pt2.x=x0+Lsin(θ)=x0(Lsin(θ))
p t 2. y = y 0 − L c o s ( θ ) pt2.y = y0-Lcos(θ) pt2.y=y0Lcos(θ)
其中
x 0 = ρ c o s ( θ ) x0=ρcos(θ) x0=ρcos(θ)
y 0 = ρ s i n ( θ ) y0=ρsin(θ) y0=ρsin(θ)
有了以上计算公式后,我们便可以根据得到的ρ和θ值计算出pt1和pt2的坐标,进而绘制出直线。
相关代码如下:

	HoughLines(magImg, lines, 1, pi180, HOUGH_VOTE, 0, 0);
	int numLines = lines.size();
	int L = 1000;
	for (int l = 0; l<numLines; l++)
	{
		float rho = lines[l][0], theta = lines[l][1];
		Point pt1, pt2;
		double a = cos(theta), b = sin(theta);
		double x0 = a*rho, y0 = b*rho;
		pt1.x = cvRound(x0 + L * (-b));
		pt1.y = cvRound(y0 + L * (a));
		pt2.x = cvRound(x0 - L * (-b));
		pt2.y = cvRound(y0 - L * (a));
		line(linImg, pt1, pt2, Scalar(255, 0, 0), 3, 8, 0);
	}

很明显,上面的代码中,L值是需要我们根据图像的大小和直线的大小来确定,并不是每一幅图像或每一条直线都取1000。L是什么的长度,博主在上面的手绘图中应该是已经标注得很清楚了。

最后,对这篇博文有不明白的可以加博主的微信/QQ 2487872782交流。

你可能感兴趣的