一文解读经典霍夫变换 Hough Transform

介绍

本文描述了霍夫变换的一些内容,补充了一些容易理解的东西,参考了一些博客等相关内容。希望能对霍夫变换有所了解,也希望看到的人发现错误及时帮我纠正。博客作者水平有限,请指教。

和历史介绍。

历史

霍夫变换是1959年由机器分析气泡室而发明的的照片。发明者保罗豪格在1962年获得了一项美国专利,名为“识别复杂图案的方法和手段”。在这个专利中,直线是用斜截距来参数化的,但是斜率可能会变成无穷大,这可能会导致无界的变换空间。

现在使用的霍夫变换是由理查德杜达和彼得哈特在1972年发明的,叫做广义霍夫变换[ght](使用霍夫变换检测图片中的直线和曲线,1972)。

然后在1981年,一篇名为概括小时变换以检测任意形状的文章出现在Dana H. Ballard 的计算机视觉社区,并得到推广。

介绍了利用模板匹配原理对Hough变换的修正。知道霍夫变换最初是为了分析定义的形状(如直线、圆、椭圆等)而开发的。).通过知道它的形状,并旨在找到图像中的位置和方向,这种变化使霍夫变换能够检测到由其模型描述的任何对象。通过找到模型在图像中的位置来解决在该图像中找到对象(由模型描述)的问题。使用广义霍夫变换(GHT),找到模型位置的问题被转化为找到将模型映射到图像的变换参数的问题。给定变换参数的值,可以确定模型在图像中的位置。

后来又产生了更多霍夫变换的变体和扩展,比如KHT和3D KHT,这里就不详细解释了。

简介

霍夫变换是一种特征提取技术。它可以用来分离图像中特定形状的特征,应用于图像分析、计算机视觉和数字图像处理等领域。目的是通过投票程序找到一个特定形状的不完美实例。该投票过程在参数空间中执行,在该参数空间中,候选对象作为所谓的累加器空间中的局部最大值被获得,该累加器空间由用于计算霍夫变换的算法显式地构造。最基本的霍夫变换是从黑白图像中检测直线(线段)。霍夫变换的主要优点是它可以容忍特征边界描述中的间隙,并且相对不受图像噪声的影响。

原则

最简单的霍夫变换是检测直线。我们知道,直线的方程表示可以用斜率和截距来表示(这种表示方法,称为截断形式),如下:

如果用参数空间表示,就是,也就是一条直线可以用斜率和截距来表示。

但这样会造成参数问题,垂直线的斜率不存在(或者是无穷大),使得斜率参数的值接近无穷大。因此,1971年4月,理查德o杜达和彼得e哈特为了更好的计算提出了黑塞范式(Hesse normal form)。

其中是原点到直线上最近点的距离(其他人可能把这个记为,下面,R也可以看成一个参数),轴与连接原点和最近点的直线所成的角度。如图1所示。

图1

因此,图像的每条直线可以与一对参数相关联。这个参数平面有时被称为霍夫空间,用于二维直线的集合。

从概念上讲,霍夫变换和拉冬变换非常接近,有人把它看成是同一变换的不同形式。

在霍夫变换之后,图像空间中的一个点被映射到霍夫空间,如图2所示。

图2

图2:点(3,4)固定时,取角度时取R的取值范围。该图是用matlab绘制的,代码如下

%一个点的坐标是(3,4)

x=3;

y=4;

%将给定的固定点映射到霍夫变换空间。

=0:pi/200:2 * pi;%角度

r=x * cos()y * sin();

plot(,r);%绘图

set(gca,' XTick '[0:pi/10:2 * pi]);%修改X轴坐标间隔

xlabel(可变heta )

雅贝尔(变量r )继续正题,图2是经过定点时的关系。说明在极坐标的极平面上画所有通过定点的直线会得到一条正弦曲线。正弦曲线的形状取决于从点到定义原点的距离。一般正弦曲线越大,振幅越大,反之越小。

所以我们可以得到一个结论,给定平面上的一个单点,那么通过该点的所有直线的集合对应于平面上的正弦曲线,对于该点是唯一的。形成一条直线的一组两点或多点将产生一条正弦曲线,该曲线与该直线的点相交。因此,检测共线点的问题可以转化为寻找共线曲线的问题。

示例1

考虑以下三点,这里显示为黑点。

图3

该图示出了霍夫变换的第一步,三个点和六个可能的角度分组。最左边的图像显示了正在转换的第一个点。首先从不同的角度画线,都经过第一个点。这些用实线表示。其次,对于每一条实线,找出同样平分原点的垂直线(法线,或连接原点垂直于线段的线)。这些用虚线表示。然后求虚线的长度和角度。这些值显示在图表下方的表格中。对三个转换点中的每一个重复该过程。然后把结果画成图,有时叫做霍夫空间图。

图4

这显示了具有三个点和六个可能角度的霍夫空间图。这是上表中数据的简单图表。线条相互交叉的点表示由作为变换输入的三个点形成的线条的角度和距离。

距离和角度在图4所示曲线的交叉点给出。距离和角度表示与测试点相交的直线。在图4中,所示的线在粉色点处相交;这对应于图3中穿过所有三个点的粉红色实线。

在图像分析的背景下,边缘段的点的坐标在图像中是已知的,因此在参数线方程中是常数,并且总和是我们正在寻找的未知变量。如果我们画出每个定义的可能值,笛卡尔图像空间中的点映射到极坐标霍夫参数空间中的曲线(即正弦曲线)。这种点到曲线的变换是直线的霍夫变换。当在霍夫参数空间中观察时,在笛卡尔图像空间中共线的点变得明显,因为它们产生在相同点处相交的曲线。

示例2

以下是显示包含两条粗线的光栅图像的霍夫变换结果的不同示例。

这种转换的结果存储在矩阵中。单元值表示通过任意点的曲线数量。更高的单元值变得更亮。两个明显的亮点是两条线的霍夫参数。根据这些点的位置,可以确定输入图像中两条线的图像中心的角度和距离。

如何用霍夫变换提取直线?实现机制是什么?

这种变换是通过将霍夫参数空间量化成有限的区间或累加器单元来实现的。随着算法的运行,每个算法将数据转换成离散曲线,并且沿着该曲线的累加器单元递增。累加器中产生的峰值表明图像中存在相应的直线。注意,现在我们正在考虑直线的霍夫变换(让暂且不考虑圈子,圈子的情况后面会简单说明)。累加器的维数是二维的(即R和)。

Hough变换检测圆时,累加器是三维累加器,目前不讨论。

然后,对于图像中的每个像素及其邻域,使用Hough变换算法确定该像素是否具有足够的直线证据。如果是,它会计算这一行的参数,然后找到参数所在的累加器框,增加这个框的值(投票值)。通过找到具有最高值的框,通常通过找到累加器空间中的局部最大值,可以提取最可能的线,并且可以读出它们的(近似)几何定义。

找到这些峰值最简单的方法是应用某种形式的阈值,但是其他技术在不同的情况下可能会产生更好的结果——确定要找到哪些行以及有多少行。由于返回的行不包含任何长度信息,通常需要在下一步中找出图像的哪些部分匹配哪些行。此外,由于边缘检测步骤中的缺陷误差,误差通常出现在累加器空间中,这使得找到适当的峰值和适当的线变得非常重要。

线性霍夫变换的最终结果是一个类似累加器的二维数组(矩阵)。矩阵的一维是量化角度,另一维是量化距离r,矩阵的每个元素的值等于位于量化参数所代表的线上的点或像素的总和。因此,具有最高值的元素表示输入图像中最具代表性的直线。在某些论文中,累加器单元的结果可视为投票值。换句话说,每个交点都被视为一个投票,也就是说,所有的点都这样计算出来之后,就可以设置一个阈值,投票大于这个阈值的线就可以被视为找到的直线。下图摘自一篇博客。

分别是原始图像,以及阈值分别为30和20时检测到的直线。对于大于阈值的点,存在具有霍夫空间的参数对。通过逆映射,我们可以得到图像空间中的直线:

实现的例子用于说明描述。

霍夫变换可用于识别最适合给定边缘点集的曲线参数。该边缘描述通常从诸如Roberts Cross、Sobel或Canny边缘检测器的特征检测算子获得,并且可能是有噪声的,即,它可能包含对应于单个整体特征的多个边缘段。此外,由于边缘检测器的输出仅定义特征在图像中的位置,霍夫变换进一步确定哪两个特征(即,检测它们的参数(或其他)特征描述)以及它们中有多少存在于图像中。

为了详细解释霍夫变换,我们从两个封闭矩形的简单图像开始。

简单矩形

这部分边界描述可以通过使用Canny边缘检测器生成,如图8所示。

这里我们看到了图像中的整个边界,但是这个结果没有不要告诉我们这个边界描述中特征的身份(和数量)。在这种情况下,我们可以使用Hough(直线检测)变换来检测图像的八条独立的直线,从而确定物体的真实几何结构。

