youcans 的 OpenCV 例程200篇150. 边缘检测梯度算子
Posted 小白YouCans
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了youcans 的 OpenCV 例程200篇150. 边缘检测梯度算子相关的知识,希望对你有一定的参考价值。
欢迎关注 『youcans 的 OpenCV 例程 200 篇』 系列,持续更新中
欢迎关注 『youcans 的 OpenCV学习课』 系列,持续更新中
【youcans 的 OpenCV 例程200篇】150. 边缘检测梯度算子
2. 点、线和边缘检测
本节基于图像灰度的不连续性,讨论根据灰度的突变检测边界,以此为基础进行图像分割。
- 边缘像素是图像中灰度突变的像素,而边缘是相连边缘像素的集合。
- 线是一条细边缘线段,其两侧的背景灰度与线段的像素灰度存在显著差异。
- 孤立的点是一个被背景像素围绕的前景像素,或一个被前景像素围绕的背景像素。
导数可以用来检测灰度的局部突变:
- 一阶导数通常产生粗边缘;
- 二阶导数对精细细节(如细线、孤立点和噪声)的响应更强;
- 二阶导数在灰度斜坡和台阶过渡处会产生双边缘响应,即二阶导数在进入和离开边缘时的符号相反;
- 二阶导数的符号可用于确定边缘的过渡是从亮到暗还是从暗到亮。
计算图像中每个像素位置的一阶导数和二阶导数的方法是空间卷积。对一个 3*3 模板,计算模板区域内灰度值与模板系数的卷积。
2.4 边缘检测的常用梯度算子
边缘检测的基本方法通常是基于一阶导数和二阶导数的,因此需要进行图像的梯度计算。图像的梯度可以用一阶导数和二阶偏导数来求解。
以矩阵形式表达的数字图像 f,任意位置 (x,y) 的梯度
∇
f
\\nabla f
∇f 定义为向量:
∇
f
=
g
r
a
d
(
f
)
=
[
g
x
g
y
]
=
[
∂
f
/
∂
x
∂
f
/
∂
x
]
\\nabla f = grad(f) =\\beginbmatrix g_x \\\\ g_y \\endbmatrix =\\beginbmatrix \\partial f /\\partial x \\\\ \\partial f /\\partial x \\endbmatrix
∇f=grad(f)=[gxgy]=[∂f/∂x∂f/∂x]
梯度算子的前向差分公式为:
g
x
(
x
,
y
)
=
∂
f
(
x
,
y
)
∂
x
=
f
(
x
+
1
,
y
)
−
f
(
x
,
y
)
g
y
(
x
,
y
)
=
∂
f
(
x
,
y
)
∂
y
=
f
(
x
,
y
+
1
)
−
f
(
x
,
y
)
g_x(x,y) = \\dfrac\\partial f(x,y)\\partial x = f(x+1,y) - f(x,y) \\\\ g_y(x,y) = \\dfrac\\partial f(x,y)\\partial y = f(x,y+1) - f(x,y) \\\\
gx(x,y)=∂x∂f(x,y)=f(x+1,y)−f(x,y)gy(x,y)=∂y∂f(x,y)=f(x,y+1)−f(x,y)
梯度向量的幅度 M 和角度
α
\\alpha
α 为:
M
(
x
,
y
)
=
∣
∣
∇
f
∣
∣
=
g
x
2
+
g
y
2
α
(
x
,
y
)
=
a
r
c
t
a
n
[
g
y
/
g
x
]
M(x,y) = ||\\nabla f|| = \\sqrt g_x^2 + g_y^2 \\\\ \\alpha (x,y) = arctan[g_y / g_x]
M(x,y)=∣∣∇f∣∣=gx2+gy2α(x,y)=arctan[gy/gx]
在实际编程中,为了减少计算量,常用绝对值来近似梯度幅度:
M
(
x
,
y
)
≈
∣
g
x
∣
+
∣
g
y
∣
M(x,y) \\approx |g_x| + |g_y|
M(x,y)≈∣gx∣+∣gy∣
根据梯度算子的定义和基本公式,可以发展多种不同的计算算法,称为梯度算子。对于图像的梯度计算,通常采用模板(卷积核)对原图像进行卷积运算来实现。
Robert 梯度算子:
简单的交叉差分算法,利用局部差分算子寻找边缘,采用对角线相邻两像素差作为梯度值检测边缘。形式简单,计算速度快,但对噪声敏感,无法抑制噪声。
Prewitt 算子:
利用两个方向模板与图像进行邻域卷积,一个方向模板检测水平边缘,另一个检测垂直边缘。能够抑制噪声,但对边缘的定位较 Roberts 算子差。
Sobel 算子:
是高斯平滑和微分求导的联合运算,抗噪声能力强。考虑了距离对权值的影响,距离越远的像素的影响越小。可以通过快速卷积实现,简单有效,应用广泛。
Isotropic Sobel 算子:
权值反比于中心距,具有各向同性,沿不同方向检测边缘时梯度幅度一致。
Scharr 算子:
是 Sobel 算子在 ksize=3 时的优化,在平滑部分中心元素占的权重更大,相当于使用更瘦高的平滑模板。与 Sobel 的速度相同,精度更高。
Lapacian 算子:
二阶微分算子,具有各向同向性,与坐标轴无关(无法检测方向)。对噪声非常敏感,可以先进行阈值处理或平滑处理。
这些基本的一阶、二阶微分算子如 Robert、Sobel、Prewitt、Laplacian 等,本质上都可以用于检测边缘,也被称为边缘检测算子。进一步地,考虑边缘和噪声的性质,可以改进边缘检测算子,如 Marr-Hildreth 算子、Canny 算子。
例程 11.4:边缘检测梯度算子
# 11.4 边缘检测的梯度算子 (Roberts 算子, Prewitt 算子, Sobel 算子, Laplacian 算子)
img = cv2.imread("../images/Fig1016a.tif", flags=0) # 读取为灰度图像
# 自定义卷积核
# Roberts 边缘算子
kernel_Roberts_x = np.array([[1, 0], [0, -1]])
kernel_Roberts_y = np.array([[0, -1], [1, 0]])
# Prewitt 边缘算子
kernel_Prewitt_x = np.array([[-1, 0, 1], [-1, 0, 1], [-1, 0, 1]])
kernel_Prewitt_y = np.array([[1, 1, 1], [0, 0, 0], [-1, -1, -1]])
# Sobel 边缘算子
kernel_Sobel_x = np.array([[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]])
kernel_Sobel_y = np.array([[1, 2, 1], [0, 0, 0], [-1, -2, -1]])
# Laplacian 边缘算子
kernel_Laplacian_K1 = np.array([[0, 1, 0], [1, -4, 1], [0, 1, 0]])
kernel_Laplacian_K2 = np.array([[1, 1, 1], [1, -8, 1], [1, 1, 1]])
# 卷积运算
imgBlur = cv2.blur(img, (3,3)) # Blur 平滑后再做 Laplacian 变换
imgLaplacian_K1 = cv2.filter2D(imgBlur, -1, kernel_Laplacian_K1)
imgLaplacian_K2 = cv2.filter2D(imgBlur, -1, kernel_Laplacian_K2)
imgRoberts_x = cv2.filter2D(img, -1, kernel_Roberts_x)
imgRoberts_y = cv2.filter2D(img, -1, kernel_Roberts_y)
imgRoberts = np.uint8(cv2.normalize(abs(imgRoberts_x) + abs(imgRoberts_y), None, 0, 255, cv2.NORM_MINMAX))
imgPrewitt_x = cv2.filter2D(img, -1, kernel_Prewitt_x)
imgPrewitt_y = cv2.filter2D(img, -1, kernel_Prewitt_y)
imgPrewitt = np.uint8(cv2.normalize(abs(imgPrewitt_x) + abs(imgPrewitt_y), None, 0, 255, cv2.NORM_MINMAX))
imgSobel_x = cv2.filter2D(img, -1, kernel_Sobel_x)
imgSobel_y = cv2.filter2D(img, -1, kernel_Sobel_y)
imgSobel = np.uint8(cv2.normalize(abs(imgSobel_x) + abs(imgSobel_y), None, 0, 255, cv2.NORM_MINMAX))
plt.figure(figsize=(12, 8))
plt.subplot(341), plt.title('Origin'), plt.imshow(img, cmap='gray'), plt.axis('off')
plt.subplot(345), plt.title('Laplacian_K1'), plt.imshow(imgLaplacian_K1, cmap='gray'), plt.axis('off')
plt.subplot(349), plt.title('Laplacian_K2'), plt.imshow(imgLaplacian_K2, cmap='gray'), plt.axis('off')
plt.subplot(342), plt.title('Roberts'), plt.imshow(imgRoberts, cmap='gray'), plt.axis('off')
plt.subplot(346), plt.title('Roberts_X'), plt.imshow(imgRoberts_x, cmap='gray'), plt.axis('off')
plt.subplot(3,4,10), plt.title('Roberts_Y'), plt.imshow(imgRoberts_y, cmap='gray'), plt.axis('off')
plt.subplot(343), plt.title('Prewitt'), plt.imshow(imgPrewitt, cmap='gray'), plt.axis('off')
plt.subplot(347), plt.title('Prewitt_X'), plt.imshow(imgPrewitt_x, cmap='gray'), plt.axis('off')
plt.subplot(3,4,11), plt.title('Prewitt_Y'), plt.imshow(imgPrewitt_y, cmap='gray'), plt.axis('off')
plt.subplot(344), plt.title('Sobel'), plt.imshow(imgSobel, cmap='gray'), plt.axis('off')
plt.subplot(348), plt.title('Sobel_X'), plt.imshow(imgSobel_x, cmap='gray'), plt.axis('off')
plt.subplot(3,4,12), plt.title('Sobel_Y'), plt.imshow(imgSobel_y, cmap='gray'), plt.axis('off')
plt.tight_layout()
plt.show()
(本节完)
版权声明:
youcans@xupt 原创作品,转载必须标注原文链接:(https://blog.csdn.net/youcans/article/details/124073181)
Copyright 2022 youcans, XUPT
Crated:2022-4-10
欢迎关注 『youcans 的 OpenCV 例程 200 篇』 系列,持续更新中
欢迎关注 『youcans 的 OpenCV学习课』 系列,持续更新中【youcans 的 OpenCV 例程200篇】01. 图像的读取(cv2.imread)
【youcans 的 OpenCV 例程200篇】02. 图像的保存(cv2.imwrite)
【youcans 的 OpenCV 例程200篇】03. 图像的显示(cv2.imshow)
【youcans 的 OpenCV 例程200篇】04. 用 matplotlib 显示图像(plt.imshow)
【youcans 的 OpenCV 例程200篇】05. 图像的属性(np.shape)
【youcans 的 OpenCV 例程200篇】06. 像素的编辑(img.itemset)
【youcans 的 OpenCV 例程200篇】07. 图像的创建(np.zeros)
【youcans 的 OpenCV 例程200篇】08. 图像的复制(np.copy)
【youcans 的 OpenCV 例程200篇】09. 图像的裁剪(cv2.selectROI)
【youcans 的 OpenCV 例程200篇】10. 图像的拼接(np.hstack)
【youcans 的 OpenCV 例程200篇】11. 图像通道的拆分(cv2.split)
【youcans 的 OpenCV 例程200篇】12. 图像通道的合并(cv2.merge&以上是关于youcans 的 OpenCV 例程200篇150. 边缘检测梯度算子的主要内容,如果未能解决你的问题,请参考以下文章
youcans 的 OpenCV 例程200篇182.基于形态学梯度的分水岭算法
youcans 的 OpenCV 例程200篇179.图像分割之 GrabCut 图割法(掩模图像)