← 返回首页
图像梯度处理
发表时间:2025-02-20 06:48:08
图像梯度处理

图像梯度是图像处理中的一个重要概念,它描述了图像灰度值在空间上的变化情况。通过计算梯度的模和方向,可以实现边缘检测、特征提取等应用。常见的梯度计算方法包括 Sobel 算子、Laplacian 算子等。

1.图像的梯度与边缘

严格的说,梯度计算需要求导数。但是图像梯度的计算,是通过计算像素值的差得到梯度的近似值。图像梯度表示的是图像变化的速度,反映了图像的边缘信息。边缘是像素值快速变化的地方,其灰度值变化较大,梯度值也较大;对于图像中较平滑的部分,其灰度值变化较小,梯度值也较小。

图像的梯度通俗来说就是图像在不同方向上的变化趋势。图像梯度可以把图像看成二维离散函数f(x,y),图像梯度其实就是这个二维离散函数的求导(即f(x,y)的求导得G(x,y)):

图像边缘:对于图像的边缘部分,其灰度值变化较大,梯度值变化也较大;相反,对于图像中比较平滑的部分,其灰度值变化较小,相应的梯度值变化也较小。 **一般情况下,图像梯度计算的是图像的边缘信息。 ** 在梯度图像中,值越高的部分,越接近人眼视觉所观察到的边缘。因此,我们可以用梯度更直接的解释边缘:边缘是图像能量急剧变化的地方,是图像梯度高的地方。

边缘类型:

边缘检测的目的是标识数字图像中亮度变化明显的点。图像属性中的显著变化通常反映了属性的重要事件和变化。其中包括“深度上的不连续”、“表面方向不连续”、“物质属性变化”和“场景照明变化。

边缘类型:简单分为4种类型,阶跃型、屋脊型、斜坡型、脉冲型,其中阶跃型和斜坡型是类似的,只是变化的快慢不同。下图是阶跃型和屋脊型示意图。

2.边缘检测算子分类

边缘检测算子分类分为一阶导数的边缘算子和二阶导数的边缘算子。一阶导数常用算子有Roberts算子和Sobel算子。二阶导数边缘算子常用的有拉普拉斯(Laplacian) 算子。

2.1 Roberts算子

Roberts算子是一种经典的边缘检测算法,属于一阶微分边缘检测算子。它通过计算图像在局部区域内的梯度变化来检测边缘,是一种简单而有效的边缘检测方法。以下是关于Roberts算子的详细介绍:

Roberts算子基于图像的梯度概念,通过计算图像在水平和垂直方向上的局部梯度来检测边缘。它利用两个2×2的卷积核分别对图像进行卷积运算,从而得到水平方向和垂直方向的梯度分量。

Roberts算子的卷积核定义如下:

Roberts算子特点 优点: - 简单快速:Roberts算子的卷积核非常小(2×2),计算复杂度低,适合对实时性要求较高的场景。 - 对边缘敏感:能够有效检测图像中的边缘信息,尤其适合检测图像中亮度变化较大的区域。

缺点: - 对噪声敏感:由于其卷积核较小,容易受到图像噪声的影响,导致误检。 - 边缘定位不够精确:由于卷积核仅考虑了2×2的局部区域,对边缘的定位精度不如Sobel算子或Canny算子。

Roberts算子常用于以下场景: - 图像预处理:在图像处理的早期阶段,用于快速检测边缘信息。 - 医学图像分析:用于检测医学图像中的结构边缘,如X光或CT图像。 - 简单目标检测:在对实时性要求较高的目标检测任务中,作为初步边缘检测手段。

在Opencv中使用filter2D是实现Roberts算子边缘检测的工具之一。

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

# 用来正常显示中文标签
plt.rcParams['font.sans-serif'] = ['SimHei']

img = cv2.imread("./images/jpg/small_bird01.jpg")
img_RGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)  # 转成RGB 方便后面显示
# 灰度化处理图像
grayImage = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 自定义Roberts算子
kernelx = np.array([[-1, 0], [0, 1]], dtype=int)
kernely = np.array([[0, -1], [1, 0]], dtype=int)
x = cv2.filter2D(grayImage, cv2.CV_16S, kernelx)
y = cv2.filter2D(grayImage, cv2.CV_16S, kernely)
# 转uint8
absX = cv2.convertScaleAbs(x)
absY = cv2.convertScaleAbs(y)
# 按照相同的权重相加
Roberts = cv2.addWeighted(absX, 0.5, absY, 0.5, 0)
# 显示图形
plt.subplot(121), plt.imshow(img_RGB), plt.title('原始图像'), plt.axis('off')  # 坐标轴关闭
plt.subplot(122), plt.imshow(Roberts, cmap=plt.cm.gray), plt.title('Roberts算子'), plt.axis('off')
plt.show()

2.2 Sobel算子

Sobel算子是一种经典的边缘检测算法,属于一阶微分边缘检测算子。它通过计算图像在水平和垂直方向上的梯度变化来检测边缘,同时对噪声具有一定的抑制能力,因此比Roberts算子更为常用。Sobel算子基于图像的梯度概念,通过计算图像在水平和垂直方向上的局部梯度来检测边缘。它利用两个3×3的卷积核分别对图像进行卷积运算,从而得到水平方向和垂直方向的梯度分量。与Roberts算子相比,Sobel算子的卷积核更大,能够更好地抑制噪声。

Sobel算子的卷积核定义如下:

