【youcans 的 OpenCV 例程200篇】151. 边缘检测中的平滑处理
2. 点、线和边缘检测
2.4 边缘检测的常用梯度算子
边缘检测的基本方法通常是基于一阶导数和二阶导数的,因此需要进行图像的梯度计算。图像的梯度可以用一阶导数和二阶偏导数来求解。
根据梯度算子的定义和基本公式,可以发展多种不同的计算算法,称为梯度算子。对于图像的梯度计算,通常采用模板(卷积核)对原图像进行卷积运算来实现。
Robert 梯度算子:
简单的交叉差分算法,利用局部差分算子寻找边缘,采用对角线相邻两像素差作为梯度值检测边缘。形式简单,计算速度快,但对噪声敏感,无法抑制噪声。
Prewitt 算子:
利用两个方向模板与图像进行邻域卷积,一个方向模板检测水平边缘,另一个检测垂直边缘。能够抑制噪声,但对边缘的定位较 Roberts 算子差。
Sobel 算子:
是高斯平滑和微分求导的联合运算,抗噪声能力强。考虑了距离对权值的影响,距离越远的像素的影响越小。可以通过快速卷积实现,简单有效,应用广泛。
Isotropic Sobel 算子:
权值反比于中心距,具有各向同性,沿不同方向检测边缘时梯度幅度一致。
Scharr 算子:
是 Sobel 算子在 ksize=3 时的优化,在平滑部分中心元素占的权重更大,相当于使用更瘦高的平滑模板。与 Sobel 的速度相同,精度更高。
Lapacian 算子:
二阶微分算子,具有各向同向性,与坐标轴无关(无法检测方向)。对噪声非常敏感,可以先进行阈值处理或平滑处理。
这些基本的一阶、二阶微分算子如 Robert、Sobel、Prewitt、Laplacian 等,本质上都可以用于检测边缘,也被称为边缘检测算子。进一步地,考虑边缘和噪声的性质,可以改进边缘检测算子,如 Marr-Hildreth 算子、Canny 算子。
例程 11.5 边缘检测算子:平滑处理的影响
本例程比较平滑操作对边缘检测的影响。
原始图像分辨率高,精细的细节丰富,使图像中主要边缘检测过于复杂。因此,先对原图像进行平滑处理,再进行梯度卷积运算,可以获得图像的主要边缘,忽略不必要的细节。
# 11.5 边缘检测算子:平滑操作的影响
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]])
# 梯度算子直接卷积运算
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))
# 先图像平滑,再用梯度算子
imgBlur = cv2.blur(img, (5,5)) # Blur 平滑后再做 Laplacian 变换
imgRoberts_x = cv2.filter2D(imgBlur, -1, kernel_Roberts_x)
imgRoberts_y = cv2.filter2D(imgBlur, -1, kernel_Roberts_y)
blurRoberts = np.uint8(cv2.normalize(abs(imgRoberts_x) + abs(imgRoberts_y), None, 0, 255, cv2.NORM_MINMAX))
imgPrewitt_x = cv2.filter2D(imgBlur, -1, kernel_Prewitt_x)
imgPrewitt_y = cv2.filter2D(imgBlur, -1, kernel_Prewitt_y)
blurPrewitt = np.uint8(cv2.normalize(abs(imgPrewitt_x) + abs(imgPrewitt_y), None, 0, 255, cv2.NORM_MINMAX))
imgSobel_x = cv2.filter2D(imgBlur, -1, kernel_Sobel_x)
imgSobel_y = cv2.filter2D(imgBlur, -1, kernel_Sobel_y)
blurSobel = np.uint8(cv2.normalize(abs(imgSobel_x) + abs(imgSobel_y), None, 0, 255, cv2.NORM_MINMAX))
plt.figure(figsize=(9, 6))
plt.subplot(231), plt.title('Roberts'), plt.imshow(imgRoberts, cmap='gray'), plt.axis('off')
plt.subplot(234), plt.title('Blur-Roberts'), plt.imshow(blurRoberts, cmap='gray'), plt.axis('off')
plt.subplot(232), plt.title('Prewitt'), plt.imshow(imgPrewitt, cmap='gray'), plt.axis('off')
plt.subplot(235), plt.title('Blur-Prewitt'), plt.imshow(blurPrewitt, cmap='gray'), plt.axis('off')
plt.subplot(233), plt.title('Sobel'), plt.imshow(imgSobel, cmap='gray'), plt.axis('off')
plt.subplot(236), plt.title('Blur-Sobel'), plt.imshow(blurSobel, cmap='gray'), plt.axis('off')
plt.tight_layout()
plt.show()
(本节完)
版权声明:
youcans@xupt 原创作品,转载必须标注原文链接:(https://blog.csdn.net/youcans/article/details/124091831)
Copyright 2022 youcans, XUPT
Crated:2022-4-10