图像梯度

原理

关于这一个知识点,有一篇非常好的博客在此推荐:

图像梯度——Sobel ,Scharr和Laplacian详解

梯度简单来说就是求导。

OpenCV 提供了三种不同的梯度滤波器,或者说高通滤波器:Sobel,Scharr 和 Laplacian。

Sobel,Scharr 其实就是求一阶或二阶导数。Scharr 是对 Sobel(使用小的卷积核求解求解梯度角度时)的优化。Laplacian 是求二阶导数。

1 Sobel 算子和 Scharr 算子

Sobel 算子是高斯平滑与微分操作的结合体,所以它的抗噪声能力很好。你可以设定求导的方向(xorder 或 yorder)。还可以设定使用的卷积核的大小(ksize)。如果 ksize=-1,会使用 3x3 的 Scharr 滤波器,它的的效果要比 3x3 的 Sobel 滤波器好(而且速度相同,所以在使用 3x3 滤波器时应该尽量使用 Scharr 滤波器)。

3x3 的 Sobel 滤波器卷积核如下:
在这里插入图片描述
在水平方向上,梯度 = 右边 × 权重 - 左边 × 权重
在竖直方向上,梯度 = 下边 × 权重 - 上边 × 权重

dst = cv2.Sobel(src, ddepth, dx, dy, ksize)
ddepth:图像的深度
dx和dy分别表示水平和竖直方向
ksize是Sobel算子的大小

例如:

import cv2
import numpy as np

def cv_show(img,name):
    cv2.imshow(name,img)
    cv2.waitKey()
    cv2.destroyAllWindows()

img = cv2.imread('C:/Users/www12/Desktop/pie.png',cv2.IMREAD_GRAYSCALE)

cv_show(img, 'img')

sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3)

cv_show(sobelx,'sobelx')

sobely = cv2.Sobel(img,cv2.CV_64F,0,1,ksize=3)

cv_show(sobely,'sobely')

原图:
在这里插入图片描述
使用了Sobel算子处理水平方向之后的图:
在这里插入图片描述
使用了Sobel算子处理竖直方向之后的图:
在这里插入图片描述
要是想同时处理水平和竖直方向,有两种方法:

第一种方法:分别计算x和y,再求和

sobelxy = cv2.addWeighted(sobelx,0.5,sobely,0.5,0)
cv_show(sobelxy,'sobelxy')

在这里插入图片描述
第二种方法:直接计算

在这里插入图片描述
第二种方法效果明显不太好,所以尽量不要直接计算!!

一个重要的事!
在查看上面这个例子的注释时不知道你有没有注意到:当我们可以通过参数 -1 来设定输出图像的深度(数据类型)与原图像保持一致,但是我们在代码中使用的却是 cv2.CV_64F。这是为什么呢?想象一下一个从黑到白的边界的导数是整数,而一个从白到黑的边界点导数却是负数。如果原图像的深度是np.int8 时,所有的负值都会被截断变成 0,换句话说就是把把边界丢失掉。所以如果这两种边界你都想检测到,最好的的办法就是将输出的数据类型设置的更高,比如 cv2.CV_16S,cv2.CV_64F 等。取绝对值然后再把它转回到 cv2.CV_8U。

3x3 的 Scharr 滤波器卷积核如下:

在这里插入图片描述
Scharr 滤波器形式和Sobel滤波器形式差不多,唯一的不同就是Scharr滤波器更精确,更敏感!

2 Laplacian 算子

拉普拉斯算子可以使用二阶导数的形式定义,可假设其离散实现类似于二阶 Sobel 导数,事实上,OpenCV 在计算拉普拉斯算子时直接调用 Sobel 算子。计算公式如下:

在这里插入图片描述
拉普拉斯滤波器使用的卷积核:

在这里插入图片描述
拉普拉斯滤波器就不仅仅是简单的对水平或者竖直方向的处理了,其对噪声敏感,会产生双边效果。不能检测出边的方向。通常不直接用于边的检测,只起辅助的角色,检测一个像素是在边的亮的一边还是暗的一边利用零跨越,确定边的位置。

下面的代码分别使用以上三种滤波器对同一幅图进行操作。

import cv2
import numpy as np

#不同算子的差异
img = cv2.imread('C:/Users/www12/Desktop/lena.jpg',cv2.IMREAD_GRAYSCALE)

sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3)
sobely = cv2.Sobel(img,cv2.CV_64F,0,1,ksize=3)
sobelx = cv2.convertScaleAbs(sobelx)   
sobely = cv2.convertScaleAbs(sobely)  
sobelxy =  cv2.addWeighted(sobelx,0.5,sobely,0.5,0)  

scharrx = cv2.Scharr(img,cv2.CV_64F,1,0)
scharry = cv2.Scharr(img,cv2.CV_64F,0,1)
scharrx = cv2.convertScaleAbs(scharrx)   
scharry = cv2.convertScaleAbs(scharry)  
scharrxy =  cv2.addWeighted(scharrx,0.5,scharry,0.5,0) 

laplacian = cv2.Laplacian(img,cv2.CV_64F)
laplacian = cv2.convertScaleAbs(laplacian)   

res = np.hstack((img, sobelxy,scharrxy,laplacian))
cv_show(res,'res')

在这里插入图片描述
可以看出,Scharr对边缘检测的效果比Sobel更好,因为其对梯度的变化更为敏感,而Laplacian不太适合边缘检测,其用于去除噪音更合适。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值