图像处理中的边缘检测与角点检测算法详解
图像处理中的边缘检测与角点检测算法详解
边缘检测和角点检测是计算机视觉和图像处理中的基本任务,广泛应用于目标检测、图像分割、特征提取等领域。本文将介绍几种常见的边缘检测和角点检测算法,包括Sobel、Canny、Susan、Harris和正方形梯度算子,并通过实验结果展示它们在不同图像上的表现。
一、实验原理
Sobel算子
Sobel算子通过对传进来的图像像素做卷积来检测边缘。卷积的实质是在求梯度值,或者说给了一个加权平均,其中权值就是所谓的卷积核。通过计算水平和竖直方向的梯度Gx和Gy,可以近似计算出梯度值。
Canny算子
Canny算子使用4个mask检测水平、垂直以及对角线方向的边缘。原始图像与每个mask所作的卷积都存储起来。对于每个点,标识在这个点上的最大值以及生成的边缘的方向。Canny使用了两个阈值——高阈值与低阈值。首先从一个较大的阈值开始,标识出比较确信的真实边缘,然后从这些边缘开始在图像中跟踪整个的边缘。
Susan算子
Susan算子使用一个圆形模板,通过检测模板中的像素与中心位置像素的偏离程度,来判断中心位置像素是否为边缘或角点。如果周边像素与中心位置像素偏差较小,则认为周边像素与中心位置像素相似,中心位置为非边缘;如果周边像素与中心位置偏差较大,则认为中心位置为边缘或角点。
Harris角点检测
Harris角点检测的基本思想是通过计算图像灰度变化的矩阵来判断一个点是否是角点。主要步骤如下:
- 计算图像梯度:对图像进行水平和垂直方向上的Sobel滤波,得到梯度图像 (I_x) 和 (I_y)。
- 构建矩阵M:
[
M=\begin{bmatrix}
I_x^2 & I_xI_y \
I_xI_y & I_y^2
\end{bmatrix}
]
其中,(I_x^2)、(I_y^2) 和 (I_xI_y) 是在一个窗口内的求和。 - 计算响应值R:
[
R=\det(M) - k \cdot (\text{trace}(M))^2
]
其中,(\det(M)) 是矩阵 (M) 的行列式,(\text{trace}(M)) 是矩阵 (M) 的迹,(k) 是经验参数,通常取值在 0.04 到 0.06 之间。 - 非极大值抑制:对响应值 (R) 进行非极大值抑制,保留局部最大值作为角点。
正方形梯度算子
正方形梯度算子与Sobel类似,但使用了不同的掩膜。它在R+G,G+B,R+B三个通道上计算梯度,然后输出其最大值。这种算子没有为0的项,更为紧凑,充分利用图像数据,对称性好,抗噪声干扰能力强。通过调整宽度参数wd,可以得到不同宽度的纹理。
二、实验结果
街道图像的边缘分割
建筑图像的边缘分割
机场图像的边缘分割
三、实验分析
Sobel算子
- 优点:Sobel算法使用简单的卷积操作,容易实现和理解,计算速度较快,适合实时应用,能够提供边缘方向的信息。
- 缺点:对噪声敏感,检测效果较粗糙,边缘定位的精度相对较低,容易导致边缘模糊。
Canny算子
- 优点:通过高斯滤波器平滑图像,减少噪声影响,使用非极大值抑制和双阈值处理,能够准确定位边缘,能够检测出较为完整和连续的边缘。
- 缺点:需要设置高斯滤波器的标准差和双阈值,参数选择对结果影响较大,在处理弱边缘和灰度变化较小的区域时,效果不理想。
Susan算子
- 优点:对噪声和局部变化具有较好的鲁棒性,能够准确检测出图像中的边缘和角点,不需要预设滤波器,能够根据图像特征自适应调整。
- 缺点:由于需要计算每个像素的局部结构,计算量较大,速度较慢,算法实现相对复杂,理解和编码难度较大。
Harris角点检测
- 优点:Harris角点检测对图像的旋转和光照变化具有较好的鲁棒性。在现代计算机上,Harris角点检测的计算速度较快,适用于实时应用。对于局部显著变化的点,Harris角点检测能准确定位。
- 缺点:Harris角点检测对图像的缩放变化不敏感,这意味着在多尺度图像中可能会错过一些角点。在噪声较多的图像中,响应值 (R) 可能会受到较大影响,导致误检或漏检。参数 (k) 的选择依赖经验,不同图像可能需要不同的参数,调参过程较为繁琐。
正方形梯度算子
- 优点:没有为0的项,更为紧凑,充分利用图像数据,对称性好,抗噪声干扰能力强。通过调整宽度参数wd,可以得到不同宽度的纹理。
- 缺点:在wd=1的情况下,可能会导致纹理过细而使边界不明显;在wd=3的情况下,可能会导致过粗而使边界混乱。实验结果表明,wd=2的正方形梯度算子在各种情况下都有较好表现效果,具有更好的泛用性。
四、实验代码
import matplotlib.pyplot as plt
import matplotlib.cm as cm
import numpy as np
import cv2 as cv
# Sobel算子
def SOBEL(img):
sobelx = cv.Sobel(img, cv.CV_64F, 1, 0, ksize=3)
sobelx = cv.convertScaleAbs(sobelx)
sobely = cv.Sobel(img, cv.CV_64F, 0, 1, ksize=3)
sobely = cv.convertScaleAbs(sobely)
sobel = cv.addWeighted(sobelx, 0.5, sobely, 0.5, 0)
plt.figure()
plt.title("Sobel")
plt.imshow(sobel, cmap=cm.gray)
plt.axis('off')
print('sobel end')
# Canny算子
def CANNY(img):
min, max = 50, 150
canny = cv.Canny(img, min, max)
plt.figure()
plt.title("Canny")
plt.imshow(canny, cmap=cm.gray)
plt.axis('off')
print('canny end')
# Susan算子
def SUSAN(img_src, t=10):
susanmask = np.ones((7, 7))
susanmask[0, 0] = 0
susanmask[0, 1] = 0
susanmask[0, 5] = 0
susanmask[0, 6] = 0
susanmask[1, 0] = 0
susanmask[1, 6] = 0
susanmask[5, 0] = 0
susanmask[5, 6] = 0
susanmask[6, 0] = 0
susanmask[6, 1] = 0
susanmask[6, 5] = 0
susanmask[6, 6] = 0
img = img_src.copy()
row_s, col_s = 3, 3
row_e, col_e = img_src.shape[0] - 3, img.shape[1] - 3
n_max = 0
n_arr = 37 * np.ones(img.shape) # 初始认为没有角点
for r in range(row_s, row_e): # 遍历所有行
for c in range(col_s, col_e): # 遍历所有列
susan_zone = img[r - 3:r + 3 + 1, c - 3:c + 3 + 1] # 获取矩形区域
susan_zone = susan_zone[susanmask != 0] # 使用mask截取圆形区域
r0 = img[r, c]
similarity = np.exp(-((1.0 * susan_zone - r0) / t) ** 6)
n = np.sum(similarity)
if n > n_max:
n_max = n
n_arr[r, c] = n
g = n_max / 2
R = np.zeros(img.shape)
index = n_arr < g # 小于g,认为是可能的角点,越小,可能性越大
R[index] = g - n_arr[index] # 取反,所以R越大,是角点的可能性越大
plt.figure()
plt.title("Susan")
plt.imshow((6.37 * n_arr).astype(np.uint8), cmap=cm.gray)
plt.axis('off')
img_show = cv.cvtColor(img_src, cv.COLOR_GRAY2BGR)
img_show[R != 0] = (255, 0, 0)
plt.figure()
plt.title("original corners")
plt.imshow(img_show, cmap=cm.gray)
plt.axis('off')
print('susan end')
return R
def Harris(image):
gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
dst = cv.cornerHarris(gray, blockSize=3, ksize=5, k=0.05)
image_dst = image[:, :, :]
image_dst[dst > 0.01 * dst.max()] = [0, 0, 255]
plt.figure()
plt.title("Harris")
plt.imshow(image_dst, cmap=cm.gray)
plt.axis('off')
class SquareOp:
def __init__(self, _img, _k=2):
self.img = np.array(_img).astype(np.float64)
self.k = _k
self.maskx = np.ones((2 * _k, 2 * _k), dtype=np.float64)
self.masky = np.ones((2 * _k, 2 * _k), dtype=np.float64)
self.maskx[:_k, :] = -1.0
self.masky[:, _k:] = -1.0
def padding(self):
n, m, l = self.img.shape
w = self.k
tmp = np.zeros((n + 2 * w - 1, m + 2 * w - 1, l), dtype=np.float64)
tmp[w - 1:w + n - 1, w - 1:w + m - 1] = self.img
self.img = tmp
def calc(self, ca, cb, mask):
val = self.img[:, :, ca] + self.img[:, :, cb]
val = cv.filter2D(val, cv.CV_64F, mask)
val = val[2 * self.k - 1:, 2 * self.k - 1:]
val = cv.convertScaleAbs(val)
return val
def sqre_x(self):
x = self.calc(0, 1, self.maskx)
y = self.calc(1, 2, self.maskx)
z = self.calc(0, 2, self.maskx)
G = np.maximum(x, y, z)
return G
def sqre_y(self):
x = self.calc(0, 1, self.masky)
y = self.calc(1, 2, self.masky)
z = self.calc(0, 2, self.masky)
G = np.maximum(x, y, z)
return G
def run(self):
self.padding()
Gx = self.sqre_x()
Gy = self.sqre_y()
G = cv.addWeighted(Gx, 0.5, Gy, 0.5, 0)
plt.figure()
plt.title("SquareOp, wd=%d" % self.k)
plt.imshow(G, cmap=cm.gray)
plt.axis('off')
return G
if __name__ == '__main__':
img = cv.imread("jiedao0.jpg")
plt.figure()
plt.title("RGBImage")
plt.imshow(img, cmap=cm.gray)
plt.axis('off')
grayimg = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
plt.figure()
plt.title("GrayImage")
plt.imshow(grayimg, cmap=cm.gray)
plt.axis('off')
SOBEL(grayimg)
CANNY(grayimg)
SUSAN(grayimg)
Harris(img)
sqr = SquareOp(img, 1)
sqr.run()
sqr2 = SquareOp(img, 2)
sqr2.run()
sqr3 = SquareOp(img, 3)
sqr3.run()
plt.show()
print('end')
总结
本文介绍了几种常见的边缘检测和角点检测算法,包括Sobel、Canny、Susan、Harris和正方形梯度算子。通过实验结果展示了它们在不同图像上的表现,并对每种算法的优缺点进行了分析。这些算法在计算机视觉和图像处理领域有着广泛的应用,掌握它们对于从事相关领域的研究和开发工作具有重要意义。