151. 边缘检测中的平滑处理

9. 阈值处理与边缘检测索引

一、边缘检测的常用梯度算子

  • 边缘检测的基本方法通常是基于一阶导数和二阶导数的,因此需要进行图像的梯度计算。图像的梯度可以用一阶导数和二阶偏导数来求解。

  • 根据梯度算子的定义和基本公式,可以发展多种不同的计算算法,称为梯度算子。对于图像的梯度计算,通常采用模板(卷积核)对原图像进行卷积运算来实现。

    • Robert 梯度算子:
      简单的交叉差分算法,利用局部差分算子寻找边缘,采用对角线相邻两像素差作为梯度值检测边缘。形式简单,计算速度快,但对噪声敏感,无法抑制噪声。
    • Prewitt 算子:
      利用两个方向模板与图像进行邻域卷积,一个方向模板检测水平边缘,另一个检测垂直边缘。能够抑制噪声,但对边缘的定位较 Roberts 算子差。
    • Sobel 算子:
      是高斯平滑和微分求导的联合运算,抗噪声能力强。考虑了距离对权值的影响,距离越远的像素的影响越小。可以通过快速卷积实现,简单有效,应用广泛。
    • Isotropic Sobel 算子:
      权值反比于中心距,具有各向同性,沿不同方向检测边缘时梯度幅度一致。
    • Scharr 算子:
      是 Sobel 算子在 ksize=3 时的优化,在平滑部分中心元素占的权重更大,相当于使用更瘦高的平滑模板。与 Sobel 的速度相同,精度更高。
    • Lapacian 算子:
      二阶微分算子,具有各向同向性,与坐标轴无关(无法检测方向)。对噪声非常敏感,可以先进行阈值处理或平滑处理。
  • 这些基本的一阶、二阶微分算子如 Robert、Sobel、Prewitt、Laplacian 等,本质上都可以用于检测边缘,也被称为边缘检测算子。
    进一步地,考虑边缘和噪声的性质,可以改进边缘检测算子,如 Marr-Hildreth 算子、Canny 算子。

二、例程

  • 11.5 边缘检测算子:平滑处理的影响
    本例程比较平滑操作对边缘检测的影响。
    原始图像分辨率高,精细的细节丰富,使图像中主要边缘检测过于复杂。因此,先对原图像进行平滑处理,再进行梯度卷积运算,可以获得图像的主要边缘,忽略不必要的细节。
import cv2
import numpy as np
from matplotlib import pyplot as plt


# 11.5 边缘检测算子:平滑操作的影响
img = cv2.imread(r"E:/OpenCV/building.jpg", 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_的博客:
https://blog.csdn.net/youcans/article/details/124091831
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容