Python OpenCV霍夫变换教程:如何理解和实现形状检测?

2021年11月28日08:05:05 发表评论 1,101 次浏览
特色图片
Python OpenCV霍夫变换示例

如何使用霍夫变换实现形状检测?今天我们将学习如何在称为霍夫变换的技术的帮助下检测图像中的线和圆。

什么是霍夫空间?

Python OpenCV霍夫变换教程:在我们开始将霍夫变换应用于图像之前,我们需要了解霍夫空间是什么,我们将通过一个例子来学习。

参数空间

当我们处理图像时,我们可以将图像想象成一个在一些 x 和 y 坐标上的二维矩阵,在该矩阵下,一条线可以被描述为 y = mx + b

参数空间
参数空间

但是在我们称为霍夫空间的参数空间中,我可以表示与mvs相同的线b,因此图像空间上线的表征将是m-b霍夫空间中位置处的单个点。

夫霍空间
霍夫空间

但是我们有一个问题y = mx + b,我们不能表示一条垂直线,因为斜率是无限的。所以我们需要一种更好的参数化方式,极坐标(rho 和 theta)。

霍夫空间

  • rho:描述线距原点的距离
  • theta:描述远离水平线的角度
线极坐标
线极坐标

不过,一个非常重要的观察是,当我们在一条线上取多个点时会发生什么,然后我们变换到我们的霍夫空间。

夫霍空间中的点线关系
霍夫空间中的点线关系

图像空间上的单个点转化为霍夫空间上的曲线,其特殊性是图像空间上一条线之间的点将由具有单个接触点的多条曲线表示。

这将是我们的目标,找到一组曲线相交的点。

什么是霍夫变换?

霍夫变换是一种特征提取方法,用于检测图像中的圆形、线条等简单形状。

“简单”特征是通过参数的形状表示得出的。一个“简单”的形状只会用几个参数来表示,例如一条直线可以用它的斜率和截距来表示,或者一个圆可以用 x、y 和半径来表示。

如何使用霍夫变换实现形状检测?在我们的线条示例中,霍夫变换将负责处理图像上的点并计算霍夫空间中的值。

进行转换并随后找到相交曲线的算法有点复杂,因此超出了本文的范围。然而,我们将看看这个算法的一个实现,它是OpenCV 库的一部分。

Python OpenCV霍夫变换教程:使用 OpenCV 检测线条

在 OpenCV 中,使用霍夫变换的线检测是在函数HoughLinesHoughLinesP(概率霍夫变换)中实现的。我们将专注于后者。

该函数需要以下参数:

  • image: 8 位单通道二进制源图像。图像可以被函数修改。
  • lines: 线的输出向量。每条线由一个 4 元素向量 (x_1, y_1, x_2, y_2) 表示,其中 (x_1,y_1) 和 (x_2, y_2) 是每个检测到的线段的终点。
  • rho:累加器的距离分辨率(以像素为单位)。
  • theta:以弧度为单位的累加器的角度分辨率。
  • threshold:累加器阈值参数。只返回那些获得足够选票的行
  • minLineLength: 最小线长。比它短的线段被拒绝。
  • maxLineGap:连接它们的同一条线上的点之间的最大允许间隙。

太复杂?举个例子就更容易了:

# Read image 
img = cv2.imread('lanes.jpg', cv2.IMREAD_COLOR)
# Convert the image to gray-scale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# Find the edges in the image using canny detector
edges = cv2.Canny(gray, 50, 200)
# Detect points that form a line
lines = cv2.HoughLinesP(edges, 1, np.pi/180, max_slider, minLineLength=10, maxLineGap=250)
# Draw lines on the image
for line in lines:
    x1, y1, x2, y2 = line[0]
    cv2.line(img, (x1, y1), (x2, y2), (255, 0, 0), 3)
# Show result
cv2.imshow("Result Image", img)

结果如下:

线路检测示例
线路检测示例

我们实际使用仅边缘图像作为霍夫变换的参数非常重要,否则算法将无法按预期工作。

Python OpenCV霍夫变换示例:使用 OpenCV 检测圆圈

该过程与行的过程大致相同,不同之处在于这次我们将使用 OpenCV 库中的不同函数。我们将使用 now HoughCircles,它接受以下参数:

  • image: 8 位、单通道、灰度输入图像。
  • circles:找到的圆的输出向量。每个向量都被编码为一个 3 元素的浮点向量 (x, y, radius) 。
  • circle_storage: 在 C 函数中,这是一个内存存储,将包含找到的圆的输出序列。
  • method: 检测方法使用。目前唯一实现的方法是 CV_HOUGH_GRADIENT ,基本上是 21HT
  • dp: 累加器分辨率与图像分辨率的反比。例如,如果 dp=1 ,则累加器具有与输入图像相同的分辨率。如果 dp=2 ,累加器的宽度和高度是原来的一半。
  • minDist:检测到的圆的中心之间的最小距离。如果参数太小,除了一个真一个之外,可能还会错误地检测到多个邻居圆。如果太大,可能会遗漏一些圆圈。
  • param1:第一个特定于方法的参数。在 CV_HOUGH_GRADIENT 的情况下,它是传递给 Canny() 边缘检测器的两者中较高的阈值(较低的阈值小两倍)。
  • param2:第二个特定于方法的参数。在 CV_HOUGH_GRADIENT 的情况下,它是检测阶段圆心的累加器阈值。它越小,检测到的假圆就越多。与较大累加器值相对应的圆圈将首先返回。
  • minRadius:最小圆半径。
  • maxRadius:最大圆半径。

如何使用霍夫变换实现形状检测?请记住,参数需要不同,因为我们无法使用与用于线的相同参数化来描述圆,而是需要使用类似(x - x0)^^2 + (y - y0)^^2 = r^^2.

和代码:

# Read image as gray-scale
img = cv2.imread('circles.png', cv2.IMREAD_COLOR)
# Convert to gray-scale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# Blur the image to reduce noise
img_blur = cv2.medianBlur(gray, 5)
# Apply hough transform on the image
circles = cv2.HoughCircles(img_blur, cv2.HOUGH_GRADIENT, 1, img.shape[0]/64, param1=200, param2=10, minRadius=5, maxRadius=30)
# Draw detected circles
if circles is not None:
    circles = np.uint16(np.around(circles))
    for i in circles[0, :]:
        # Draw outer circle
        cv2.circle(img, (i[0], i[1]), i[2], (0, 255, 0), 2)
        # Draw inner circle
        cv2.circle(img, (i[0], i[1]), 2, (0, 0, 255), 3)

请注意,与前面的示例相比,我们没有在此处应用任何边缘检测功能。这是因为该功能HoughCircles具有内置的智能检测功能。

结果:

圆形检测示例
圆形检测示例

Python OpenCV霍夫变换教程结论

霍夫变换是一种用于检测图像中简单形状的出色技术,具有多种应用,从医学应用(如 X 射线、CT 和 MRI 分析)到自动驾驶汽车。如果你有兴趣了解更多关于霍夫空间的信息,我建议你实际运行代码,自己尝试不同的配置,并查看OpenCV 文档 以获取更多信息。

谢谢阅读!

木子山

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: