Python的OpenCV实现霍夫曼直线检测原理和api介绍

1. 引言

霍夫曼直线检测(Hough Line Detection)是一种在图像中检测直线的经典算法。它通过在极坐标空间内累积直线的交点,从而有效地检测图像中的直线。在本篇博客中,我们将使用Python和OpenCV库来实现霍夫曼直线检测,并深入介绍该算法的原理、相关API以及代码实例。

2. 霍夫曼直线检测原理

霍夫曼直线检测是一种基于累加器的技术。其原理可以简单概括为以下几个步骤:

  1. 边缘检测:首先,对图像进行边缘检测,常用的方法是使用Canny边缘检测算法。

  2. 构建霍夫空间:对边缘检测后的图像,在霍夫空间中进行累加。霍夫空间是一个极坐标空间,其中横轴表示直线的角度(θ),纵轴表示直线到原点的距离(ρ)。每个边缘点都在霍夫空间中产生一条曲线。

  3. 查找直线:在霍夫空间中找到最大累加值的点,该点对应的直线就是图像中的一条直线。

  4. 重复以上步骤:重复上述步骤,直到找到所有的直线。

这个原理看起来有点突兀,感觉说了等于没说,下面具体描述一下霍夫曼的原理。

3.霍夫曼基本原理

霍夫曼直线检测是一种利用点与线的对偶性来从图像中分离出直线的算法。它的基本思想是将图像空间中的每个点转换到极坐标系下的一条曲线,然后在极坐标系中寻找曲线的交点,这些交点对应着图像中的直线。

首先我们应该清楚的是:图像空间中一个点对应着参数空间中一条直线,而参数空间中一个点对应着图像空间中一条直线。

我们都知道一般的灰度图或二值图像是由二维矩阵组成,而这个矩阵就可以当作一个平面坐标。霍夫曼直线检测算法就是将图像中组成直线的像素点转换为参数空间的一条条直线。而这些直线交于一个点数量达到一定阈值,这个点就可以映射到图像空间的一条直线。

     我们首先通过直接坐标系来通俗理解原理。

  • 在直角坐标中一般使用y=kx+b代表一条直线,唯一的k,b值可以唯一确定一条直线。
  • 在图像空间中,x,y是变量,k,b是参数,k是斜率,b是截距。
  • 首先看点A(x0,y0),如果把直线转化为 b=-kx0+y0  。在参数空间中把x0,y0当作参数,k,b当作变量,这样在图像空间中一个点A对应参数空间一条直线。

Python的OpenCV实现霍夫曼直线检测原理和api介绍_第1张图片

而在图像空间中一条直线上有多个点,每个点都对应参数空间中一条直线。如下图:

例如直线y=k0*x+b0上有四个点对应参数空间四条直线,而这四条直线相交于点(k0,b0),从而映射到图像空间的直线。

Python的OpenCV实现霍夫曼直线检测原理和api介绍_第2张图片

 以上就是霍夫曼直线检测算法利用点与线对偶性的核心思想。能够理解上面基本就知道了原理。总之霍夫曼直线检测就是利用上面的原理。核心步骤就是:在图像中找直线——>将直线上所有点转换为参数空间中的直线——>当参数空间中交于某一点上的直线达到一定数量就可以检测到该点对应图像中的一条直线。

不过需要注意的是,霍夫曼算法在实际应用中采用的是极坐标,因为在直角坐标中直线垂直时斜率无穷大无法表示。但核心思想和上面相同,极坐标图像空间的点对应参数空间一条曲线,多条曲线交于同一点就可以确定图像中对应的直线了。具体情况不再赘述。

4. OpenCV霍夫曼直线检测API介绍

在OpenCV中,霍夫曼直线检测相关的函数是HoughLinesHoughLinesP,主要介绍常用参数。下面分别介绍这两个函数的作用:

HoughLines

HoughLines函数用于在给定二值图像中检测直线。

