深入理解Hough 变换的原理、实现与应用
基于参数空间投票的几何形状检测方法
点 - 线对偶性:图像空间中的一条直线对应参数空间中的一个点;图像空间中的一个点对应参数空间中的一条正弦曲线。共线的点在参数空间中表现为相交的正弦曲线,交点即为所求直线的参数。
ρ = x · cos(theta) + y · sin(theta)
首先对输入图像进行边缘检测(通常使用 Canny 算子),获取边缘点集合。这些边缘点是后续 Hough 变换的输入。
将连续的参数空间离散化为累加器数组:
# 参数空间大小
rho_max = sqrt(width2 + height2)
rho_bins = 2 * rho_max # 步长为 1
theta_bins = 180 # 步长为 1 度
accumulator = zeros((rho_bins, theta_bins))
对每个边缘点,遍历所有可能的theta值,计算对应的ρ值,并在累加器中对应位置投票。
在累加器中寻找局部最大值点,这些峰值对应图像中的直线。只有超过阈值的峰值才被接受。
三个共线点在参数空间中对应三条相交的正弦曲线,交点即为检测到的直线参数
| 参数 | 说明 | 影响 |
|---|---|---|
| ρ分辨率 | 距离量化精度 | 越小检测越精确 |
| theta分辨率 | 角度量化精度 | 影响角度精度 |
| 阈值 | 最小投票数 | 决定直线检测灵敏度 |
import cv2
import numpy as np
import matplotlib.pyplot as plt
def hough_line_transform(image_path, threshold=100):
"""
使用 OpenCV 实现标准 Hough 变换
:param image_path: 输入图像路径
:param threshold: 累加器阈值
:return: 原图和检测到直线的图像
"""
# 读取图像
img = cv2.imread(image_path)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 边缘检测
edges = cv2.Canny(gray, 50, 150, apertureSize=3)
# 使用 HoughLines 检测直线
lines = cv2.HoughLines(edges, 1, np.pi/180, threshold)
# 在原图上绘制检测到的直线
img_with_lines = img.copy()
if lines is not None:
for rho, theta in lines[:, 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_with_lines, (x1, y1), (x2, y2), (0, 0, 255), 2)
return img, img_with_lines
def probabilistic_hough_transform(image_path, threshold=50,
min_line_length=50, max_line_gap=10):
"""
使用概率 Hough 变换检测直线
:param image_path: 输入图像路径
:param threshold: 累加器阈值
:param min_line_length: 最小直线长度
:param max_line_gap: 最大线段间隙
:return: 原图和检测到直线的图像
"""
# 读取图像
img = cv2.imread(image_path)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 边缘检测
edges = cv2.Canny(gray, 50, 150, apertureSize=3)
# 使用概率 Hough 变换检测直线
lines = cv2.HoughLinesP(edges, 1, np.pi/180, threshold,
minLineLength=min_line_length,
maxLineGap=max_line_gap)
# 在原图上绘制检测到的直线
img_with_lines = img.copy()
if lines is not None:
for x1, y1, x2, y2 in lines[:, 0]:
cv2.line(img_with_lines, (x1, y1), (x2, y2), (0, 255, 0), 2)
return img, img_with_lines
# 使用示例
if __name__ == "__main__":
img, result = hough_line_transform('image.jpg', threshold=100)
prob_img, prob_result = probabilistic_hough_transform('image.jpg', threshold=50)
plt.figure(figsize=(15, 5))
plt.subplot(1, 3, 1)
plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
plt.title('Original Image')
plt.subplot(1, 3, 2)
plt.imshow(cv2.cvtColor(result, cv2.COLOR_BGR2RGB))
plt.title('Standard Hough')
plt.subplot(1, 3, 3)
plt.imshow(cv2.cvtColor(prob_result, cv2.COLOR_BGR2RGB))
plt.title('Probabilistic Hough')
plt.show()
| 参数 | 含义 | 调节建议 | 影响 |
|---|---|---|---|
| rho | 距离分辨率 | 通常为 1 像素 | 越小精度越高,计算越慢 |
| theta | 角度分辨率 | 通常为π/180 (1°) | 越小精度越高,累加器越大 |
| threshold | 累加器阈值 | 根据图像大小调整 | 越高检测到的直线越少但越可靠 |
| minLineLength | 最小线段长度 | 仅用于 HoughLinesP | 过滤短线段 |
| maxLineGap | 最大线段间隙 | 仅用于 HoughLinesP | 连接断裂线段 |
检测表格线、文本行
自动驾驶中的车道识别
检测建筑结构线条
产品缺陷检测
导航和定位
扩展到圆、椭圆检测
| 变种 | 原理 | 优点 | 缺点 |
|---|---|---|---|
| 标准 Hough | 遍历所有点和角度 | 检测精确 | 计算慢,内存大 |
| 概率 Hough | 随机采样边缘点 | 速度快,输出线段 | 可能漏检 |
| 广义 Hough | 使用 R 表存储形状 | 可检测任意形状 | 需要模板,复杂 |
| 圆 Hough | 三维参数空间 (a,b,r) | 可检测圆形 | 计算量更大 |