霍夫变换(Hough Transform)是一个关于图像领域类的一个算法,被用来检测图像中的各类曲线,直线,圆,椭圆等等,本文记录相关内容与 OpenCV 实现。
Hough(霍夫)变换是一种用于检测线、圆或者图像中其他简单形状的方法。最初Hough变换是一种线变换,这是一种相对较快的检测二值图像中直线的方法,可以进一步推广到除简单线之外的情况。
for edge point (x,y) in image:
for theta = 0 to 180:
rho = x * cos(theta) + y * sin(theta)
H(round(theta), round(rho)) += 1
使用标准霍夫变换查找二值图像中的直线。 官方文档
cv2.HoughLines(
image, # 原图像。
rho, # 累加器的距离分辨率(以像素为单位)。
theta, # 累加器的弧度角分辨率。
threshold[, # 累加器阈值参数。只返回那些获得足够投票的直线(> threshold)。
lines[, # 返回的线,格式为 [[rho_1,theta_1], [rho_2,theta_2], ...]
srn[, # 对于多尺度 Hough 变换,它是距离分辨率 ρ 的一个除数。
粗的累加器距离分辨率为 ρ,精确的累加器分辨率为 ρ/srn。
如果同时使用 srn = 0 和 stn = 0,则使用经典的 Hough 变换。
否则,这两个参数都应该是正数。
stn[, # 对于多尺度 Hough 变换,它是距离分辨率 θ 的除数。
min_theta[, # 对于标准和多尺度霍夫变换,最小角度检查线。必须在0和max_theta之间。
max_theta # 对于标准和多尺度霍夫变换,检查线路的最大角度。必须在 min_theta 和 cv2.CV_pi 之间。
]]]]]) -> lines
img = mt.cv_rgb_imread('hough_line.jpeg')
ori_img = img.copy()
gray = mt.to_gray_image(img)
edge = cv2.Canny(gray, 17430, 34000, apertureSize=7, L2gradient=True)
lines = cv2.HoughLines(edge, rho=1, theta=np.pi/180, threshold=170)
for line in lines:
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(img,(x1,y1),(x2,y2),(250,250,40),2)
PIS(ori_img, img)
用于实现概率霍夫变换寻找边缘中的直线 官方文档
cv2.HoughLinesP(
image, # 源图像。
rho, # 累加器的距离分辨率(以像素为单位)。
theta, # 累加器的弧度角分辨率。
threshold[, # 累加器阈值参数。只返回那些获得足够投票的直线(> threshold)。
lines[, # 返回线结果,格式为 [[xmin, ymin, xmax, ymax], ...]。
minLineLength[, # 最短线段长度。
maxLineGap]]] # 点连接成线的最大距离。
) -> lines
img = mt.cv_rgb_imread('hough_line.jpeg')
ori_img = img.copy()
gray = mt.to_gray_image(img)
edge = cv2.Canny(gray, 17430, 34000, apertureSize=7, L2gradient=True)
lines = cv2.HoughLinesP(edge, rho=1, theta=np.pi/180, threshold=30, minLineLength=30, maxLineGap=20)
for line in lines:
x1,y1,x2,y2 = line[0]
cv2.line(img,(x1,y1),(x2,y2),(250,255,70),2)
PIS(ori_img, img)
Hough圆变换的方法与之前描述的线变换方法相似。粗略解释的话,就是如果你想尝试用完全类似的方法去做,就要从累加平面变成累加三维的体积,三维坐标分别是圆心的位置x、y和圆的半径r。但这样做意味着更大的内存需求和更慢的速度。OpenCV中圆变换的实现通过采用一种称为Hough梯度法的较为复杂的方法来避免了这个问题。
其中 i \in { 1,2,3 }
Hough圆变换的方法与之前描述的线变换方法相似。粗略解释的话,就是如果你想尝试用完全类似的方法去做,就要从累加平面变成累加三维的体积,三维坐标分别是圆心的位置x、y和圆的半径r。但这样做意味着更大的内存需求和更慢的速度。OpenCV中圆变换的实现通过采用一种称为Hough梯度法的较为复杂的方法来避免了这个问题。
Hough梯度法工作过程如下。
cv2.Canny()
);
cv2.Sobel()
计算一阶 Sobel x-导数 和 y-导数 来计算梯度)。
通过这个梯度,我们沿着这个斜率表示的线在累加器内从一个最小值到一个最大值遍历每个点,同时,记录轮廓图像中每个非零像素所在的位置。
官方贴士:
通常该函数能很好地检测出圆的中心。但是,它可能无法找到正确的半径。您可以通过指定半径范围(minRadius 和 maxRadius)来辅助函数。或者,在 HOUGH_gradient 方法的情况下,您可以将 maxRadius 设置为一个负数,只返回中心而不进行半径搜索,并使用另一个程序找到正确的半径。
OpenCV 实现霍夫圆变换的函数 官方文档
cv2.HoughCircles(
image, # 单通道灰度图像,uint8 格式
method, # 检测方法,支持 cv2.HOUGH_GRADIENT 和 cv2.HOUGH_GRADIENT_ALT
cv2.HOUGH_GRADIENT_ALT 是 4.3.0 版本的新方法,精度较高
dp, # 累加器分辨率与图像分辨率的反比
# 例如,如果 dp=1 ,则累加器具有与输入图像相同的分辨率。
如果 dp=2,累加器的宽度和高度只有一半。
# 对于 HOUGH_GRADIENT_ALT 算法,除非有很小的圆需要检测,否则建议 dp=1.5
minDist[, # 检测到的圆心之间的最小距离。
# 如果参数太小,除了一个真实的圆之外,多个相邻的圆可能会被错误地检测到。
如果太大,有些圆圈可能会被漏掉。
circles[, # 返回的圆结果
如果是三维则结果为 (x, y, radius)
如果是四维则结果为 (x, y, radius, votes)
param1[, # 第一个参数
对于 cv2.HOUGH_GRADIENT 和 cv2.HOUGH_GRADIENT_ALT,
它是传递给 Canny 算子的两个阈值中较高的阈值(较低的阈值小两倍)。
注意,cv2.HOUGH_ HOUGH_GRADIENT_ALT 使用 Scharr 算法计算图像导数,
因此阈值通常应该较高,如300或正常曝光和对比度图像。
param2[, # 第二个参数
在 cv2.HOUGH_GRADIENT 情况下,它是检测阶段圆心的累加阈值。
它越小,就可能检测到越多的错误圆环。与较大的累加器值对应的“圆”将首先返回。
在 cv2.HOUGH_ HOUGH_GRADIENT_ALT 算法的情况下,这是圆的“完美性”度量。
越接近1,算法选择形状越好的圆形。在大多数情况下,0.9就可以了。
如果你想更好地发现小圆,你可以把它减少到0.85,0.8甚至更少。
但同时也要尝试限制搜索范围[ minRadius,maxRadius ] ,以避免出现许多错误的圆圈。
minRadius[, # 最小的圆半径
maxRadius]]]]]) -> # 最大圆半径。
如果该参数 <= 0,则使用最大图像维数。
如果该参数 < 0,当方法为 cv2.HOUGH_GRADIENT 时函数返回中心,但不找半径;
cv2.HOUGH_GRADIENT_ALT 总是计算圆半径。
circles
cv2.HOUGH_GRADIENT
img_org = mt.cv_rgb_imread('hough_circles.jpeg', gray=False)
img_org = mt.image_resize(img_org, factor=0.4)
img = mt.to_gray_image(img_org)
res = cv2.HoughCircles(img, cv2.HOUGH_GRADIENT, 1.2, 100, param1=360, param2=120, minRadius=50, maxRadius=300)
for circle in res[0]:
x, y, radius = circle
cv2.circle(img_org, mt.vvd_round([x, y]), mt.vvd_round(radius), color=[255, 0, 0], thickness=2)
PIS(img_org)
cv2.HOUGH_GRADIENT
部分问题在新版本的算法 cv2.HOUGH_GRADIENT_ALT
中得到了改进
cv2.HOUGH_GRADIENT_ALT
img_org = mt.cv_rgb_imread('hough_circles.jpeg', gray=False)
img_org = mt.image_resize(img_org, factor=0.4)
img = mt.to_gray_image(img_org)
res = cv2.HoughCircles(img, cv2.HOUGH_GRADIENT_ALT, 1.2, 120, param1=500, param2=0.85, minRadius=50, maxRadius=300)
for circle in res:
x, y, radius = circle[0]
cv2.circle(img_org, mt.vvd_round([x, y]), mt.vvd_round(radius), color=[255, 0, 0], thickness=2)
PIS(img_org)
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有