Hough Transform Tutorial


在这里插入图片描述

霍夫变换

它在许多计算机视觉应用程序中非常有用。霍夫变换的原始形式旨在识别直线。这就是我今天要解释的内容。此外,该技术后来被推广到检测其他形状,如圆形、椭圆等。

方法的目标,图像准备

要使用霍夫线变换,处理后的图像应该是二进制的。但我们想在原始彩色图像上搜索直线。因此,最常见的解决方案可能是首先对图像进行灰度化,然后检测边缘。然后可以将这样的边缘掩码提取到 Hough Lines 方法,该方法应该输出在图像上找到的一组直线。

直线表示

正如我们从很早的学校课程中学到的,直线可以用两个参数表示。最简单和最广泛使用的参数对是(a,b),它们对应于斜率和截距。然后该行被描述为:y = ax + b

让我们暂时忘记这些参数。我们还可以使用极坐标系中的(ρ, θ)对来明确地描述线。第一个参数ρ是从原点到直线的最短距离(垂直接近直线)。第二个,θ,是 x 轴和距离线之间的角度。这种表示的好处之一是我们可以用ρ和θ来描述垂直线,这在笛卡尔系统中仅使用(a, b)参数是不可能的。

在这里插入图片描述

对于给定的线,我们可以确定特定的ρ和θ。然后,对于属于该线的每个x,y点满足以下等式:

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

从图像空间映射到霍夫空间

让我们再次在图像空间上画一条线。正如我们已经知道的,它由一些ρ和θ 表示。因此,我们可以在(ρ, θ)坐标中绘制这样的点,该坐标稍后将被称为霍夫空间。

在这里插入图片描述
现在,在图像空间中,我们正在绘制在一个公共点相交的其他线。让我们看看在霍夫空间中会产生哪些与这些线相对应的点。

在这里插入图片描述
事实证明,(ρ, θ)空间中的这些点正在形成一个正弦曲线。绘制在这一点相交的无限数量的附加线将导致霍夫空间中的连续正弦曲线。所以,也许,我们可以说图像空间中的一个点会导致霍夫空间中的正弦曲线?让我们回忆一下方程ρ = x cos( θ ) + y sin( θ )。实际上,对于表示图像空间中的点的固定 ( x , y ) 参数并在某个范围内滑过所有可能的θ值,我们获得形成正弦曲线的ρ值。

在这里插入图片描述
综上所述,我们观察到图像空间和霍夫空间之间的以下关系:

直线→点

点 → 正弦曲线

寻找霍夫线

最后,也许是最有趣的效果。如果我们在图像空间中绘制形成一条线的点,我们将在霍夫空间中获得一堆正弦曲线。但是,神奇的是,它们恰好在一点相交!

在这里插入图片描述
这意味着,要识别候选直线,我们应该在霍夫空间中寻找交叉点。下面,您可以在霍夫空间中看到 2 条线和相应的图像。果然,为了方便起见,这里突出显示了 2 个主要十字路口。它们是直线的代表(通过ρ和θ参数)。

在这里插入图片描述

霍夫线参数

在实际应用中,例如使用 OpenCV 库,将图像的霍夫空间划分为均匀的簇。网格由可以称为rho 分辨率和theta 分辨率的参数定义。它们通常分别等于 1 个像素和 1 度。我们扫过网格中的所有单元格并计算某条线有多少票。如果投票数超过给定阈值,我们声称已找到直线,并由所考虑集群中的ρ和θ参数描述。

用 Python 实现

好的,现在我们已经准备好使用 OpenCV 和 Python 在真实图像中找到霍夫线了。图像加载后,我执行灰度、模糊和边缘检测。然后,调用 OpenCV cv2.HoughLines函数来获取检测到的线集。接下来,呈现结果。请注意,函数cv2.HoughLines需要前面讨论过的 3 个参数。对于给定的图像示例,它们是通过实验选择的。使用这些参数很好。例如,如果阈值较低,则会找到更多行,反之亦然。

import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import numpy as np
import cv2
 
image = mpimg.imread("test_images/ppnt.jpg")
gray_image = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
blurred_image = cv2.GaussianBlur(gray_image, (9, 9), 0)
edges_image = cv2.Canny(blurred_image, 50, 120)
   
rho_resolution = 1
theta_resolution = np.pi/180
threshold = 155
 
hough_lines = cv2.HoughLines(edges_image, rho_resolution , theta_resolution , threshold)
 
hough_lines_image = np.zeros_like(image)
draw_lines(hough_lines_image, hough_lines)
original_image_with_hough_lines = weighted_img(hough_lines_image,image)
 
plt.figure(figsize = (30,20))
plt.subplot(131)
plt.imshow(image)
plt.subplot(132)
plt.imshow(edges_image, cmap='gray')
plt.subplot(133)
plt.imshow(original_image_with_hough_lines, cmap='gray') 
plt.show()

下面,有一些辅助函数。我附上它们是为了更好地理解整个代码。

def draw_lines(img, houghLines, color=[0, 255, 0], thickness=2):
    for line in houghLines:
        for rho,theta in line:
            a = np.cos(theta)
            b = np.sin(theta)
            x0 = a*rho
            y0 = b*rho
            x1 = int(x0 + 1000*(-b))
            y1 = int(y0 + 1000*(a))
            x2 = int(x0 - 1000*(-b))
            y2 = int(y0 - 1000*(a))
 
            cv2.line(img,(x1,y1),(x2,y2),color,thickness)   
                
 
def weighted_img(img, initial_img, α=0.8, β=1., λ=0.):
    return cv2.addWeighted(initial_img, α, img, β, λ)

示例结果

结果如下所示。如果我们认为线条太多或太少,我们应该调整rho 分辨率、theta 分辨率和阈值参数。但还要记住在模糊和边缘检测中使用的调整参数。应修改整个流程以适应您的需求。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
值得注意的是,在 OpenCV 中存在另一个版本的函数来查找霍夫线。它被命名为HoughLines P。P 后缀在这里代表概率。它具有更高效的实现,并且该函数输出检测到的线的极值(x0、y0、x1、y1),这非常有用。下面是使用HoughLinesP找到直线的同一图像的示例。

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_42990464/article/details/127093017