图像处理之霍夫变换

本文详细介绍了霍夫变换的基本原理,包括直角坐标和极坐标下的直线表示,以及如何利用霍夫变换进行直线检测。通过实例展示了在OpenCV中应用霍夫变换检测图像中的直线,并提供了相关代码示例。此外,还提到了霍夫变换在解决垂直直线表示问题上的应用。
摘要由CSDN通过智能技术生成

图像处理之霍夫(Hough)变换

4、说一下霍夫(Hough)变换原理

答:霍夫(Hough)变换是一个非常重要的检测间断点边界形状的方法。它通过将图像坐标空间变换到参数空间,来实现直线和曲线的拟合。

直线检测

1.1 直线坐标参数空间

在图像x−y坐标空间中,经过点(xi,yi)的直线表示为:

yi = a*xi + b        (1)

其中,参数a为斜率,b为截矩。

通过点(xi,yi)的直线有无数条,且对应于不同的a和b值。

如果将xi和yi视为常数,而将原本的参数a和b看作变量,则式子(1)可以表示为:

b = −xi*a + yi         (2)

这样就变换到了参数平面a−b。这个变换就是直角坐标中对于(xi,yi)点的Hough变换。该直线是图像坐标空间中的点(xi,yi)在参数空间的唯一方程。考虑到图像坐标空间中的另一点(xj,yj),它在参数空间中也有相应的一条直线,表示为:

b = −xj*a + yj         (3)

这条直线与点(xi,yi)在参数空间的直线相交于一点(a0,b0),而(a0,b0)就是图像坐标空间中点(xi,yi)和点(xj,yj)所确定的直线的参数。反之,在参数空间中相交于同一点的所有直线,在图像坐标空间中都有贡献的点与之对应。根据这个特性,给定图像坐标空间的一些边缘点,就可以通过Hough变换确定连接这些点的直线方程。如图所示:

 具体计算时,可以将参数空间视为离散的。建立一个二维累加数组A(a,b),第一维的范围是图像坐标空间中直线斜率的可能范围,第二维的范围是图像坐标空间中直线截矩的可能范围。开始时A(a,b)初始化为0,然后对图像坐标空间的每一个前景点(xi,yi),将参数空间中每一个a的离散值代入式子(2)中,从而计算出对应的b值。每计算出一对(a,b),都将对应的数组元素A(a,b)加1,即A(a,b)=A(a,b)+1。所有的计算结束之后,在参数计算表决结果中找到A(a,b)的最大峰值,所对应的a0、b0就是源图像中共线点数目最多(共A(a,b)个共线点)的直线方程的参数;接下来可以继续寻找次峰值和第3峰值和第4峰值等等,它们对应于原图中共线点略少一些的直线。

【在直线坐标系下共线的点,在参数空间中都相交于同一点。】

注意:使用直角坐标表示直线,当直线为一条垂直直线或者接近垂直直线时,该直线的斜率为无限大或者接近无限大,从而无法在参数空间a-b上表示出来。为了解决这个问题,可以采用极坐标系。

1.2 极坐标参数空间

极坐标中用如下参数方程表示一条直线:

ρ = x*cosθ + y*sinθ      (4)

其中,ρ代表直线到原点的垂直距离,θ代表x轴到直线垂线的角度,取值范围为±90∘如下图所示。

 与直角坐标类似,极坐标中的Hough变换也将图像坐标空间中的点变换到参数空间中。在极坐标表示下,图像坐标空间中共线的点变换到参数空间中后,在参数空间都相交于同一点,此时所得到的 ρ、θ 即为所求的直线的极坐标参数。与直角坐标不同的是,用极坐标表示时,图像坐标空间的共线的两点(xi,yi)和(xj,yj)映射到参数空间是两条正弦曲线,相交于点(ρ0,θ0),如上图所示。

具体计算时,与直角坐标类似,也要在参数空间中建立一个二维数组累加器A,只是取值范围不同。对于一副大小为D×D的图像,通常

 计算方法与直角坐标系中累加器的计算方法相同,最后得到最大的A所对应的(ρ,θ)。

OpenCV代码示例:

// 霍夫直线检测.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"

#include <iostream>

using namespace cv;
using namespace std;

static void help()
{
	cout << "\nThis program demonstrates line finding with the Hough transform.\n"
		"Usage:\n"
		"./houghlines <image_name>, Default is pic1.png\n" << endl;
}

int _tmain(int argc, _TCHAR* argv[])
{
	//Mat src = imread("../pic1.png", 1);
	Mat src = imread("../road1.jpg", 0);
	if(src.empty())
	{
		help();
		cout << "can not open ../pic1.png" << endl;
		return -1;
	}
	cout << "src.channels = " << src.channels() << endl;
	namedWindow("source", 0);
	imshow("source", src);
	waitKey();

	Mat mat_binary;
	// binary
	cv::threshold(src, mat_binary, 0, 255.0, cv::THRESH_BINARY | cv::THRESH_OTSU);
	namedWindow("binary", 0);
	imshow("binary", mat_binary);
	waitKey();

	Mat dst, cdst;
	Canny(mat_binary, dst, 50, 200, 3); //边缘检测后的图像为灰度图
	cout << "canny_dst.channels = " << dst.channels() << endl;
	cvtColor(dst, cdst, COLOR_GRAY2BGR);

#if 0
	vector<Vec2f> lines;
	HoughLines(dst, lines, 1, CV_PI/180, 100, 0, 0 ); //标准霍夫变换

	for( size_t i = 0; i < lines.size(); i++ )
	{
		float rho = lines[i][0], theta = lines[i][1];
		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( cdst, pt1, pt2, Scalar(255,0,0), 1, CV_AA);
	}
#else
	vector<Vec4i> lines;
	
	//累计概率霍夫变换
	HoughLinesP(
		dst, //输入图像,需为8位单通道二进制图像
		lines, //存储检测到的线条的输出矢量
		1, //以像素为单位的距离精度,直线搜索时的进步尺寸的单位半径
		CV_PI/180, //以弧度为单位的角度精度,直线搜索时的进步尺寸的单位角度
		100, //累加平面的阈值参数
		100, //最低线段的长度
		60 ); //允许将同一行点与点之间连接起来的最大距离
	for( size_t i = 0; i < lines.size(); i++ )
	{
		Vec4i l = lines[i];
		line( cdst, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(0,0,255), 1, CV_AA);
	}
#endif
	imwrite("houghLine.jpg", dst);

	namedWindow("detected lines", 0);
	imshow("detected lines", cdst);
	waitKey();

	return 0;
}

还没看明白的,可参考此处霍夫变换直线检测(Line Detection)原理及示例_leonardohaig的博客-CSDN博客_霍夫直线检测,该博主写的还不错。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值