今天我们将学习如何借助霍夫变换技术来检测图像中的直线和圆。
什么是霍夫空间?
在我们开始对图像应用霍夫变换之前,我们需要了解霍夫空间是什么,我们将通过一个例子来进行了解。
参数空间
当我们处理图像时,我们可以将图像想象成是某个 x 和 y 坐标上的二维矩阵,在该坐标下,一条线可以被描述为 y = mx b。
参数空间
在参数空间中,我们称之为霍夫空间,我可以用 m 和 b 来表示同一条线,因此图像空间中的一条线的表征将是霍夫空间中 m-b 位置的一个点。
霍夫空间
但是我们有一个问题,当 y = mx b 时,我们不能表示一条垂直线,因为斜率是无限的。所以我们需要一种更好的参数化方式,极坐标(ρ 和 θ)。
霍夫空间
- ρ:描述直线与原点的距离
- θ:描述远离水平线极坐标的角度
线极坐标
不过,一个非常重要的观察结果是,当我们在一条线上取多个点,然后我们变换到我们的霍夫空间时,会发生什么呢?
霍夫空间中的点线关系
图像空间上的单个点转化为霍夫空间上的曲线,其特殊性是图像空间上一条直线之间的点将由具有单个接触点的多条曲线表示。
这将是我们的目标,找到一组曲线相交的点。
什么是霍夫变换?
霍夫变换是一种特征提取方法,用于检测图像中的简单形状,如圆、线等。
“简单”特征是通过参数的形状表示推导出来的。一个“简单”的形状将仅由几个参数来表示,例如一条直线可以用它的斜率和截距来表示,或者一个圆可以用 x、y 和半径来表示。
在我们的直线示例中,霍夫变换将负责处理图像上的点并计算霍夫空间中的值。
进行转换并随后找到相交曲线的算法有点复杂,因此超出了本文的范围。不过,我们将看看这个算法的实现,它是OpenCV库的一部分。
使用 OpenCV 检测直线
在OpenCV中,使用霍夫变换的线检测是在函数HoughLines和HoughLinesP(概率霍夫变换)中实现的。我们将重点讨论后者。
该函数需要以下参数:
- 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 :同一直线上连接点的最大允许间距。
举个例子让我们能够更好的理解:
代码语言:javascript复制# 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)
结果如下:
线路检测示例
我们实际使用仅边缘图像作为霍夫变换的参数非常重要,否则算法将无法按预期工作。
使用 OpenCV 检测圆
该过程与直线的过程大致相同,不同之处在于这次我们将使用 OpenCV 库中的不同函数。我们现在将使用 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的方程.
代码:
代码语言:javascript复制# 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 具有内置的 Canny 检测函数。
结果:
圆形检测示例
结论
霍夫变换是一种用于检测图像中简单形状的出色技术,具有多种应用,从医学应用(如 X 射线、CT 和 MRI 分析)到自动驾驶汽车。