Sobel算子:

是离散微分算子(discrete differentiation operator),用来计算图像灰度的近似梯度,梯度越大越有可能是边缘。

Soble算子的功能集合了高斯平滑和微分求导,又被称为一阶微分算子,求导算子,在水平和垂直两个方向上求导,得到的是图像在X方法与Y方向梯度图像。

缺点:比较敏感,容易受影响,要通过高斯模糊(平滑)来降噪。

算子是通过权重不同来扩大差异。

梯度计算:(在两个方向求导,假设被作用图像为 I)

水平变化: 将 I 与一个奇数大小的内核 Gx进行卷积。比如,当内核大小为3时, Gx的计算结果为:

垂直变化: 将:math:I 与一个奇数大小的内核 Gy进行卷积。比如,当内核大小为3时, Gy的计算结果为:

img

在图像的每一点,结合以上两个结果求出近似梯度:

img

有时也用下面更简单公式代替,计算速度快:(最终图像梯度)。

img

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import cv2
import numpy as np
#dest = cv2.Sobel(src,ddepth,dx,dy,ksize)
'''
ddepth 图像的深度
dx和dy分别表示水平和竖直方向
ksize是Sobel算子的大小'''
img = cv2.imread("a28.png")
ret,thresh = cv2.threshold(img,127,255,cv2.THRESH_BINARY_INV,0)

#水平
sobel_x = cv2.Sobel(thresh,cv2.CV_64F,1,0,ksize=3)
sobel_x = cv2.convertScaleAbs(sobel_x)


#竖直
sobel_y = cv2.Sobel(thresh,cv2.CV_64F,0,1,ksize=3)
sobel_y = cv2.convertScaleAbs(sobel_y)

#分别计算x和y再求和
sobel_x1_y1 = cv2.addWeighted(sobel_x,0.5,sobel_y,0.5,0)
cv2.imshow("sobel_x1_y1",sobel_x1_y1)

# 不建议使用
sobel_x2_y2 = cv2.Sobel(thresh,cv2.CV_64F,1,1,ksize=3)
sobel_x2_y2 = cv2.convertScaleAbs(sobel_x2_y2)
cv2.imshow('sobel_x2_y2',sobel_x2_y2)
#输出
# res = np.hstack(sobel_x,sobel_y)
cv2.imshow('sobel_x',sobel_x)
cv2.imshow('sobel_y',sobel_y)
cv2.waitKey(0)
cv2.destroyAllWindows()

image-20230304170139314

Sobel/Scharr提取边缘(求导)步骤:

1)高斯模糊平滑降噪:

GaussianBlur( src, dst, Size(3,3), 0, 0, BORDER_DEFAULT );

2)转灰度:

cvtColor( src, gray, COLOR_RGB2GRAY );

3)求X和Y方向的梯度(求导):

Sobel(gray_src, xgrad, CV_16S, 1, 0, 3);

Sobel(gray_src, ygrad, CV_16S, 0, 1, 3);

Scharr(gray_src, xgrad, CV_16S, 1, 0);

Scharr(gray_src, ygrad, CV_16S, 0, 1);

4)像素取绝对值:

convertScaleAbs(A, B); //计算图像A的像素绝对值,输出到图像B

img

5)相加X和Y,得到综合梯度,称为振幅图像:

addWeighted( A, 0.5,B, 0.5, 0, AB); //混合权重相加,效果较差

或者循环获取像素,每个点直接相加,效果更好。