假设我们有一个简单的图像区域,像素的灰度值如下:

我们用水平方向的Sobel算子(Gₓ)计算该区域的水平梯度:

计算中心像素(150)的水平梯度: - 左侧:(-1)×100 + (-2)×100 + (-1)×100 = -400 - 右侧:1×200 + 2×200 + 1×250 = 950 - 中心:0×150 + 0×150 + 0×150 = 0

总和 = -400 + 950 + 0 = 550 所以,中心像素的水平梯度(Gₓ)是550。 类似地,我们可以用垂直方向的Sobel算子计算垂直梯度(Gᵧ),然后结合Gₓ和Gᵧ计算梯度大小和方向。每个像素的梯度强度计算公式如下:

Sobel算子特点 优点: - 对噪声有抑制能力:由于卷积核较大(3×3),能够对局部区域内的像素进行加权平均,从而对噪声有一定的抑制作用。 - 边缘检测效果较好:能够较为准确地检测出图像中的边缘,尤其适合检测图像中亮度变化较大的区域。 - 计算效率较高:虽然卷积核比Roberts算子大,但仍然属于线性滤波器,计算复杂度较低,适合实时应用。

缺点: - 对噪声仍有一定敏感性:尽管比Roberts算子更鲁棒,但在高噪声环境下仍可能产生误检。 - 边缘定位不够精确:与Canny算子相比,Sobel算子的边缘定位精度较低。

Sobel算子常用于以下场景: - 图像预处理:在图像处理的早期阶段,用于快速检测边缘信息。 - 特征提取:在计算机视觉中,用于提取图像的边缘特征,为后续的目标检测或识别任务提供输入。 - 医学图像分析:用于检测医学图像中的结构边缘,如X光或CT图像。 - 机器人视觉:用于检测环境中的边缘信息,帮助机器人进行路径规划或目标识别。

代码实现:

import cv2 as cv
import matplotlib.pyplot as plt

# 用来正常显示中文标签
plt.rcParams['font.sans-serif'] = ['SimHei']
# 读取图像
img = cv.imread('./images/jpg/small_bird01.jpg', cv.COLOR_BGR2GRAY)
rgb_img = cv.cvtColor(img, cv.COLOR_BGR2RGB)
# 灰度化处理图像
grayImage = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
# Sobel 算子
x = cv.Sobel(grayImage, cv.CV_16S, 1, 0)
y = cv.Sobel(grayImage, cv.CV_16S, 0, 1)
# 转 uint8 ,图像融合
absX = cv.convertScaleAbs(x)
absY = cv.convertScaleAbs(y)
Sobel = cv.addWeighted(absX, 0.5, absY, 0.5, 0)
# 显示图形
titles = ['原始图像', 'Sobel算子']
images = [rgb_img, Sobel]
for i in range(2):
    plt.subplot(1, 2, i + 1), plt.imshow(images[i], 'gray')
    plt.title(titles[i])
    plt.xticks([]), plt.yticks([])
plt.show()

2.3 拉普拉斯(Laplacian) 算子

Laplacian(拉普拉斯)算子是一种二阶导数算子,其具有旋转不变性,可以满足不同方向的图像边缘锐化(边缘检测)的要求。通常情况下,其算子的系数之和需要为零。拉普拉斯(Laplacian) 算子是 维欧几里德空间中的一个二阶微分算子,常用于图像增强领域和边缘提取。它通过灰度差分计算邻域内的像素。

算法基本流程

  1. 判断图像中心像素灰度值与它周围其他像素的灰度值,如果中心像素的灰度更高,则提升中心像素的灰度;反之降低中心像素的灰度,从而实现图像锐化操作;
  2. 在算法实现过程中,Laplacian算子通过对邻域中心像素的四方向或八方向求梯度,再将梯度相加起来判断中心像素灰度与邻域内其他像素灰度的关系;
  3. 最后通过梯度运算的结果对像素灰度进行调整。

Laplacian算子分为四邻域和八邻域,四邻域是对邻域中心像素的四个方向求梯度,八邻域是对八个方向求梯度。

其中,Laplacian算子四邻域模板如下所示:

Laplacian算子的八邻域模板如下所示:

通过Laplacian算子的模板可以发现: 1. 当邻域内像素灰度相同时,模板的卷积运算结果为0; 2. 当中心像素灰度高于邻域内其他像素的平均灰度时,模板的卷积运算结果为正数; 3. 当中心像素的灰度低于邻域内其他像素的平均灰度时,模板的卷积为负数。对卷积运算的结果用适当的衰弱因子处理并加在原中心像素上,就可以实现图像的锐化处理。

在OpenCV中,可以使用cv2.Laplacian()函数来计算拉普拉斯算子。以下是一个简单的代码示例:

import cv2
#读取原图
image = cv2.imread('./images/jpg/small_bird01.jpg', cv2.IMREAD_UNCHANGED)

# 读取图像并转换为灰度图
image_gray = cv2.imread('./images/jpg/small_bird01.jpg', cv2.IMREAD_GRAYSCALE)

# 使用Laplacian算子进行边缘检测
laplacian = cv2.Laplacian(image_gray, cv2.CV_64F, ksize=3)

# 取绝对值并转换为8位无符号整数
laplacian = cv2.convertScaleAbs(laplacian)

# 显示结果
cv2.imshow('Original Image', image)
cv2.imshow('Laplacian Edges', laplacian)
cv2.waitKey(0)
cv2.destroyAllWindows()