本节将要介绍OpenCV 提供的三种不同的梯度滤波器,或者说高通滤波器:Sobel,Scharr 和 Laplacian。
总的来说:Sobel,Scharr 其实就是求一阶或二阶导数。Scharr 是对 Sobel(使用小的卷积核求解求解梯度角度时)的优化。而Laplacian 是求二阶导数。
其API如下:
dst = cv2.Sobel(src, ddepth, dx, dy[, dst[, ksize[, scale[, delta[, borderType]]]]])
函数返回其处理结果。
前四个是必须的参数:
第一个参数是需要处理的图像;
第二个参数是图像的深度,-1表示采用的是与原图像相同的深度。目标图像的深度必须大于等于原图像的深度;
第三、四参数:dx和dy表示的是求导的阶数,0表示这个方向上没有求导,一般为0、1、2。
其后是可选的参数:
dst不用解释了;
ksize是Sobel算子的大小,必须为1、3、5、7。
scale是缩放导数的比例常数,默认情况下没有伸缩系数;
delta是一个可选的增量,将会加到最终的dst中,同样,默认情况下没有额外的值加到dst中;
borderType是判断图像边界的模式。这个参数默认值为cv2.BORDER_DEFAULT。
注意:第二个参数在代码中通常使用的却是 cv2.CV_16S,cv2.CV_64F。这是为什么呢?想象一下一个从黑到白的边界的导数是整数,而一个从白到黑的边界点导数却是负数。如果原图像的深度是np.int8 时,所有的负值都会被截断变成 0,换句话说就是把把边界丢失掉。所以如果这两种边界你都想检测到,最好的的办法就是将输出的数据类型设置的更高,比如 cv2.CV_16S,cv2.CV_64F 等。取绝对值然后再把它转回到 cv2.CV_8U。
import cv2
import numpy as np
filenames = '/longmao.png'
img = cv2.imread(filenames)
cv2.imshow('orginal',img)
#sobel处理
imgx = cv2.Sobel(img,cv2.CV_16S,1,0,ksize=3)
imgy = cv2.Sobel(img,cv2.CV_16S,0,1,ksize=3)
#转回uint8
imgx_uint8 = cv2.convertScaleAbs(imgx)
imgy_uint8 = cv2.convertScaleAbs(imgy)
#x,y方向组合
img = cv2.addWeighted(imgx_uint8,0.5,imgy_uint8,0.5,0)
cv2.imshow('sobelimg',img)
cv2.waitKey(0)
cv2.destroyAllWindows()
结果:
二、Scharr算子
基本和Sobel算子一样,只是没有了超参数ksize,使用固定的3*3ksize。
#scharr处理
sobelimgx = cv2.Scharr(img,cv2.CV_16S,1,0)
sobelimgy = cv2.Scharr(img,cv2.CV_16S,0,1)
三、Laplacian 算子
图像中的边缘区域,像素值会发生“跳跃”,对这些像素求导,在其一阶导数在边缘位置为极值,这就是Sobel算子使用的原理——极值处就是边缘。如下图:
Laplace函数实现的方法是先用Sobel 算子计算二阶x和y导数,再求和
#laplace处理
laplace = cv2.Laplacian(img,cv2.CV_16S,ksize=3)
#转回uint8
laplace_img = cv2.convertScaleAbs(laplace)
结果: