17.3 Scharr算子
理论基础
Sobel算子,虽然可以有效提取图像边缘,但是对图像中较弱的边缘提取效果较差。
这是由于Sebel算子在计算相对较小的核时,其近似计算导数的精度比较低,例如使用3*3的Sobel算子时,在梯度角接近水平或垂直方向时,其不精确度就非常明显。
因此引入Scharr算子。Scharr算子是对Sobel算子差异性的增强,两者在检测图像边缘的原理和使用方式上相同。
Scharr算子的主要思路是通过将模板中的权重系数放大来增大像素值间的差异。
Scharr算子又称为Scharr滤波器,也就是计算x或y方向上的图像差分,在openCV中主要是配合Sobel算子的运算而存在的。
cv2.Scharr()函数
使用Scharr算子,有两种方法,一种是在cv2.Soble()中将ksize 代表 Sobel 核的大小。该值为-1 时,则会使用 Scharr 算子进行运算。另一种就是cv2.Scharr()函数
原型:
dst=cv2.Scharr(src,ddepth,dx,dy[,dst=None[,scale=None[,delta=None[,borderType=None]]]])
参数:
- dst 代表目标图像。
- src 代表原始图像。
- ddepth 代表输出图像的深度。
- dx 代表 x 方向上的求导阶数。
- dy 代表 y 方向上的求导阶数。
- scale 代表计算导数值时所采用的缩放因子,默认情况下该值是 1,是没有缩放的。
- delta 代表加在目标图像 dst 上的值,该值是可选的,默认为 0。
- borderType 代表边界样式。
返回值:dst
17.4 laplacian算子
前一节我们学习了 Sobel 算子 ,其基础来自于一个事实,即在边缘部分,像素值出现”跳跃“或者较大的变化。如果在此边缘部分求取一阶导数,你会看到极值的出现。正如下图所示:
如果在边缘部分求二阶导数会出现什么情况?
你会发现在一阶导数的极值位置,二阶导数为0。所以我们也可以用这个特点来作为检测图像边缘的方法。 但是, 二阶导数的0值不仅仅出现在边缘(它们也可能出现在无意义的位置),但是我们可以过滤掉这些点。
laplacian 算子
从以上分析中,我们推论二阶导数可以用来 检测边缘 。 因为图像是 “2维”, 我们需要在两个方向求导。使用Laplacian算子将会使求导过程变得简单。
Laplacian 算子 的定义:
laplacian 算子的设计,从下图中可以看出当前点的位置与周围4个点位置之差, 即周围四个点之和减去 4*当前位置像素点,这种算法容易受到噪声点的干扰,不存在x和y轴的计算过程:
与Sobel算子和Scharr算子计算(先计算x方向、y方向,再计算将两个方向加权)不同,Laplacain算子是一步获取结果。
cv2.Laplacian()函数
OpenCV函数 Laplacian 实现了Laplacian算子。 实际上,由于 Laplacian使用了图像梯度,它内部调用了 Sobel 算子。
Laplacian函数实现的方法是先用Sobel算子计算二阶x和y导数,再求和。
原型:
dst=cv2.Laplacian(src,ddepth, dst=None,ksize=None,scale=None,delta=None,borderType=None)
参数:
- dst 代表目标图像。
- src 代表原始图像。
- ddepth 代表输出图像的深度。
- ksize 代表 计算导数的核的大小。必须是正数的奇数。当kszie的为1时,就是上面的(1,-4)矩阵。
- scale 代表计算导数值时所采用的缩放因子,默认情况下该值是 1,是没有缩放的。
- delta 代表加在目标图像 dst 上的值,该值是可选的,默认为 0。
- borderType 代表边界样式。
返回值:dst
17.5 三种算子的综合例子
import cv2
import numpy as np
import matplotlib.pyplot as plt
# 第一步读取图片为灰度图
img = cv2.imread('C:\\Users\\xxx\\Downloads\\picture1.jpeg', cv2.IMREAD_GRAYSCALE)
# 第二步:使用cv2.Sobel进行sobel算子计算
sobel_x = cv2.Sobel(img, cv2.CV_64F, 1, 0)
sobel_y = cv2.Sobel(img, cv2.CV_64F, 0, 1)
sobel_x = cv2.convertScaleAbs(sobel_x)
sobel_y = cv2.convertScaleAbs(sobel_y)
sobel_xy = cv2.addWeighted(sobel_x, 0.5, sobel_y, 0.5, 0)
# 第三步:使用cv2.Scharr进行scharr算子计算
scharr_x = cv2.Scharr(img, cv2.CV_64F, 1, 0)
scharr_y = cv2.Scharr(img, cv2.CV_64F, 0, 1)
scharr_x = cv2.convertScaleAbs(scharr_x)
scharr_y = cv2.convertScaleAbs(scharr_y)
scharr_xy = cv2.addWeighted(scharr_x, 0.5, scharr_y, 0.5, 0)
# 第四步: 使用cv2.Laplacian 拉普拉斯算子计算
lapkacian = cv2.Laplacian(img, cv2.CV_64F)
lapkacian = cv2.convertScaleAbs(lapkacian)
# 第五步: 对原图和三种结果进行画图
cv2.namedWindow('imgs',0)
cv2.imshow('imgs', np.hstack((img,sobel_xy, scharr_xy, lapkacian)))
cv2.waitKey(0)
cv2.destroyAllWindows()
运行结果为: