在离散的空间上,有很多方法可以用来计算近似导数,在使用3×3的Sobel算子时,可能计算结果并不太精准。OpenCV提供了Scharr算子,该算子具有和Sobel算子同样的速 度,且精度更高。可以将Scharr算子看作对Sobel算子的改进,其核通常为:
OpenCV提供了函数cv2.Scharr()来计算Scharr算子,其语法格式如下:
dst=cv2.Scharr(src,ddepth,dx,dy[,scale[,delta[,borderType]]])
式中:
● dst代表输出图像。
● src代表原始图像。
● ddepth代表输出图像深度。该值与函数cv2.Sobel()中的参数ddepth的含义相同。
● dx代表x方向上的导数阶数。
● dy代表y方向上的导数阶数。
● scale代表计算导数值时的缩放因子,该项是可选项,默认值是1,表示没有缩放。
● delta代表加到目标图像上的亮度值,该项是可选项,默认值为0。
● borderType代表边界样式。
在函数cv2.Sobel()中介绍过,如果ksize=-1,则会使用Scharr滤波器。 因此,如下语句:dst=cv2.Scharr(src,ddepth,dx,dy)和 dst=cv2.Sobel(src,ddepth,dx,dy,-1) 是等价的。
函数cv2.Scharr()和函数cv2.Sobel()的使用方式基本一致。 首先,需要注意的是,参数ddepth的值应该设置为“cv2.CV_64F”,并对函数 cv2.Scharr()的计算结果取绝对值,才能保证得到正确的处理结果。
另外,需要注意的是,在函数cv2.Scharr()中,要求参数dx和dy满足条件:
dx >=0 && dy >=0 && dx+dy==1
因此,参数dx和参数dy的组合形式有:
● 计算x方向边缘(梯度):dx=1,dy=0。
● 计算y方向边缘(梯度): dx=0,dy=1。
● 计算x方向与y方向的边缘叠加:通过组合方式实现。
import cv2 as cv
def cv_show(name, img):
cv.imshow(name, img)
cv.waitKey(0)
cv.destroyAllWindows()
img = cv.imread('D:\\qipan.jpg')
if img is None:
print('Failed to read the image')
# x方向边缘检测
img1 = cv.Scharr(img, cv.CV_64F, 1, 0)
scharrx = cv.convertScaleAbs(img1)
cv_show('scharrx', scharrx)
# y方向边缘检测
img2 = cv.Scharr(img, cv.CV_64F, 0, 1)
scharry = cv.convertScaleAbs(img2)
cv_show('scharry', scharry)
# 需要注意的是,参数dx和dy的值不能都为1。例如,如下语句是错误的:
# dst=Scharr(src,ddpeth,dx=1,dy=1)
scharr = cv.addWeighted(scharrx, 0.5, scharry, 0.5, 0)
cv_show('scharr', scharr)
原图如下:
x方向边缘检测:
y方向边缘检测:
x,y方向叠加效果: