霍夫变换(直线检测算法)

时间:2022-10-07 15:19:27

霍夫变换是图像变换中的经典手段之一,主要用来从图像中分离出具有某种相同特征的几何形状(如直线,圆等)。霍夫变换寻找直线与圆的方法相比其他方法可以更好的减少噪声干扰。经典的霍夫变换常用来检测直线、圆、椭圆等。

在实际应用中,y=k*x+b形式的 直线方程 没有办法表示x=c形式的直线(这时候, 直线的斜率 为无穷大)。所以实际应用中,是采用 参数方程 p=x*cos(theta)+y*sin(theta)。这样,图像平面上的一个点就对应到参数p---theta平面上的一条 曲线 上。其它的还是一样。

霍夫变换算法思想:

以直线检测为例,每个像素坐标点经过变换都变成都直线特质有贡献的统一度量,一个简单

的例子如下:一条直线在图像中是一系列离散点的集合,通过一个直线的离散极坐标公式,

可以表达出直线的离散点几何等式如下:

X *cos(theta) + y * sin(theta)  = r 其中角度theta指r与X轴之间的夹角,r为到直线几何垂

直距离。任何在直线上点,x, y都可以表达,其中 r, theta是常量。该公式图形表示如下:

霍夫变换(直线检测算法)

然而在实现的图像处理领域,图像的像素坐标P(x, y)是已知的,而r, theta则是我们要寻找的变量。如果我们能绘制每个(r, theta)值根据像素点坐标P(x, y)值的话,那么就从图像笛卡尔坐标系统转换到极坐标霍夫空间系统,这种从点到曲线的变换称为直线的霍夫变换。变换通过量化霍夫参数空间为有限个值间隔等分或者累加格子。当霍夫变换算法开始,每个像素

坐标点P(x, y)被转换到(r, theta)的曲线点上面,累加到对应的格子数据点,当一个波峰出现时候,说明有直线存在。



OPENCV霍夫变换使用方法——边缘检测+霍夫变换求出图像中的直线

霍夫变换(直线检测算法)
p205霍夫变换



openCV中文论坛中的霍夫变换教程:
霍夫线变换
1.霍夫线变换是一种用来寻找直线的方法。
2.用霍夫变换之前,首先要对图像进行边缘检测的处理,也即霍夫线变换的直接输入只能是边缘二值图像。
它是如何实现的?
1.众所周知,一条直线在图像二维空间可由两个变量表示。
a。在笛卡尔坐标系:可由参数:(m,b)斜率和截距表示
b。在极坐标系:可由参数:(r,θ)极径和极角表示
对于霍夫变换,我们将用极坐标系来表示直线。因此直线的表达式可为:
霍夫变换(直线检测算法)化简得:r = x cos θ + y sinθ
2.一般来说对于点(x0,y0),我们可以将通过这个点的一族直线统一定义为: 霍夫变换(直线检测算法)
这就意味着每一对(r θ θ)代表一条通过(x0,y0)的直线。
3.如果对于一个给定点(x0,y0)我们在极坐标对极径极角平面绘出所有通过它的直线,将得到一条正弦曲线。例如,对于给定点x0 = 8,y0 = 6,我们可以绘出下图:
霍夫变换(直线检测算法)
4.我们可以对图像中所有的点进行上述操作。如果两个不同点进行上述操作后得到的曲线在平面θ-r相交,这就意味着它们通过同一条直线。
eg。接着上面的例子我们继续对点:x1 = 9, y1 = 4 和点 x2 = 12,y2 = 3绘图,得到下图
霍夫变换(直线检测算法)
这三条曲线在θ-r平面相交于点(0.925, 9.6)。
5.以上材料说明什么呢?这意味着一般来说,一条直线能够通过在平面θ-r寻找教育一点的曲线数量来检测。越多曲线交于一点也就意味着这个交点表示的直线由更多的点组成。一般来说我们可以通过设置直线上点的阈值来定义,多少条曲线交于一点我们才认为是检测到了一条直线。
6.这就是霍夫变换要做的,它追踪图像中每个点对应曲线间的交点。如果交于一点的曲线的数量超过了阈值,那么可以认为这个交点所代表的参数对(θ,r θ)在原图像中为一条直线。

标准霍夫线变换和统计概率霍夫线变换:
openCV实现了以下两种霍夫线变换:
a。标准霍夫线变换
原理在上面的部分已经说明了。他能给我们提供一组参数对(θ,r θ)的集合来表示检测到的直线
在OpenCV中,通过函数HoughLines来实现
b。统计概率霍夫线变换
这是执行起来效率更高的霍夫线变换。它输出检测到的直线的端点(x0,y0,x1,y1
在OpenCv中,它通过函数HoughLinesP来实现

实现过程:
1.加载图片
Mat src = imread(filename, 0);
if(src.empty())
{
  help();
  cout << "can not open " << filename << endl;
  return -1;
}
2.用Canny算子对图像进行边缘检测
Canny(src, dst, 50, 200, 3);
3.标准霍夫线变换
a。首先,要执行变换
vector<Vec2f> lines;
HoughLines(dst, lines, 1, CV_PI/180, 100, 0, 0 );
带有以下自变量:
dst:边缘检测的输出图像。它应该是个灰度图,但事实上是个二值化图。
lines:存储着检测到的直线的参数对(r, θ)的容器。 
*rho:参数极径r 以像素值为单位的分辨率。我们使用1像素。
theta:参数极角 θ以弧度为单位的分辨率。我们使用1度(即CV_PI/180)
threshold:要检测出一条直线所需最少的曲线交点
srn and stn:参数默认为零。
b。通过画出检测到的直线来显示结果。
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(0,0,255), 3, CV_AA);
}
4.统计概率霍夫变换
a。首先,要执行变换
vector<Vec4i> lines;
HoughLinesP(dst, lines, 1, CV_PI/180, 50, 50, 10 );
带有以下自变量:
dst:边缘检测的输出图像。它应该是个灰度图,但事实上是个二值化图。
lines:储存着检测到的直线的参数对(x start,y start,x end,y end)的容器
rho:参数极径r 以像素值为单位的分辨率。我们使用1像素。
theta:参数极角 θ以弧度为单位的分辨率。我们使用1度(即CV_PI/180)
threshold:要检测出一条直线所需最少的曲线交点
*minLinLength:能组成一条直线的最少点的数量。点数量不足的直接将被抛弃。
maxLineGap:能被认为在一条直线上的亮点的最大距离。
b。通过画出检测到的直线来显示结果。
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), 3, CV_AA);
}