霍夫变换的原理 及 一种参数迭代的自适应寻找最佳霍夫直线的代码(在条码识别中的应用)

       霍夫变换(Hough Transform)是一种识别几何形状的方法!霍夫变换的基本原理是利用点与线的对偶性,将原始图像空间的给定的曲线通过曲线表达形式变为参数空间的一个点。这样就把原始图像中给定曲线的检测问题转化为寻找参数空间中的峰值问题。霍夫变换于1962年由Paul Hough 首次提出,后于1972年由Richard Duda和Peter Hart推广使用,经典霍夫变换用来检测图像中的直线,后来霍夫变换扩展到任意形状物体的识别,多为圆和椭圆。

1、霍夫线变化

       设已知一黑白图像上画了一条直线,要求出这条直线所在的位置。我们知道,直线的方程可以用y=k*x+b 来表示,其中k和b是参数,分别是斜率和截距。过某一点(x0,y0)的所有直线的参数都会满足方程y0=kx0+b。即点(x0,y0)确定了一族直线。方程y0=kx0+b在参数k--b平面上是一条直线,(你也可以是方程b=-x0*k+y0对应的直线)。这样,图像x--y平面上的一个前景像素点就对应到参数平面上的一条直线。我们举个例子说明解决前面那个问题的原理。设图像上的直线是y=x, 我们先取上面的三个点:A(0,0), B(1,1), C(2,2)。可以求出,过A点的直线的参数要满足方程b=0, 过B点的直线的参数要满足方程1=k+b, 过C点的直线的参数要满足方程2=2k+b, 这三个方程就对应着参数平面上的三条直线,而这三条直线会相交于一点(k=1,b=0)。 同理,原图像上直线y=x上的其它点(如(3,3),(4,4)等) 对应参数平面上的直线也会通过点(k=1,b=0)。这个性质就为我们解决问题提供了方法,就是把图像平面上的点对应到参数平面上的线,最后通过统计特性来解决问题。假如图像平面上有两条直线,那么最终在参数平面上就会看到两个峰值点,依此类推。

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

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

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

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


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


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



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

        霍夫变换在OpenCV中的函数名称为HoughLines,其中最为关键的是设置其第三个参数rho,对于傅里叶变换后的图像要拟合霍夫直线,如果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;

}





  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值