Hough Transform
霍夫变换是一种基于投票的计算机视觉技术,即使图像边缘存在间断或噪声,也能检测直线、圆和其他形状。
霍夫变换是一种几何特征提取技术:它让图像中的点为可能的形状投票,从而检测直线、圆和其他参数化形状。属于同一结构的点会相互增强,在投票表中形成明显的峰值。在计算机视觉中,这有助于恢复边缘存在间断或噪声的形状。
Paul V. C. Hough 于 1959 年在《气泡室照片的机器分析》中提出了这项技术,用于处理物理学照片中的粒子轨迹。Richard Duda 和 Peter Hart 在其1972 年的直线与曲线检测论文中介绍了广泛使用的角度—距离表示法。
霍夫投票的工作原理#
典型流程从数据预处理和边缘检测开始。边缘检测器会识别局部亮度变化;霍夫变换则将边缘像素归并为几何结构。Sobel 算子用于估算亮度梯度,而 Canny 会生成适合直线投票的细边缘图。
每条候选直线都由 rho 和 theta 表示:rho 是图像原点到直线的有符号垂直距离,theta 是该垂线相对于 x 轴的角度。这种表示法可以处理斜率为无穷大的垂直直线。每个边缘像素都会为兼容的 rho–theta 对投票,投票结果记录在 累加器 中;累加器是将参数空间划分为离散区间的表格。即使共线像素在图像中彼此分离,它们也会为同一区间投票。峰值表示得到足够支持的直线。
几何形状和投票规则决定输出结果。深度学习检测器会从训练数据中学习视觉模式;霍夫检测则使用选定的形状模型和数值阈值,而不是学习得到的模型权重。
直线变换、概率霍夫变换和圆变换#
三种常见实现的搜索方式和输出结果各不相同:
- 标准直线变换:
cv2.HoughLines()返回描述无限长直线的 rho–theta 对。要得到线段端点,需要进行额外处理。 - 概率直线变换:
cv2.HoughLinesP()通过对点采样减少投票计算量,并直接返回线段端点。minLineLength会剔除较短的线段;maxLineGap控制对齐线段之间允许连接的最大间隔。 - 圆变换: 候选圆由圆心和半径确定。
cv2.HoughCircles()使用基于梯度的方法,并通过半径范围缩小搜索空间。其输入为灰度图,而直线变换函数的输入为二值图像。
使用 Python 检测线段#
使用 pip install opencv-python numpy 安装依赖项。本示例使用 OpenCV 在公交车示例图像中检测并绘制线段。
from urllib.request import urlopen
import cv2
import numpy as np
with urlopen("https://ultralytics.com/images/bus.jpg") as response:
encoded = np.frombuffer(response.read(), dtype=np.uint8)
image = cv2.imdecode(encoded, cv2.IMREAD_COLOR)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# 提取边缘以进行投票。
edges = cv2.Canny(gray, 50, 150)
# 检测由累加器投票支持的有限线段。
lines = cv2.HoughLinesP(
edges,
1,
np.pi / 180,
threshold=80,
minLineLength=80,
maxLineGap=10,
)
if lines is not None:
for x1, y1, x2, y2 in lines[:, 0]:
cv2.line(image, (x1, y1), (x2, y2), (0, 0, 255), 2)
cv2.imwrite("hough_segments.jpg", image)保存的图像会将返回的线段以红色叠加显示。rho 区间的宽度为一个像素,theta 区间为一度,而 threshold=80 用于设置累加器的投票阈值。线段长度和间隙设置的单位均为像素。
应用场景与实际限制#
在文档处理中,提取网格线有助于进行结构分析:OpenCV 展示了在数独图像上进行霍夫检测的方法。圆形投票可用于定位硬币的圆心和半径,相关内容见 scikit-image 的圆与椭圆示例。这些输出描述的是几何形状;目标检测会添加语义类别,而实例分割会将像素分配给各个对象。
一个钢梁测量原型结合 YOLOv8 掩码、Canny 边缘和概率霍夫直线来辅助提取角点。Ultralytics YOLO26分割可生成用于对象隔离的掩码,从而能够在单独进行几何处理前采用相同的掩码输入方法。
累加器区间越细,内存用量越大;区间越粗,彼此接近的候选结果越容易合并。在表格边界提取中,边框不完整会减少可检测的边界,而无关直线可能导致边界校正错误。增大 maxLineGap 会连接间隔更大的对齐线段;增大 minLineLength 则会移除较短的线段。










