引言

霍夫变换(Hough Transform)是一种常用于图像处理和计算机视觉中的特征提取技术,主要用于检测特定形状,如直线、圆和椭圆等。
本文基于Python语言,记录了本人霍夫变换直线检测的学习步骤。

原理介绍

霍夫变换(Hough Transform)是一种基于参数空间投票的图像处理方法,在直线检测中,霍夫变换的核心思想是将图像中的点从笛卡尔空间映射到霍夫空间,并通过累积投票的方式来找到直线。

1 数据准备

在笛卡尔坐标系内可以用 y = k x + b y = kx + b y=kx+b表达式来表示一条直线。我们首先绘制一条 k = 1 k=1 k=1 b = 1 b=1 b=1的直线,即 y = x + 1 y = x + 1 y=x+1
同时,我们在直线上选取三个点 ( x 1 , y 1 ) (x_1,y_1) (x1,y1) ( x 2 , y 2 ) (x_2,y_2) (x2,y2) ( x 3 , y 3 ) (x_3,y_3) (x3,y3),三个点的坐标分别为 ( 1 , 2 ) (1,2) (1,2) ( 2 , 3 ) (2,3) (2,3) ( 3 , 4 ) (3,4) (3,4)
下面我们就使用霍夫变换来检测这条直线。
在这里插入图片描述

2 空间变换

霍夫变换中最重要的思想就是将笛卡尔空间内的点转到霍夫空间,其中霍夫空间是指的一种参数空间的概念。
针对直线表达式 y = k x + b y = kx + b y=kx+b,在笛卡尔空间内认为是描述因变量y随着自变量x变化而变化的关系式。
现在我们对直线进行空间变换,将笛卡尔空间转为参数空间。变换的过程就是将原本的x轴替换为k轴,原本的y轴替换为b轴,即在参数空间内,我们希望描述的是因变量b随着自变量k的变化而变化的情况。
下面是进行空间变换的步骤:

  • 等式变换
    首先,将等式 y = k x + b y = kx + b y=kx+b变换成 b = − x k + y b = -xk + y b=xk+y,记住,我们现在的因变量是b,自变量是k。
  • 带入坐标点
    其次,将某个坐标点带入变化后的公式。例如,将点 ( 1 , 2 ) (1,2) (1,2)带入 b = − x k + y b = -xk + y b=xk+y,得到 b = − k + 2 b = -k + 2 b=k+2,我们就在参数空间内得到了一条直线表达式。由此可以得出,笛卡尔坐标系内的一个点,在当前的参数空间内表现形式是一条直线。
  • 绘制参数空间
    现在,我们将 ( 1 , 2 ) (1,2) (1,2) ( 2 , 3 ) (2,3) (2,3) ( 3 , 4 ) (3,4) (3,4)这三个点依次表示在参数空间内,就可以得到下图。
    在这里插入图片描述

分析上图, ( 1 , 2 ) (1,2) (1,2) ( 2 , 3 ) (2,3) (2,3) ( 3 , 4 ) (3,4) (3,4)这三个点转换后的形成了三条直线,且都经过同一个点 ( 1 , 1 ) (1,1) (1,1),而这个 ( 1 , 1 ) (1,1) (1,1)点恰巧表示的是笛卡尔坐标系内 y = x + 1 y = x + 1 y=x+1这条直线的斜率 k k k和截距 b b b
由此可以得出,在k-b参数空间内的一个点代表了笛卡尔空间内的一条线,k-b参数空间内的一条线代表了笛卡尔空间内的一个点。
基于上述理论,如果我们希望找出二值图像中的直线,可以先将图像中的每个点映射到参数空间,然后在参数空间中寻找相交点,若这个相交点经过的直线越多,则在图像中越可能是直线。

3 参数空间优化

但是,在某些情况下k-b参数空间存在弊端,如我在笛卡尔空间内的直线垂直于x轴(例如直线 x = 2 x = 2 x=2),此时k值无穷大,在k-b参数空间内难以映射。
此使就需要将直角坐标系内的直线转用极坐标表示,将k-b参数空间转为ρ-θ参数空间。
在极坐标系内 ρ = c o s θ ∗ x + s i n θ ∗ y ρ = cosθ * x + sinθ * y ρ=cosθx+sinθy表示一条直线,此时的因变量是ρ,自变量是θ。同理,我们将 ( 1 , 2 ) (1,2) (1,2) ( 2 , 3 ) (2,3) (2,3) ( 3 , 4 ) (3,4) (3,4)三个坐标点带入式内,并在ρ-θ参数空间内绘制曲线,它们也表现出经过同一点的特征。
在这里插入图片描述

代码实现

接下来我们使用cv2的相关接口来实现图像的直线检测。
运行环境:python=3.10 opencv-python=4.11.0.86

  • 边缘检测
    霍夫直线检测算法的输入需为一个二值图像,因此首先需要对图像进行预处理。我们采用Canny边缘检测获取图像的边缘信息。
    代码如下:
	# 读取图片
    in_path = './X.png'
    img = cv2.imread(in_path)
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    # 边缘检测
    edge = cv2.Canny(gray, 50, 150)
	# 展示结果
    fig, ax = plt.subplots(nrows=1, ncols=2, figsize=(10, 8), dpi=100)
    ax[0].imshow(gray, cmap='gray')
    ax[0].set_title('Original Image')
    ax[1].imshow(edge, cmap='gray')
    ax[1].set_title('Canny Result')
    plt.show()

在这里插入图片描述

  • 直线检测
	# 霍夫直线检测
    lines = cv2.HoughLines(edge, 1, np.pi / 180, 55)

cv2.HoughLines(img, rho, theta, threshold)
rho参数:表示 rho 的分辨率,即直线搜索时的距离精度,单位为像素。rho=1表示以1像素为单位进行搜索。
theta参数:表示 theta 的分辨率,即直线搜索时的角度精度,单位为弧度。np.pi/180 表示以1度为单位进行搜索。
threshold参数:表示在霍夫空间内线相交的次数阈值,大于该阈值的直线会被保留为结果。

在直线检测过程中,内部确实会创建一个以ρ和θ为轴的二维数组,其具体步骤如下
(1)初始化累加器: 先创建一个所有元素都初始化为0的二维数组。数组的大小由ρ的最大值和θ的范围确定。每个单元格代表了在特定的ρ和 θ值下直线出现的“票数”。
(2)对于图像中的每一个非零像素点(即边缘检测后的有效点),算法会遍历所有可能的θ值,根据直线方程 ρ = c o s θ ∗ x + s i n θ ∗ y ρ = cosθ * x + sinθ * y ρ=cosθx+sinθy 计算对应的ρ,这里x和y是该像素点的坐标。
(3)对于计算得到的每一对 (ρ,θ) ,增加相应累加器单元格中的值(即“投票”)。这意味着对于图像中的每个点,它所能构成的所有直线在累加器中对应的 (ρ,θ) 单元格的票数都会增加。
(4) 经过上述步骤后,累加器中票数高于某个阈值的,对应的直线就被认为是图像中实际存在的直线。这些被选中的 (ρ,θ)对就是最终检测到的直线参数。
图像的检测结果如下:
在这里插入图片描述

小结

总结来说,霍夫变换直线检测是计算机视觉中的一项基础且有力的技术,适用于多种场景,如道路检测、建筑物轮廓提取等。掌握它不仅能够增强我们对图像处理技术的理解,也能够为解决复杂的视觉识别问题提供支持。希望本教程能帮助你更好地理解霍夫变换直线检测的原理和方法,为你的项目带来价值。

Logo

火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。

更多推荐