【 图像梯度处理,图像边缘检测】图像处理(OpenCv)-part6
13 图像梯度处理
13.1 图像梯度
边缘提取是图像处理中的一个重要任务,其目的是检测图像中灰度值发生显著变化的区域,这些区域通常对应于图像中的物体边界、纹理变化或深度变化等。边缘提取的原理可以分为以下几个关键步骤:
1. 边缘的定义和灰度变化
边缘可以定义为图像中灰度值发生显著变化的区域。这些变化通常是由于物体的边界、阴影、纹理或其他视觉特征引起的。边缘提取的目标是找到这些灰度变化的区域。
2. 梯度计算
边缘提取的核心是计算图像的梯度,梯度反映了灰度值的变化率。梯度通常使用梯度算子来计算,这些算子通过卷积操作与图像进行计算。
常见的梯度算子包括:
-
Sobel 算子:用于计算 x 和 y 方向的梯度,能够突出水平和垂直方向的边缘。
-
Prewitt 算子:类似于 Sobel 算子,但使用不同的权重。
-
Roberts 算子:用于计算对角线方向的梯度。
-
Scharr 算子:在某些情况下提供更精确的梯度计算结果。
13.2 垂直边缘提取
obel 算子 :Sobel 算子通过计算图像亮度的空间梯度来突出边缘,它使用两个 3x3 的卷积核,其中一个用于检测水平方向边缘(即垂直边缘),其卷积核为:
在进行卷积运算时,该算子在图像的每个 3×3 区域内,将卷积核的每个元素与对应位置的像素值相乘后求和,得到该区域在水平方向的梯度近似值,即垂直边缘的信息。例如,对于一个 3×3 的像素块,使用上述卷积核计算得到的梯度值若较大,则说明该区域存在垂直边缘。
Prewitt 算子 :Prewitt 算子也采用两个 3x3 的卷积模板来检测水平和垂直方向的边缘,其垂直边缘检测的卷积核为:
与 Sobel 算子类似,通过在图像上滑动该卷积核进行运算,可得到图像中垂直边缘的响应。Prewitt 算子对图像中的噪声具有一定的平滑作用,对灰度和噪声较多的图像处理效果较好。
Roberts 算子 :Roberts 算子是一种用于图像边缘检测的算子,其通过计算图像上相邻像素点之间的差异来检测边缘。用于检测垂直边缘的卷积核为:
该算子计算简单快速,但对噪声非常敏感,且产生的边缘响应较弱,除非边缘非常锐利。
Scharr 算子 :Scharr 算子在计算梯度时具有更好的旋转对称性,并且在计算垂直边缘时,其卷积核为:
相较于 Sobel 算子,Scharr 算子在某些情况下可以提供更精确的梯度计算结果,能够更准确地提取垂直边缘。
基于梯度计算后的处理
13.3 计算梯度幅值和方向
在使用上述算子计算出梯度分量后,通常需要计算梯度的幅值和方向,以确定边缘的位置和强度。梯度的幅值表示边缘的强度,方向表示边缘的方向。对于垂直边缘,其梯度方向近似为 0 度或 180 度。计算公式如下:
例如,当使用 Sobel 算子计算出 Gx 和 Gy 后,通过上述公式计算梯度幅值和方向,若某个像素点的梯度方向接近 0 度或 180 度,且梯度幅值较大,则可判断该点为垂直边缘点。
13.4 非极大值抑制
该步骤用于消除边缘检测中产生的伪边缘,保留真正的边缘。在确定梯度幅值和方向后,对于垂直边缘检测,将每个像素点与其在垂直方向上的两个邻点进行比较,若该像素点的梯度幅值不是这三个点中的最大值,则抑制该点的梯度幅值,将其设为 0,从而保留沿垂直方向的局部最大值,得到更精细的垂直边缘。
13.5 双阈值检测和边缘连接
通过设定两个阈值,如高阈值和低阈值,对梯度幅值进行筛选。大于高阈值的像素点被确定为边缘点,介于低阈值和高阈值之间的像素点则根据与确定边缘点的连接关系来判断是否为边缘点,小于低阈值的像素点则被排除。这一步骤有助于连接断断续续的边缘,形成完整的垂直边缘轮廓。
13.6 总结
边缘提取的原理主要包括以下几个步骤:
-
梯度计算:使用梯度算子计算图像的梯度。
-
梯度幅度和方向:计算梯度的幅度和方向,确定边缘的强度和方向。
-
非极大值抑制:保留沿边缘方向的局部最大值,消除伪边缘。
-
双阈值检测和边缘连接:通过设定两个阈值,筛选出真正的边缘点并连接形成完整的边缘轮廓。
这些步骤共同作用,实现了从图像中提取边缘的目标。通过这些方法,可以有效地检测出图像中的物体边界和其他重要特征。
13.7 代码
img = cv.imread('images/shudu.png')
kernel =np.array([[-1, 0, 1],[-2, 0, 2],[-1, 0, 1]],np.float32)
#垂直边缘提取
img1 = cv.filter2D(img, -1, kernel)
kernel2 = kernel.T
#水平边缘提取
img2 = cv.filter2D(img, -1, kernel2)
cv.imshow('1', img1)
cv.imshow('2', img2)
cv.waitKey(0)
cv.destroyAllWindows()
img2 = cv.filter2D(img, -1, kernel2)
函数用于对图像应用二维滤波操作
img
: 输入图像,这里是之前读取的图像数据。
-1
: 表示输出图像的深度与输入图像相同。在 OpenCV 中,-1
通常表示输出图像的深度与输入图像一致,这里输入图像是彩色图像(假设使用cv.imread
读取),因此输出图像的深度保持不变。
kernel2
: 卷积核,这是一个二维的浮点数数组,用于定义滤波器的权重。
举个直观粒子
import numpy as np
import cv2 as cvimg = np.array([[100, 102, 109, 110, 98, 20, 20, 18, 21],[110, 104, 105, 100, 104, 23, 20, 18, 20],[98, 100, 104, 104, 100, 17, 19, 22, 21],[110, 104, 105, 100, 104, 23, 20, 18, 20],[98, 100, 104, 104, 100, 17, 19, 22, 21],[100, 102, 109, 110, 98, 20, 19, 18, 21]
], dtype=np.float32)kernel =np.array([[-1, 0, 1],[-1, 0, 2],[-1, 0, 1]],np.float32)
img2 = cv.filter2D(img, -1, kernel)
print(img2)
输出
[[ 102. 108. 110. 85. -224. -226. 6. 22. 18.]
[ 104. 115. 108. 88. -231. -223. 16. 23. 18.]
[ 100. 100. 100. 94. -224. -230. 17. 23. 22.]
[ 104. 112. 104. 95. -228. -226. 23. 24. 18.]
[ 100. 114. 112. 84. -237. -225. 20. 25. 22.]
[ 102. 130. 126. 79. -244. -222. 26. 27. 18.]]
边缘检测的关键点
显著变化的值:边缘通常对应于绝对值较大的正数或负数,因为这些值表示灰度值的急剧变化。
正负变化的边界:边缘可能出现在正值和负值之间的过渡区域。
具体分析
在输出数组中,以下位置的值绝对值较大,可能是边缘的候选位置:
(0,4): -224
(0,5): -226
(1,4): -231
(1,5): -223
(2,4): -224
(2,5): -230
(3,4): -228
(3,5): -226
(4,4): -237
(4,5): -225
(5,4): -244
(5,5): -222
这些位置的值显著偏离周围的像素值,表明在这些区域灰度值发生了较大的变化,可能是垂直边缘所在的位置。