python实现广义Hough变换算法、Hough变换算法
-
-
- 1.广义Hough变换算法详解
-
- 算法步骤
- Python 实现
- 详细解释
- 优缺点
- 2.Hough变换算法详解
-
- 算法步骤
- Python 实现
- 详细解释
- 优缺点
-
实现广义Hough变换算法(Generalized Hough Transform)可以用于检测任意形状的对象,不限于标准的直线或圆形。这里将详细介绍广义Hough变换的原理及其Python实现。
1.广义Hough变换算法详解
广义Hough变换的基本原理是将目标形状(通常用边缘检测后的二值图像表示)的每个像素点转化为其可能的参数空间(例如,中心点、旋转角度等)中的投票。通过累积这些投票,可以找到在图像中存在的目标形状的位置和方向。
算法步骤
-
预处理:获取目标形状的边缘图像。
-
定义参数空间:根据目标形状的特征,定义参数空间(通常是多维的),例如中心点坐标、角度、比例等。
-
填充累加器:对于每个目标形状的像素点,计算其在参数空间中的可能位置,并在累加器中进行累加。
-
确定目标位置:在累加器中找到最高投票的位置,该位置即为目标形状在原始图像中的位置和属性。
Python 实现
以下是广义Hough变换的Python实现示例,用于检测图像中的任意形状。这里以检测矩形为例子。
import cv2 import numpy as np import matplotlib.pyplot as plt def generalized_hough_transform(image, template): """ 广义Hough变换算法实现,用于检测任意形状的对象 参数: image (numpy.ndarray): 输入的灰度图像 template (numpy.ndarray): 目标形状的二值化模板图像 返回: tuple: 目标形状在原始图像中的位置和属性信息 """ # 提取目标形状的边缘 edges = cv2.Canny(template, 50, 150) # 计算目标形状的参数空间 accumulator = np.zeros_like(image, dtype=np.uint64) rows, cols = np.nonzero(edges) for i in range(len(rows)): y = rows[i] x = cols[i] for theta in range(0, 180): # 假设角度范围 rho = x * np.cos(np.deg2rad(theta)) + y * np.sin(np.deg2rad(theta)) rho = int(rho) accumulator[rho, theta] += 1 # 找到最高投票的位置 rho_idx, theta_idx = np.unravel_index(np.argmax(accumulator), accumulator.shape) rho = rho_idx - accumulator.shape[0] // 2 # 转换为原始坐标系中的rho theta = np.deg2rad(theta_idx) # 转换为角度 return rho, theta # 示例用法 if __name__ == "__main__": # 读取图像 image = cv2.imread('example.jpg', cv2.IMREAD_GRAYSCALE) template = cv2.imread('template.png', cv2.IMREAD_GRAYSCALE) # 调用广义Hough变换算法 rho, theta = generalized_hough_transform(image, template) # 显示原始图像和检测结果 plt.figure(figsize=(12, 6)) plt.subplot(1, 2, 1) plt.title('Original Image') plt.imshow(image, cmap='gray') plt.axis('off') plt.subplot(1, 2, 2) plt.title('Detected Shape') plt.imshow(cv2.cvtColor(template, cv2.COLOR_GRAY2RGB)) plt.axis('off') # 绘制检测到的形状 h, w = template.shape cos_theta = np.cos(theta) sin_theta = np.sin(theta) x0 = cos_theta * rho y0 = sin_theta * rho x1 = int(x0 + 1000 * (-sin_theta)) y1 = int(y0 + 1000 * (cos_theta)) x2 = int(x0 - 1000 * (-sin_theta)) y2 = int(y0 - 1000 * (cos_theta)) plt.plot([x1, x2], [y1, y2], 'r-', lw=2) plt.show()
详细解释
1. 提取目标形状的边缘:
edges = cv2.Canny(template, 50, 150)
使用Canny边缘检测算法获取目标形状的二值化边缘图像。
2. 计算目标形状的参数空间:
accumulator = np.zeros_like(image, dtype=np.uint64)
创建一个累加器数组,用于累计目标形状的投票。
3. 填充累加器:
for i in range(len(rows)): y = rows[i] x = cols[i] for theta in range(0, 180): # 假设角度范围 rho = x * np.cos(np.deg2rad(theta)) + y * np.sin(np.deg2rad(theta)) rho = int(rho) accumulator[rho, theta] += 1
遍历目标形状的边缘像素,计算其在参数空间(rho, theta)中的投票,并在累加器中进行累加。
4. 找到最高投票的位置:
rho_idx, theta_idx = np.unravel_index(np.argmax(accumulator), accumulator.shape) rho = rho_idx - accumulator.shape[0] // 2 # 转换为原始坐标系中的rho theta = np.deg2rad(theta_idx) # 转换为角度
在累加器中找到最高投票的位置,并将其转换为原始图像坐标系中的rho和角度theta。
5. 显示和保存检测结果:
plt.subplot(1, 2, 1) plt.title('Original Image') plt.imshow(image, cmap='gray') plt.axis('off') plt.subplot(1, 2, 2) plt.title('Detected Shape') plt.imshow(cv2.cvtColor(template, cv2.COLOR_GRAY2RGB)) plt.axis('off') # 绘制检测到的形状 h, w = template.shape cos_theta = np.cos(theta) sin_theta = np.sin(theta) x0 = cos_theta * rho y0 = sin_theta * rho x1 = int(x0 + 1000 * (-sin_theta)) y1 = int(y0 + 1000 * (cos_theta)) x2 = int(x0 - 1000 * (-sin_theta)) y2 = int(y0 - 1000 * (cos_theta)) plt.plot([x1, x2], [y1, y2], 'r-', lw=2) plt.show()
-
使用Matplotlib库显示原始图像和检测到的形状,以及在检测结果图像上绘制检测到的形状。
优缺点
优点:
- 适用性广泛:能够检测任意形状的对象,不限于直线或圆形。
- 灵活性:通过定义不同的参数空间,可以适应不同形状的检测需求。
缺点:
- 计算复杂度高:需要对每个像素点在多维参数空间中进行累加,对计算资源要求高。
- 对参数敏感:参数的选择对检测结果影响较大,需要根据具体应用进行调整。
广义Hough变换算法在实际应用中需要根据具体场景和目标形状进行参数调整和优化,以达到最佳的检测效果。
Hough变换是一种经典的图像处理技术,用于检测图像中的直线。它通过将图像空间中的像素点映射到参数空间(Hough空间),并在参数空间中进行累加来检测直线。以下是Hough变换的详细介绍和Python实现。
2.Hough变换算法详解
算法步骤
-
边缘检测:首先对图像进行边缘检测,通常使用Canny边缘检测器获取二值化的边缘图像。
-
参数空间初始化:根据图像的尺寸和角度范围初始化Hough变换的参数空间。对于检测直线,通常使用极坐标参数表示:极径(r)和极角(θ)。
-
累加器填充:遍历边缘图像中的每个像素点,对每个边缘像素点计算其可能的直线参数,并在Hough累加器中进行累加。
-
找出累加器中的峰值:在累加器中找到高投票的点,这些点表示了可能的直线参数(r, θ)。
-
反映射直线到图像空间:将在参数空间中找到的直线参数(r, θ)反映射到原始图像空间中,并绘制检测到的直线。
Python 实现
以下是使用Python和OpenCV库实现Hough变换算法检测直线的示例代码:
import cv2 import numpy as np import matplotlib.pyplot as plt def hough_transform(image, edge_image, threshold): """ 实现Hough变换检测图像中的直线 参数: image (numpy.ndarray): 输入的灰度图像 edge_image (numpy.ndarray): 边缘检测后的二值化图像 threshold (int): 累加器阈值,用于确定直线检测的灵敏度 返回: list: 检测到的直线的参数列表 [(rho1, theta1), (rho2, theta2), ...] """ # 图像尺寸 height, width = edge_image.shape # 极坐标参数空间的r和theta的步长 theta_step = 1 r_step = 1 # 极坐标参数空间的范围 max_rho = int(np.sqrt(height**2 + width**2)) # 极径的最大值 theta_range = np.arange(0, 180, theta_step) rho_range = np.arange(-max_rho, max_rho, r_step) # 构建累加器 accumulator = np.zeros((len(rho_range), len(theta_range)), dtype=np.uint64) # 边缘图像中的非零像素点 edge_points = np.argwhere(edge_image > 0) # 遍历每个边缘像素点 for y, x in edge_points: for theta_idx, theta in enumerate(np.deg2rad(theta_range)): rho = int(x * np.cos(theta) + y * np.sin(theta)) rho_idx = np.argmin(np.abs(rho_range - rho)) accumulator[rho_idx, theta_idx] += 1 # 获取高投票的直线参数 lines = [] for rho_idx in range(len(rho_range)): for theta_idx in range(len(theta_range)): if accumulator[rho_idx, theta_idx] > threshold: rho = rho_range[rho_idx] theta = np.deg2rad(theta_range[theta_idx]) lines.append((rho, theta)) return lines # 示例用法 if __name__ == "__main__": # 读取图像 image = cv2.imread('example.jpg', cv2.IMREAD_GRAYSCALE) # 边缘检测 edge_image = cv2.Canny(image, 50, 150) # 进行Hough变换 threshold = 100 # 累加器阈值 detected_lines = hough_transform(image, edge_image, threshold) # 绘制检测到的直线 plt.figure(figsize=(8, 6)) plt.imshow(cv2.cvtColor(image, cv2.COLOR_GRAY2RGB)) plt.title('Detected Lines') plt.axis('off') for rho, theta in detected_lines: 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)) plt.plot([x1, x2], [y1, y2], 'r-', lw=2) plt.show()
详细解释
-
边缘检测:
edge_image = cv2.Canny(image, 50, 150)
使用Canny边缘检测算法获取图像的二值化边缘图像。
-
初始化参数空间:
max_rho = int(np.sqrt(height**2 + width**2)) # 极径的最大值 theta_range = np.arange(0, 180, theta_step) rho_range = np.arange(-max_rho, max_rho, r_step) accumulator = np.zeros((len(rho_range), len(theta_range)), dtype=np.uint64)
初始化极坐标参数空间(rho, theta)及其对应的累加器。
-
填充累加器:
for y, x in edge_points: for theta_idx, theta in enumerate(np.deg2rad(theta_range)): rho = int(x * np.cos(theta) + y * np.sin(theta)) rho_idx = np.argmin(np.abs(rho_range - rho)) accumulator[rho_idx, theta_idx] += 1
遍历边缘图像中的每个像素点,计算其可能的直线参数(rho, theta),并在累加器中进行累加。
-
找出高投票的直线参数:
lines = [] for rho_idx in range(len(rho_range)): for theta_idx in range(len(theta_range)): if accumulator[rho_idx, theta_idx] > threshold: rho = rho_range[rho_idx] theta = np.deg2rad(theta_range[theta_idx]) lines.append((rho, theta))
在累加器中找到累计值超过阈值的点,即为检测到的直线参数(rho, theta)。
-
绘制检测到的直线:
plt.figure(figsize=(8, 6)) plt.imshow(cv2.cvtColor(image, cv2.COLOR_GRAY2RGB)) plt.title('Detected Lines') plt.axis('off') for rho, theta in detected_lines: 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)) plt.plot([x1, x2], [y1, y2], 'r-', lw=2) plt.show()
使用Matplotlib库在原始图像上绘制检测到的直线。
优缺点
优点:
- 适用性广泛:能够检测直线,简单且有效。
- 不依赖于直线的长度和位置:适用于检测任意方向的直线。
缺点:
- 对参数的选择敏感:参数的选择(如阈值)会影响检测结果,需要根据具体情况调整。
- 计算复杂度高:需要遍历边缘图像中的每个像素点,并在参数空间中进行累加,计算量较大。
标签:plt,idx,Hough,变换,range,rho,np,theta From: https://www.cnblogs.com/Gaowaly/p/18328324Hough变换是一种经典且重要的图像处理技术,在许多计算机视觉和图像分析应用中都有广泛应用。