cv2.HoughLines(image, rho, theta, threshold)
  • image: 输入的二值图像,一般为边缘检测后的图像。
  • rho: 以像素为单位的距离精度。
  • theta: 以弧度为单位的角度精度。
  • threshold: 累加器阈值,只有高于该阈值的交点才会被认为是直线。

返回值是一个包含直线的数组,每条直线由ρ和θ表示。

HoughLinesP

HoughLinesP函数也用于在给定二值图像中检测直线,但与HoughLines不同的是,它会返回直线上的端点。

cv2.HoughLinesP(image, rho, theta, threshold, minLineLength, maxLineGap)
  • image: 输入的二值图像,一般为边缘检测后的图像。
  • rho: 以像素为单位的距离精度。
  • theta: 以弧度为单位的角度精度。
  • threshold: 累加器阈值,只有高于该阈值的交点才会被认为是直线。
  • minLineLength: 最小直线长度。比这个短的线段将被忽略。
  • maxLineGap: 最大直线间隙。如果两条直线之间的距离小于该值,则被认为是一条直线。

返回值是一个包含直线端点的数组,每条直线由两个端点坐标表示。

5. 代码实例

这里使用HoughLines

我们了解霍夫曼直线检测原理后,能够灵活使用它才能发挥作用。

首先要注意:

HoughLines返回的是三维矩阵,每一行表示检测到的一条直线,包含两个值:rhotheta

  • rho表示直线到原点(0, 0)的距离,单位为像素;
  • theta表示直线的角度,单位为弧度。

[[[-74.           2.3561945 ]]

 [[501.           0.        ]]

 [[302.           0.5061455 ]]

 [[302.           0.57595867]]]

 绘制直线的原理是根据直线的参数(rhotheta),计算直线上的两个点的坐标,然后使用cv2.line()函数将这两个点连接起来。

import cv2
import numpy as np

# 读取图像并转换为灰度图像
image = cv2.imread("img.png")
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
#阈值分割
ret, edge = cv2.threshold(gray, 80, 255, cv2.THRESH_OTSU)
# 边缘检测
edges = cv2.Canny(edge, 50, 150, apertureSize=3)
# 进行霍夫曼直线检测
lines = cv2.HoughLines(edges, rho=1, theta=np.pi/180, threshold=200)
#打印检测出来的直线信息
print(lines)

# 绘制检测到的直线
for line in lines:
    #rho为直线到原点的距离,单位为像素,theta为直线的方向,以水平向右为0度,角度范围从0到180度。
    rho, theta = line[0]
    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(image, (x1, y1), (x2, y2), (0, 0, 255), 2)

# 显示结果图像
cv2.imshow("Hough Lines", image)
cv2.waitKey(0)
cv2.destroyAllWindows()

 Python的OpenCV实现霍夫曼直线检测原理和api介绍_第3张图片

 Python的OpenCV实现霍夫曼直线检测原理和api介绍_第4张图片Python的OpenCV实现霍夫曼直线检测原理和api介绍_第5张图片

 写在最后:霍夫曼直线检测是一种常用的图像处理技术,它可以从图像中提取出具有某种相同特征的几何形状,如直线,圆,椭圆等。霍夫曼直线检测的优点和局限性如下:

优点:霍夫曼直线检测的优点是抗干扰能力强,对图像中直线的殘缺部分、噪声以及其它共存的非直线结构不敏感,能容忍特征边界描述中的间隙,并且相对不受图像噪声的影响。霍夫曼直线检测还可以通过多尺度和概率的方法来提高效率和精度,以及检测出直线的端点。

局限性:霍夫曼直线检测的局限性是需要大量的计算资源和存储空间,因为它需要在参数空间中建立累加器矩阵,并对每个像素点进行变换和投票。并且只能检测直线的位置和方向,不能检测出直线的长度。霍夫曼直线检测还不能很好地处理弯曲或分叉的直线。

参考:(104条消息) 霍夫变换直线检测(Line Detection)原理及示例_霍夫变换直线检测原理_leonardohaig的博客-CSDN博客

(三十一)霍夫曼直线检测 - 知乎 (zhihu.com)

你可能感兴趣的:(opencv,人工智能,计算机视觉)