Laplacian算子边缘检测的来源
在边缘部分求取一阶导数,你会看到极值的出现:
如果在边缘部分求二阶导数会出现什么情况?
从上例中我们可以推论检测边缘可以通过定位梯度值大于邻域的相素的方法找到(或者推广到大 于一个阀值). 从以上分析中,我们推论二阶导数可以用来检测边缘 。 因为图像是 “2维”, 我们需要在两个方向求导。使用Laplacian算子将会使求导过程变得简单。
Laplacian定义:
代码实现:
import cv2
import numpy as np img=cv2.imread('lenna.png',0)#为了让结果更清晰,图像有3个channel,这里的ksize设为3,
gray_lap=cv2.Laplacian(img,cv2.CV_16S,ksize=3)#拉式算子
dst=cv2.convertScaleAbs(gray_lap)cv2.imshow('laplacian',dst)cv2.waitKey(0)
cv2.destroyAllWindows()
结果展示:
需要注意的几个点:
注意一:
Laplacian算子的调用函数解析
在OpenCV-Python中,Laplace算子的函数原型如下:
dst = cv2.Laplacian(src, ddepth[, dst[, ksize[, scale[, delta[, borderType]]]]])
第一个参数是需要处理的图像;
第二个参数是图像的深度,-1表示采用的是与原图像相同的深度。目标图像的深度必须大于等于原图像的深度;
dst不用解释了;
ksize是算子的大小,必须为1、3、5、7。默认为1。
scale是缩放导数的比例常数,默认情况下没有伸缩系数;
delta是一个可选的增量,将会加到最终的dst中,同样,默认情况下没有额外的值加到dst中;
borderType是判断图像边界的模式。这个参数默认值为cv2.BORDER_DEFAULT。
注意二:
ddepth(目标图像深度)为什么是cv2.CV_16S
?
这里引用了OpenCV 图像梯度 :cv2.Sobel(),cv2.Schar(),cv2.Laplacian() + 数据类型设置:cv2.CV_8U,cv2.CV_16S,cv2.CV_64F
当我们可以通过参数-1 来设定输出图像的深度(数据类型)与原图像保持一致,但是我们在代码中使用的却是cv2.CV_64F。这是为什么呢?想象一下一个从黑到白的边界的导数是整数,而一个从白到黑的边界点导数却是负数。如果原图像的深度是np.int8 时,所有的负值都会被截断变成0,换句话说就是把把边界丢失掉。所以如果这两种边界你都想检测到,最好的的办法就是将输出的数据类型设置的更高,比如cv2.CV_16S,cv2.CV_64F 等。取绝对值然后再把它转回到cv2.CV_8U。下面的示例演示了输出图片的深度不同造成的不同效果。
注意三:
ksize=3
为什么?
laplace内部是调用sobel来实现,而这个算子的大小实际是sobel的kernel_size,用于计算二阶导数的滤波器的孔径尺寸,大小必须为正奇数(正奇数才能有中心点)