是离散微分算子(discrete differentiation operator),用来计算图像灰度的近似梯度,梯度越大越有可能是边缘。
Soble算子的功能集合了高斯平滑和微分求导,又被称为一阶微分算子,求导算子,在水平和垂直两个方向上求导,得到的是图像在X方法与Y方向梯度图像。
缺点:比较敏感,容易受影响,要通过高斯模糊(平滑)来降噪。Sobel算子并没有将图像的主体与背景严格地区分开来,换言之就是Sobel算子没有基于图像灰度进行处理,由于Sobel算子没有严格地模拟人的视觉生理特征,所以提取的图像轮廓有时并不能令人满意。
梯度计算:(在两个方向求导,假设被作用图像为 I)
水平变化: 将 I 与一个奇数大小的内核 Gx进行卷积。比如,当内核大小为3时, Gx的计算结果为:
垂直变化: 将:math:I 与一个奇数大小的内核 Gy进行卷积。比如,当内核大小为3时, Gy的计算结果为:
在图像的每一点,结合以上两个结果求出近似梯度:
有时也用下面更简单公式代替,计算速度快:(最终图像梯度)。
cv2.Sobel( src, ddepth, dx, dy[,ksize[, scale[, delta[, borderType]]]] )
dst 代表目标图像。
src 代表原始图像。
ddepth 代表输出图像的深度。
dx 代表 x 方向上的求导阶数。
dy 代表 y 方向上的求导阶数。
ksize 代表 Sobel 核的大小。该值为-1 时,则会使用 Scharr 算子进行运算。
scale 代表计算导数值时所采用的缩放因子,默认情况下该值是 1,是没有缩放的。
delta 代表加在目标图像 dst 上的值,该值是可选的,默认为 0。
borderType 代表边界样式。
在实际操作中,计算梯度值可能会出现负数。通常处理的图像
是 8 位图类型,如果结果也是该类型,那么所有负数会自动截断为 0,发生信息丢失。所以,为了避免信息丢失,我们在计算时使用更高的数据类型 cv2.CV_64F,再通过取绝对值将其映射为 cv2.CV_8U(8 位图)类型。
故此我们还需要调用convertScaleAbs()函数计算绝对值,并将图像转换为8位图进行显示。其算法原型如下:
convertScaleAbs(src[, dst[, alpha[, beta]]])
dst 代表处理结果。
src 代表原始图像。
alpha 代表调节系数,该值是可选值,默认为 1。
beta 代表调节亮度值,该值是默认值,默认为 0。
import cv2
import matplotlib.pyplot as plt
import numpy as np
img =cv2.imread("./cycle.png",cv2.IMREAD_COLOR)
kernel = np.ones((5,5),np.uint8)
opening = cv2.morphologyEx(img,cv2.MORPH_OPEN,kernel)
cv2.imshow("opening",opening)
sobelx = cv2.Sobel(opening,cv2.CV_64F,1,0,ksize=3)
sobelx = cv2.convertScaleAbs(sobelx)
cv2.imshow("sobelx",sobelx)
sobely = cv2.Sobel(opening,cv2.CV_64F,0,1,ksize=3)
sobely = cv2.convertScaleAbs(sobely)
cv2.imshow("sobely",sobely)
sobel = cv2.addWeighted(sobelx,0.5,sobely,0.5,0)
cv2.imshow("sobel",sobel)
cv2.waitKey(0)
cv2.destroyAllWindows()
结果显示
为了能够有效的提取出较弱的边缘,需要将像素值间的差距增大,因此引入Scharr算子。Scharr算子是对Sobel算子差异性的增强,因此两者之间的在检测图像边缘的原理和使用方式上相同。Scharr算子的边缘检测滤波的尺寸为3×3,因此也有称其为Scharr滤波器。可以通过将滤波器中的权重系数放大来增大像素值间的差异,Scharr算子就是采用的这种思想,其在X方向和Y方向的边缘检测算子如中所示
Scharr(src, ddepth, dx, dy[, dst[, scale[, delta[, borderType]]]])
参数就不一一解释了,类似于sobel
laplacian 算子,从图中可以看出当前点的位置与周围4个点位置之差, 即周围四个点之和 - 4*当前位置像素点,这种算法容易受到噪声点的干扰,不存在x和y轴的计算过程
cv2.Laplacian(src, ddepth)
import cv2
import matplotlib.pyplot as plt
import numpy as np
img =cv2.imread("./lena.jpg",cv2.IMREAD_GRAYSCALE)
sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3)
sobelx = cv2.convertScaleAbs(sobelx)
sobely = cv2.Sobel(img,cv2.CV_64F,0,1,ksize=3)
sobely = cv2.convertScaleAbs(sobely)
sobel = cv2.addWeighted(sobelx,0.5,sobely,0.5,0)
scharrx = cv2.Scharr(img,cv2.CV_64F,1,0)
scharrx = cv2.convertScaleAbs(scharrx)
scharry = cv2.Scharr(img,cv2.CV_64F,0,1)
scharry = cv2.convertScaleAbs(scharry)
scharr = cv2.addWeighted(scharrx,0.5,scharry,0.5,0)
laplacian = cv2.Laplacian(img,cv2.CV_64F)
laplacian = cv2.convertScaleAbs(laplacian)
res = np.hstack((img,sobel,scharr,laplacian))
cv2.imshow("res",res)
cv2.waitKey(0)
cv2.destroyAllWindows()
结果展示
三种算子的结果与原图对比