这样就把原始图像中给定曲线的检测问题转化为寻找参数空间中的峰值问题。霍夫变换于1962年由Paul Hough 首次提出,后于1972年由Richard Duda和Peter Hart推广使用,经典霍夫变换用来检测图像中的直线,后来霍夫变换扩展到任意形状物体的识别,多为圆和椭圆。

1、霍夫线变化

opencv 霍夫直线拟合 霍夫直线变换原理_opencv 霍夫直线拟合

最后通过统计特性来解决问题。假如图像平面上有两条直线,那么最终在参数平面上就会看到两个峰值点,依此类推。

对于看了上述概念描述还没有头绪的可以学习这个PPT

https://wenku.baidu.com/view/18787c768e9951e79b89270e.html?from=search:

下面截了几张图帮助理解:

1)对于空间坐标中的一条直线,相当于是Hough坐标中的一个点

opencv 霍夫直线拟合 霍夫直线变换原理_opencv 霍夫直线拟合_02

2)对于空间坐标中的一个点,相当于是Hough坐标中的一条线

opencv 霍夫直线拟合 霍夫直线变换原理_图像平面_03

3)Hough坐标中两条线的交点用来表示过点(x0,y0)和点(x1,y1)的直线

opencv 霍夫直线拟合 霍夫直线变换原理_图像平面_04


2、OpenCv霍夫变换---在条码识别中的应用

如果rho的值取得很大会导致所拟合的直线满天飞,而rho的值如果取得很小则拟合不出直线。如何设计代码得到最为精确的拟合直线是关键技术。以下方法是:通过逐渐扩大rho的值,而从达到寻找最佳霍夫直线的要求。(通过参数迭代的方式达到自适应寻找直线的效果)

        条码识别的HoughLines可设计为如下代码:

void HoughAngle(Mat FourierImage, Mat &Linemat, float &angelD) 
{
	// HoughLines查找傅里叶频谱的直线,该直线跟原图的一维码方向相互垂直
	vector<Vec2f> lines;
	float pi180 = (float)CV_PI / 180;

	// 取最佳霍夫直线
	double HoughLineRho = 0.1;
	HoughLines(FourierImage, lines, HoughLineRho, pi180, 100, 0, 0);
	
	while (!lines.size() && HoughLineRho < 20)
	{
		HoughLineRho = HoughLineRho + 0.1;
		HoughLines(FourierImage, lines, HoughLineRho, pi180, 100, 0, 0);
	}

	cout << "霍夫直线为: " << lines.size() << endl;

	Linemat = FourierImage.clone();

	// 计算霍夫直线
    float theta = 0;   // 最终theta的取值问题直接影响结果
    
	// 绘制霍夫直线,若没有将霍夫直线拟合出来,则不进行绘制
	for (int l = 0; l < lines.size(); l++) {

		float rho = lines[l][0];
		theta = lines[l][1];
		float aa = (theta / CV_PI) * 180;
		Point pt1, pt2;
		double a = cos(theta), b = sin(theta);
		double x0 = a*rho, y0 = b*rho;
		pt1.x = cvRound(x0 + 1000 * (-b));
		pt1.y = cvRound(y0 + 1000 * (a));
		pt2.x = cvRound(x0 - 1000 * (-b));
		pt2.y = cvRound(y0 - 1000 * (a));

		line(Linemat, pt1, pt2, Scalar(255, 0, 0), 3, 8, 0); // 原图上绘制霍夫变换的曲线
	}

	 //计算霍夫直线的角度,最终theta的取值问题直接影响结果
	if (lines.size()) 
	{
		theta = lines[0][1];
	}

	angelD = 180 * theta / CV_PI - 90;

}