如果我们将这些边缘/边界点作为霍夫变换的输入,那么在笛卡尔空间中的每个边缘点的极坐标空间中将生成一条曲线。当作为强度图像查看时,累加器阵列如图9所示。

图9

直方图均衡化技术可用于使图像显示低强度像素值中包含的信息模式,如图10所示。

注意,虽然sum是一个概念上的极坐标,但是累加器空间被绘制为一个具有横坐标和纵坐标的矩形。注意,累加器空间围绕图像的垂直边缘,因此实际上只有8个实际峰值。

梯度图像中共线点生成的曲线在霍夫变换空间中相交于峰值。这些交叉点代表原始图像的直线段。有许多方法可以从累加器阵列中提取这些亮点或局部最大值。例如,一种简单的方法包括阈值处理,然后细化累加器阵列图像中孤立的亮点簇。这里,我们使用相对阈值来提取原始图像中每条直线边缘对应的点。(换句话说,我们只使用累加器数组中的那些局部最大值,其值等于或大于全局最大值的固定百分比。)

从霍夫变换空间(即逆霍夫变换)映射回笛卡尔空间产生了图像主题的一组线条描述。通过将该图像叠加在原始反转版本上,我们可以确认霍夫变换找到两个矩形的8条真实边缘的结果,并由此揭示遮挡场景的基本几何形状。

从霍夫变换空间(即逆霍夫变换)映射回笛卡尔空间产生了图像主题的一组线条描述。通过将该图像叠加在原始的反转版本上(参见图11),我们可以确认霍夫变换找到两个矩形的8个真实边缘的结果,从而揭示遮挡场景的基本几何形状。

图11

请注意,在这个简单的例子中,检测到的图像线和原始图像线的对齐精度显然是不完美的,这取决于累加器数组的量化。(还要注意,很多图像边缘都有几条检测线。这是因为附近有几个霍夫空间峰值具有相似的线参数值。有一些技术可以控制这种效果,但是这里没有使用它来说明标准的霍夫变换。)

还要注意,霍夫变换产生的线的长度是无限的。如果我们想要确定产生变换参数的实际线段,我们需要进一步的图像分析,以查看这些无限长的线的哪些部分实际上有点。

为了说明霍夫技术对噪声的鲁棒性,在霍夫变换之前,Canny边缘描述已经被破坏(由椒盐噪声引起),如图12所示。

图12

在霍夫空间中绘制的结果如图13所示。

图13

对这个结果进行反向Hough变换(并将其覆盖在原始结果上,参见图14)。

图14

图14:相对阈值设置为40%。

您可以通过变换图像(使用绘图工具进行编辑,参见图15)来研究霍夫变换对特征边界间隙的敏感性。

图15

然后我们将其转换到霍夫变换空间,如图16所示。

图16

然后使用40%的相对阈值对图像进行反向霍夫变换(也叠加在原始图像上)

图17

在这种情况下,因为累加器空间没有接收前一示例中的条目数,所以只能找到7个峰值,但这些都是结构上相关的行。

前面的例子都不是自然的例子。下面展示的是自然例子的例子。

城市场景

在第一种情况下,我们有一个城市场景,这些建筑物被雾覆盖,如图18所示。

图18

如果我们想找到建筑物的真正边缘,边缘检测器(如Canny)可以不能很好地恢复这些信息,如图19所示。

图19

但是,Hough变换可以检测到一些代表遮挡区域中建筑物边缘的直线。原始图像的直方图均衡化累加器空间表示如图20所示。

图20

如果我们将相对阈值设置为70%,我们将得到如图21所示的反向霍夫变换图像。

图21

这里只能检测到几条长边,并且存在许多重复,其中许多线或边段几乎共线。应用较大的相对阈值(即50%)将产生如图22所示的效果。

图22

将产生更多的预期线,但代价是许多共线边缘碎片产生许多假线。

最后一个例子来自遥感应用。这里,我们想要检测图像中的街道。

遥感应用

图23

图23显示了一个合理的矩形城区。我们可以使用Canny边缘检测器来检测这个图像,如图24所示。

图24

然而,街道信息不能单独用作边缘检测器的输出。

图25示出了霍夫线检测器可以恢复一些这种信息。然而,由于原始图像的对比度差,确定了有限的一组特征(即街道)。

图25

实现算法描述

提取博客的算法描述:

初始化空间,指示该参数所指示的直线上的像素点的数量)

对于每个像素,在参数空间中找到满意的对,然后让

统计所有取出的尺寸和参数(为预设阈值)

但我不我不认为这是一个完整的算法流程。所以我对它的改进描述如下。

读取原始图像转换成灰度图像,使用边缘检测算子(比如Canny)转换成二值边缘图像。

