【数字图像处理】边缘检测

0. 前言

边缘检测是一种图像处理技术,旨在标识和定位数字图像中的边缘和轮廓。边缘是图像中灰度值变化明显的位置,通常是物体的边缘或表面的变化。通过边缘检测算法,可以将图像中的物体和背景分离出来,从而实现目标检测、图像分割、计算机视觉和机器人视觉等应用。

边缘检测算法的基本原理是在数字图像中寻找灰度变化的位置。其中,最常见的方法是基于图像梯度的边缘检测算法,如Sobel算子、Prewitt算子、Roberts算子和Canny算子等。

1. Sobel算子

Sobel算子将数字图像与两个卷积核Gx和Gy进行卷积,Gx和Gy分别用于计算水平方向和垂直方向上的梯度:
G x = [ − 1 0 1 − 2 0 2 − 1 0 1 ] G_x = \begin{bmatrix}-1 & 0 & 1 \\-2 & 0 & 2 \\-1 & 0 & 1\end{bmatrix} Gx= 121000121 G y = [ − 1 − 2 − 1 0 0 0 1 2 1 ] G_y = \begin{bmatrix}-1 & -2 & -1 \\0 & 0 & 0 \\1 & 2 & 1\end{bmatrix} Gy= 101202101
在计算完Gx和Gy之后,可以计算每个像素的梯度强度和方向:
G = G x 2 + G y 2 G = \sqrt{G_x^2 + G_y^2} G=Gx2+Gy2 θ = tan ⁡ − 1 ( G y G x ) \theta = \tan^{-1}\left(\frac{G_y}{G_x}\right) θ=tan1(GxGy)

import cv2
import numpy as np
import matplotlib.pyplot as plt

# 读取图片
img = cv2.imread("example.jpg", cv2.IMREAD_GRAYSCALE)

# 定义Sobel算子
sobel_x = np.array([[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]])

sobel_y = np.array([[-1, -2, -1], [0, 0, 0], [1, 2, 1]])

# 对图片进行Sobel边缘检测
img_sobel_x = cv2.filter2D(img, -1, sobel_x)
img_sobel_y = cv2.filter2D(img, -1, sobel_y)

# 计算梯度幅值和梯度方向
gradient_magnitude = np.sqrt(img_sobel_x ** 2 + img_sobel_y ** 2)
gradient_magnitude = (gradient_magnitude / gradient_magnitude.max())*255
gradient_direction = np.arctan2(img_sobel_y, img_sobel_x)
gradient_direction = (gradient_direction / gradient_direction.max()) * 255

# 显示结果
fig, axs = plt.subplots(1, 4, figsize=(16, 4))
axs[0].imshow(img, cmap="gray")
axs[0].set_title("Original")
axs[1].imshow(img_sobel_x, cmap="gray")
axs[1].set_title("Sobel X")
axs[2].imshow(img_sobel_y, cmap="gray")
axs[2].set_title("Sobel Y")
axs[3].imshow(gradient_magnitude.astype(np.uint8), cmap="gray")
axs[3].set_title("Gradient Magnitude")
plt.show()

在这里插入图片描述
可以看到,Gx主要检测出了竖直方向上的边缘,Gy主要检测出了水平方向上的边缘。

2. Canny算子

Canny算子是在工业界广泛使用的边缘检测算法,它的主要原理是通过检测图像中像素灰度变化的一阶导数来检测边缘。

Canny算法主要分为以下几个步骤:

  • 去噪
    由于图像中可能存在噪声,并且噪声对边缘检测的影响较大(因为噪声也是高频信息),首先需要对图像进行去噪声处理。常见的方法是使用高斯滤波器对图像进行平滑处理,以减少噪声的影响。

  • 计算梯度
    在图像平滑之后,需要计算每个像素点的梯度值和方向。常用的方法是使用Sobel算子,对图像进行水平和垂直方向上的梯度计算。梯度方向的计算可以通过计算水平和垂直梯度值的反正切来得到。

  • 非极大值抑制
    由于Sobel算子计算的梯度值较大,图像中可能存在多个方向的梯度,需要进行非极大值抑制来确定每个像素点的主要梯度方向。具体来说,对于每个像素点,沿着其梯度方向上的两个邻域像素点进行比较,如果当前像素点的梯度值最大,则保留它,否则将其置为零。

  • 双阈值检测
    经过前面的处理之后,图像中只剩下边缘可能存在的位置。但是,由于图像中存在很多噪声和灰度变化,有些边缘可能会被误判为非边缘。因此需要使用双阈值检测来进一步筛选边缘。将梯度幅值分为两个阈值:高阈值和低阈值。如果一个像素点的梯度幅值大于高阈值,则被认为是边缘像素;如果一个像素点的梯度幅值小于低阈值,则被认为是非边缘像素。如果一个像素点的梯度幅值在两个阈值之间,则只有它与高阈值相连的像素点才被认为是边缘像素。

  • 边缘连接
    经过上述处理之后,图像中可能还存在一些不连续的边缘。因此,需要使用边缘连接算法将它们连接起来。一种常用的方法是使用基于滞后阈值的连接算法。具体来说,从高阈值像素开始,将与其相邻的低阈值像素加入到边缘中,直到不存在低阈。

3. 深度学习算法

3.1 Holistically-Nested Edge Detection(HED)

HED是一个端到端的边缘检测模型,总体架构如下:
在这里插入图片描述
在这里插入图片描述
将移除了全连接层的VGG16作为特征提取器,每个stage会外接一个卷积和sigmoid,用于输出单通道的边缘检测结果,即图中的Side-output。

  • 训练阶段:每个side-output的输出经过上采样至GT的分辨率,然后分别与GT求loss;考虑到图像中的边缘信息占据比例较小,因此引入了 β \beta β解决类别不均衡的问题,对于非边缘像素的损失分配较小的权重。
    在这里插入图片描述
    side部分的总损失等于各个side损失的加权求和
    在这里插入图片描述
    除了side-output,网络还有一个fuse输出,即将所有side输出concat后进行卷积(输出通道为1),然后经过sigmoid输出最终的fuse结果。fuse输出也要利用GT进行监督,损失函数为cross-entropy。
    在这里插入图片描述
    整个网络的优化目标为使side损失和fuse损失最低
    在这里插入图片描述

  • 测试阶段:将所有side-output和fuse-output平均后的结果作为最终的边缘检测结果

3.2 Richer Convolutional Features(RCF)

RCF是针对HED的改进,主要改进有两点:

  • 改进点1:HED的side-output是每个stage最后一个卷积输出的特征图经过卷积和sigmoid得来的,RCF中改为将每个stage中所有卷积的输出经过1×1卷积->求和->1×1卷积->sigmoid后的结果,利用了更丰富的特征信息。

在这里插入图片描述

  • 改进点2:设置一个阈值 η \eta η,小于阈值的不计算损失(分不清到底是边缘还是非边缘),计算非边缘部分的损失时分配一个较小的权重 α \alpha α,计算边缘部分的损失时分配一个较大的权重 β \beta β
    在这里插入图片描述

参考资料

[1] Holistically-Nested Edge Detection
[2] Richer convolutional features for edge detection

猜你喜欢

转载自blog.csdn.net/zxdd2018/article/details/130497099
今日推荐