OpenCV——图像梯度

目录

  • 前言
  • 原理
    • Sobel算子与Scharr算子
    • Laplace算子
    • 自定义内核对图像进行卷积
  • 参考问下

前言

梯度简单来说就是求导,OpenCV 提供了三种不同的梯度滤波器,或者说高通滤波器: Sobel,Scharr 和 Laplacian。Sobel, Scharr 其实就是求一阶或二阶导数。 Scharr 是对 Sobel(使用小的卷积核求解求解梯度角度时)的优化。 Laplacian 是求二阶导数。图像上表现出来的就是提取图像的边缘(不管是横向的、纵向的、斜方向的等等)。

原理

Sobel算子与Scharr算子

Sobel算子是高斯平滑与微分操作的结合体,所以其抗噪能力很强,用途较多。一般的sobel算子包括x与y两个方向,算子模板为;
OpenCV——图像梯度_第1张图片
在opencv函数中,还可以设置卷积核(ksize)的大小,如果ksize=-1,就演变为3*3的Scharr算子,模板无非变了个数字:
OpenCV——图像梯度_第2张图片
Sobel算子依然是一种过滤器,只是其是带有方向的。
原型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。

效果图

code

def sobel_demo(image):
    grad_x = cv.Sobel(image,cv.CV_32F,1,0)# 采用CV_32F是怕数据被截断 ,对x求导
    grad_y = cv.Sobel(image,cv.CV_32F,0,1)# 012->0表示这个方向没有进行求导,对y求导

    gradx = cv.convertScaleAbs(grad_x)# 由于算完的图像有正有负,所以对其取绝对值
    grady = cv.convertScaleAbs(grad_y)

    #计算两个图像的权值和。
    gradxy = cv.addWeighted(gradx,0.5,grady,0.5,0)

    cv.imshow("gradx",gradx)
    cv.imshow("grady",grady)
    cv.imshow("gradxy",gradxy)

额外需注意的点:
在Sobel函数的第二个参数这里使用了cv2.CV_16S。因为OpenCV文档中对Sobel算子的介绍中有这么一句:“in the case of 8-bit input images it will result in truncated derivatives”。即Sobel函数求完导数后会有负值,还有会大于255的值。而原图像是uint8,即8位无符号数,所以Sobel建立的图像位数不够,会有截断。因此要使用16位有符号的数据类型,即cv2.CV_16S。
在经过处理后,别忘了用convertScaleAbs()函数将其转回原来的uint8形式。否则将无法显示图像,而只是一副灰色的窗口。convertScaleAbs()的原型为:
dst = cv2.convertScaleAbs(src[, dst[, alpha[, beta]]])
其中可选参数alpha是伸缩系数,beta是加到结果上的一个值。结果返回uint8类型的图片。
由于Sobel算子是在两个方向计算的,最后还需要用cv2.addWeighted(…)函数将其组合起来。其函数原型为:
dst = cv2.addWeighted(src1, alpha, src2, beta, gamma[, dst[, dtype]])
其中alpha是第一幅图片中元素的权重,beta是第二个的权重,gamma是加到最后结果上的一个值。

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。

效果图

code

def laplace_demo(image):
    dst = cv.Laplacian(image,cv.CV_32F)
    lpls = cv.convertScaleAbs(dst)
    cv.imshow("laplace_demo",lpls)

自定义内核对图像进行卷积

函数
dst=cv.filter2D(src, ddepth, kernel[, dst[, anchor[, delta[, borderType]]]])
OpenCV——图像梯度_第3张图片
这个自定义内核对指定图像进行卷积的操作就相当于上面的 Laplace算子法了。甚至效果还会好一点。

效果图

code

def custom_laplace(image):
    # 以下算子与上面的Laplace_demo()是一样的,增强采用np.array([[1, 1, 1], [1, -8, 1], [1, 1, 1]])
    kernel = np.array([[1, 1, 1], [1, -8, 1], [1, 1, 1]])
    dst = cv.filter2D(image, cv.CV_32F, kernel=kernel)
    lpls = cv.convertScaleAbs(dst)
    cv.imshow("custom_laplace", lpls)

参考问下

  1. opencv 图像梯度
  2. OpenCV-Python教程(7、Laplacian算子)

你可能感兴趣的:(OpenCV,opencv)