然后对图像执行霍夫变换。

先用峰值检测函数找到大于阈值的霍夫变换单元(局部最大值应该是最可能的直线,步长和量化会影响效果)。

要识别上面提到的一组候选峰,需要确定相关的线段及其起止点(这需要一定的算法,很多论文对其进行了改进,比如蝴蝶形状和宽度,峰廊)。

然后描绘于原图(或结果图)上

代码实现

矩阵实验室版本

原图

图26

%读取图像

I=im read(霍芙。jpg );

% 转换成灰度图

grayI=RGB 2 gray(I);

% 创建二进制图像

BW=edge(grayI,精明);

% 使用二值图像创建踝关节变换。

[H,T,R]=Hough(BW);

imshow(H,[],XData ,T,YData ,R,

初始放大''适合');

xlabel(赫塔),ylabel(

ho’);

轴打开,轴正常,保持;

% 在图像的霍夫变换中查找峰值

P=houghpeaks(H,5,门槛ceil(0.3 * max(H(:)));

x=T(P(:2));y=R(P(:1));

plot(x,y, ,'颜色''白色');

% 找到线条并绘制它们

lines=houghlines(BW,T,R,P,FillGap ,5,'MinLength ,7);

图,imshow(一),坚持住

max _ len=0;

对于k=1:长度(行)

xy=[线条(k)。第一点;线条(k)。第2点];

plot(xy(:1),xy(:2),线宽'2,'颜色''绿色');

% 绘制线条的开始和结束

plot(xy(1,1),xy(1,2),x ,'线宽'2,'颜色''黄色');

plot(xy(2,1),xy(2,2),x ,'线宽'2,'颜色''红色');

% 确定最长线段的端点

len=norm(行(k))。第1点-线条(k)。点2);

if(len max _ len)

最大长度=长度

xy _ long=xy

结束

结束

% 通过为青色着色来突出显示最长的线段

plot(xy_long(:1),xy_long(:2),线宽'2,'颜色''青色');

运行结果

图27

只是个示范使用,参数可自调。

大蟒实现

#!python2

#编码:utf-8

将numpy作为铭牌导入

将matplotlib.pyplot作为plt导入

从skimage.transform导入霍夫线

从skimage.draw导入行

img=np.zeros((100,150),dtype=bool)

img[30,]=1

img[:65]=1

img[35:45,35:50]=1

rr,cc=line(60,130,80,10)

img[rr,cc]=1

img=NP。随机的。随机(img。形状)》0.95

输出,角度,d=霍夫线(img)

fix,axes=plt.subplots(1,2,figsize=(7,4))

坐标轴[0]。imshow(img,cmap=plt.cm.gray)

坐标轴[0]。set _ title(输入图像')

坐标轴[1]。imshow(

out,cmap=plt.cm.bone,

范围=(np.rad2deg(angles[-1]),np.rad2deg(angles[0]),d[-1],d[0])

坐标轴[1]。set _ title(霍夫变换')

坐标轴[1]。set _ xlabel(角度(度)')

坐标轴[1]。set _ y label(距离(像素)')

plt.tight_layout()

plt.show()

运行结果

图28

Opencv实现

opencv的关于霍夫变换提取的函数可以在Opencv的该文档见到Opencv关于houghlines函数博主电脑安装的是opencv2.4.13版本,代码是来自于浅墨大神(毛星云)的代码实现。

//- 【头文件包含部分】 -

//描述:包含程序所依赖的头文件

//-

#包括《opencv2/opencv.hpp》

#包括《opencv2/imgproc/imgproc.hpp》

//- 【命名空间声明部分】 -

//描述:包含程序所使用的命名空间

//-

使用名称空间cv;

//- 【main()函数】 -

//描述:控制台应用程序的入口函数,我们的程序从这里开始

//-

int main()

{

//【1】载入原始图和垫子变量定义

mat src image=im read(1 .jpg );//工程目录下应该有一张名为1.jpg的素材图

Mat midImage,dstImage//临时变量和目标图的定义

//【2】进行边缘检测和转化为灰度图

Canny(srcImage,midImage,50,200,3);//执行这种精明的边缘检测。

cvtColor(midImage,dstImage,CV _ gray 2 bgr);//将边缘检测后的图像转换为灰度图像。

//[3]进行霍夫线变换

向量《Vec2f》行;//定义一个向量结构lines来存储获得的线向量集。

HoughLines(midImage,Lines,1,CV_PI/180,150,0,0);

//[4]依次画出图中各线段。

for(size _ t I=0;I《lines . size();我)

{

float=lines[I][0],theta=lines[I][1];

点pt1,pt2

双a=cos(),b=sin();

double x0=a*rho,y0=b * rho

pt1 . x=cv round(x0 1000 *(-b));

pt1 . y=cv round(y0 1000 *(a));

pt2 . x=cv round(x0-1000 *(-b));

pt2 . y=cv round(y0-1000 *(a));

line(dstImage,pt1,pt2,Scalar(55,100,195),1,CV _ AA);

}

//[5]显示原图。

im show(原图,srcImage);

//[6]边缘检测后的图像

im show(边缘检测后的图像,midImage);

//[7]展示效果图

im show(效果图,dst image);

wait key(0);

返回0;

}

运行结果

图30

利用浅层Tikhov变换提取圆

我们可以使用相同的程序来检测具有分析描述的其他特征。例如,在圆的情况下,参数方程为

其中a和b是圆心的坐标,是半径。在这种情况下,算法的计算复杂度开始增加,因为我们现在有了参数空间中的三个坐标和三维累加器。(一般情况下,累加器数组的计算量和大小会随着参数数量的增加而增加,因此基本的Hough技术只适用于简单的曲线。)

步骤

其算法步骤如下:

首先,创建由每个像素单元组成的累加器空间。最初,每个单元格被设置为0。

然后,对于每个图像中的边缘点,根据圆方程累积可能是圆心的单元值。这些细胞在方程式中用字母A表示。

然后,在前面的步骤中,从每个可能值A中,找到满足等式的所有可能值B。

在累加器空间中搜索局部最大值。这些单元格表示算法检测到的圆。如果我们不如果不知道预先定位的圆的半径,我们可以使用三维累加器空间来搜索任意半径的圆。当然,这在计算上更昂贵。

这种方法也可以检测部分在累加器空间之外的圆,只要在圆区域中有足够多的圆。

霍夫变换提取圆的几个实现环节

详细说明:关于Hough变换提取圆的matlab

Matlab圆提取(https://ww2.mathworks.cn/help/images/ref/imfindcircles.html)

详细说明:关于opencv的提取圆(给出了C,C和Python)

Opencv关于圆提取的官方文档(detection.html https://docs.opencv.org/2.4/modules/imgproc/doc/feature?突出显示=HoughCircles)

-python实现了提取圆

Python圆提取(https://scikit-image.org/docs/dev/api/skimage.transform.html)

浅层广义霍夫变换

当我们希望孤立特征的形状没有描述其边界的简单解析方程时,我们使用广义霍夫变换。在这种情况下,我们不使用曲线的参数方程,而是使用查找表来定义边界位置和方向与霍夫参数之间的关系。(在初始阶段,您必须使用原型形状来计算查找表值。)

例如,假设我们知道所需特征的形状和方向。(见下图)我们可以在特征中指定一个任意的参考点,它定义了特征的形状(即R从边界到这个参考点法线的距离和角度)。我们的查找表(即R表)将由这些距离和方向对组成,由边界的方向索引。

图31

图31:R表组件描述。

霍夫变换空间现在根据形状在图像中的可能位置,即可能范围来定义。换句话说,转换被定义为:

(对于特定的已知方向,值之和来自表中的值)。如果所需特征的方向未知,则过程变得复杂,因为我们必须通过引入额外的参数来扩展累加器以考虑方向。

基本霍夫变换的局限性

霍夫变换仅在大量选票落入正确的箱中时有效,因此箱可以容易地在背景噪声中被检测到。这意味着箱子不能太小,否则一些选票会落入相邻的箱子中,从而降低主箱子的可见性。

此外,当参数数量较大时(即我们使用通常超过三个参数的Hough变换时),单个盒子中的平均投票数很低,这些盒子对应的实际数字在图像中的投票数不一定比它们的邻居多得多。复杂度以一定的速率增加,其中每个附加参数是图像空间的大小,m是参数的数量。因此,必须非常小心地使用霍夫变换来检测除了直线或圆之外的任何东西。

最后,Hough变换的效率大部分取决于输入数据的质量:为了使Hough变换高效,需要进行边缘检测。在噪声图像上使用Hough变换是一个非常困难的问题。一般来说,降噪阶段必须在之前使用。当图像被斑点损坏时(如在雷达图像中),Radon变换有时更适合于检测线,因为它通过求和来衰减噪声。

标签

这篇博文主要讲述了基本的经典霍夫变换,描述了霍夫变换如何提取直线及其原理,展示了一些例子和代码实现,也展开了霍夫变换的一些简单描述,希望能成为读者的参考。

japan quarterly 日本季刊