基于霍夫变换的目标检测
-
- 0. 前言
- 1. 使用圆形霍夫变换统计图像中圆形对象
- 2. 使用渐进概率霍夫变换检测直线
-
- 2.1 渐进霍夫变换原理
- 2.2 直线检测
- 3. 使用广义霍夫变换检测任意形状的对象
-
- 3.1 广义霍夫变换原理
- 3.2 检测自定义形状
- 小结
- 系列链接
0. 前言
霍夫变换 (
- 我们可以使用极参数
(
ρ
,
θ
)
(ρ, heta)
(ρ,θ) 表示直线,其中
ρ
ρ
ρ 是线段的长度,
θ
θ
θ 是线和
x
x
x 轴之间的夹角
- 为了探索
(
ρ
,
θ
)
(ρ,θ)
(ρ,θ) 参数空间,首先在
ρ
?
θ
ρ-θ
ρ?θ 空间中创建二维直方图
- 然后,对于
ρ
ρ
ρ 和
θ
θ
θ 的每个值,计算输入图像中接近由参数构建的直线的非零像素的数量,并相应地将数组
(
ρ
,
θ
)
(ρ,θ)
(ρ,θ) 递增
- 因此,每个非零像素都可以被认为是对潜在候选线的投票
- 最可能的线对应于获得最高投票的参数值,即
2D 直方图中的局部最大值。
可以使用类似的投票过程来查找圆的参数空间中的最大值,从而将该方法扩展到检测椭圆或其他曲线,更进一步,可以将该方法推广到其他任何任意形状。曲线的参数越多,使用霍夫变换检测曲线的空间和计算成本就越高。在本节中,我们将学习如何使用不同类型的霍夫变换来检测图像中不同形状的对象。
1. 使用圆形霍夫变换统计图像中圆形对象
在本节中,我们将学习如何使用圆形霍夫变换来统计图像中的圆形对象,并使用
(1) 首先导入所有必需的库函数:
import numpy as np import matplotlib.pyplot as plt from skimage.io import imread from skimage.color import rgb2gray from skimage.transform import hough_circle, hough_circle_peaks from skimage.feature import canny from skimage.draw import circle_perimeter from skimage.util import img_as_ubyte from sklearn.neighbors import KDTree
(2) 加载输入图像并使用
orig = imread('1.png') h, w = orig.shape[:2] image = rgb2gray(orig) edges = canny(image, sigma=1, low_threshold=0.15, high_threshold=0.45)
(3) 将函数
hough_radii = np.arange(10, 20, 1) hough_res = hough_circle(edges, hough_radii) accums, cx, cy, radii = hough_circle_peaks(hough_res, hough_radii, min_xdistance = 10, min_ydistance = 10, #num_peaks = 5, total_num_peaks=400)
(4) 使用
circles = [] image = orig.copy() for center_y, center_x, radius in zip(cy, cx, radii): circy, circx = circle_perimeter(center_y, center_x, radius, shape=image.shape) if len(circles) > 1: tree = KDTree(np.array(circles), leaf_size=2) count = tree.query_radius(np.array([[center_y, center_x]]), r=10, count_only=True) if count[0] > 0: continue circles.append([center_y, center_x]) for j in range(-3,4): image[np.minimum(circy+j,h-1), np.minimum(circx+j,w-1)] = (255, 0, 0) print(len(cx))
(5) 最后,绘制原始输入图像,用
plt.figure(figsize=(20, 8)) plt.gray() plt.subplots_adjust(0,0,1,0.975,0.05,0.05) plt.subplot(131), plt.imshow(orig), plt.axis('off'), plt.title('original', size=10) plt.subplot(132), plt.imshow(edges), plt.axis('off'), plt.title('edges with canny', size=10) plt.subplot(133), plt.imshow(image), plt.axis('off'), plt.title('circle detected', size=10) plt.suptitle('Counting circles with Circle Hough transform, number of circles={}'.format(len(circles)), size=12) plt.show()
2. 使用渐进概率霍夫变换检测直线
2.1 渐进霍夫变换原理
霍夫变换是一种流行的提取集合形状的常用方法,变换主要方面是参数化、累加器设计、投票模式和峰值检测。概率霍夫变换 (
渐进概率霍夫变换 (
- 循环选择新的随机点进行投票
- 投票后,检验计数是否可能是由于随机噪声引起
- 检验过程需要与每个bin更新的阈值进行一次比较
- 当检测到一条线时,支持点会撤回选票
- 支持该线的其余点将从尚未投票的点集中删除,然后进行下一次随机选择
- 只需根据累加器决定是否检测到特征
- 算法允许被中断,仍然可以输出检测到的显著特征
- 该算法不需要停止迭代的条件,当所有点被投票或被分配给某个特征时,计算停止
在霍夫变换中,只有一小部分点可以投票,而其余部分作为检测到的特征的支持证据。例如,如果以最小线长度的形式给出约束,则可以在选择投票点之前测试停止条件。在本节中,我们将学习如何使用
2.2 直线检测
(1) 首先导入所需的库和函数,读取输入图像,然后将其转换为灰度图像:
import matplotlib.pyplot as plt from skimage.io import imread from skimage.color import rgb2gray from skimage.feature import canny from skimage.color import rgb2gray from skimage.transform import probabilistic_hough_line
(2) 调用函数
line_length 参数指定的检测线的最小可接受长度line_gap 参数指定的形成直线的像素之间的最大间隙
image = rgb2gray(imread('1.png')) # the image have pixel values in the range [0,1] edges = canny(image, 2, 30/255, 80/255) lines = probabilistic_hough_line(edges, threshold=20, line_length=20, line_gap=5)
最后,绘制输入图像、边缘图像和输出图像:
fig, axes = plt.subplots(1, 3, figsize=(30, 20), sharex=True, sharey=True) ax = axes.ravel() plt.gray() ax[0].imshow(image, cmap=plt.cm.gray) ax[0].set_title('Input image', size=10) ax[1].imshow(edges, cmap=plt.cm.gray) ax[1].set_title('Canny edges', size=10) ax[2].imshow(edges * 0) for line in lines: p0, p1 = line ax[2].plot((p0[0], p1[0]), (p0[1], p1[1]), linewidth=5) ax[2].set_xlim((0, image.shape[1])) ax[2].set_ylim((image.shape[0], 0)) ax[2].set_title('Probabilistic Hough', size=10) for a in ax: a.set_axis_off() plt.axis('off') plt.tight_layout() plt.show()
3. 使用广义霍夫变换检测任意形状的对象
3.1 广义霍夫变换原理
广义霍夫变换 (
广义霍夫变换解释了如何使用任意非解析形状的边界来构建图像空间和霍夫变换空间之间的映射,可以利用这样的映射来检测图像中特定形状的实例。此外,形状的变化(例如旋转,比例变化或图形逆转)对应于该映射的直接转换。但是,最显着的特征是,可以组合这些映射,从简单形状和组件形状的映射中构建复杂形状的映射。这使得广义霍夫成为一种通用变换,可以用来寻找任意复杂的形状。
在本节中,我们将学习如何使用
3.2 检测自定义形状
(1) 我们首先导入所需的库和函数:
from matplotlib.pylab import imshow, title, show from skimage.filters import threshold_otsu import cv2 import numpy as np import matplotlib,pylab as plt
(2) 读取输入和模板图像,将它们转换为灰度图像,并使用
orig = cv2.imread('match_shapes.png') img = 255-cv2.cvtColor(orig, cv2.COLOR_BGR2GRAY) templ = 255-cv2.imread('shape2.png', 0) edges = cv2.Canny(img, 130,150)
(3) 使用
alg = cv2.createGeneralizedHoughBallard() alg.setTemplate(templ) [positions,votes] = alg.detect(edges)
(4) 在检测到的包含形状的区域周围绘制边界框,在图像内部找到的可能位置的坐标表示形状的中心坐标:
clone = orig.copy() #np.dstack([edges, edges, edges]) for i in range(len(positions[0])): pos, scale, angle = positions[0][i][:2], positions[0][i][2], positions[0][i][3] print(pos, scale, angle) # need to write code here to rotate the bounding rect if angle is not zero and scale is not 1 cv2.rectangle(clone, (int(pos[0]) - templ.shape[1]//2, int(pos[1]) - templ.shape[0]//2), (int(pos[0] + templ.shape[1]//2), int(pos[1] + templ.shape[0]//2)), (0,0,255), 2)
(5) 最后,绘制输入和模板图像以及边界框,在图像中可以看出,虽然模板图像与源图像中对象略有不同,但该算法仍可以正确找到图像内部的形状:
plt.figure(figsize=(20, 8)) plt.gray() plt.subplots_adjust(0,0,1,0.975,0.05,0.05) plt.subplot(131), plt.imshow(img), plt.axis('off'), plt.title('input', size=10) plt.subplot(132), plt.imshow(templ), plt.axis('off'), plt.title('template', size=10) plt.subplot(133), plt.imshow(clone), plt.axis('off'), plt.title('object detection with generalized Hough', size=10) plt.show()
小结
霍夫变换是一种特征提取 (
系列链接
Python图像处理【1】图像与视频处理基础
Python图像处理【2】探索Python图像处理库
Python图像处理【3】Python图像处理库应用
Python图像处理【4】图像线性变换
Python图像处理【5】图像扭曲/逆扭曲
Python图像处理【6】通过哈希查找重复和类似的图像
Python图像处理【7】采样、卷积与离散傅里叶变换
Python图像处理【8】使用低通滤波器模糊图像
Python图像处理【9】使用高通滤波器执行边缘检测
Python图像处理【10】基于离散余弦变换的图像压缩
Python图像处理【11】利用反卷积执行图像去模糊
Python图像处理【12】基于小波变换执行图像去噪
Python图像处理【13】使用PIL执行图像降噪
Python图像处理【14】基于非线性滤波器的图像去噪
Python图像处理【15】基于非锐化掩码锐化图像
Python图像处理【16】OpenCV直方图均衡化
Python图像处理【17】指纹增强和细节提取
Python图像处理【18】边缘检测详解