OpenCV计算图像梯度

Sobel算子

  • 如何理解梯度?
    我们可以把梯度理解为一个图像的边界点。
  • 如何计算梯度,我们可以之前定义kernel函数,对图像中的某一个点进行计算。同时我们还需要计算要从两个方向入手,1:水平计算;2:垂直计算。Sobel算子的计算公式如下如所示:
    在这里插入图片描述
  • 通过代码及展现形式可以更深入地了解用法:
#dst = cv2.Sobel(src, ddepth, dx, dy, ksize)
#src:图像
#ddepth:图像的深度
#dx和dy分别表示水平和竖直方向
#ksize是Sobel算子的大小

def cv_show(img,name):
    cv2.imshow(name,img)
    cv2.waitKey()
    cv2.destroyAllWindows()
sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3)
cv_show(sobelx,'sobelx')    

在这里插入图片描述

  • 为什么只显示了半边的边界呢?因为白到黑是正数,黑到白就是负数了,所有的负数会被截断成0,所以要取绝对值。优化代码如下:
sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3)
sobelx = cv2.convertScaleAbs(sobelx)
cv_show(sobelx,'sobelx')

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

在这里插入图片描述
在这里插入图片描述

  • 计算完x,y之后在进行相加操作:
#这里的0.5表示的是图像的权重,0表示表示的是偏置项,默认为0
sobelxy = cv2.addWeighted(sobelx,0.5,sobely,0.5,0)
cv_show(sobelxy,'sobelxy')

在这里插入图片描述

  • 这里不建议直接计算,这可能导致最后得到的梯度图像效果非常差,如下图所示:
sobelxy=cv2.Sobel(img,cv2.CV_64F,1,1,ksize=3)
sobelxy = cv2.convertScaleAbs(sobelxy) 
cv_show(sobelxy,'sobelxy')

在这里插入图片描述

  • 实战一下,我继续使用Lena这个图像进行操作。
img = cv2.imread('lena.jpg',cv2.IMREAD_GRAYSCALE)
sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3)
sobelx = cv2.convertScaleAbs(sobelx)
sobely = cv2.Sobel(img,cv2.CV_64F,0,1,ksize=3)
sobely = cv2.convertScaleAbs(sobely)
sobelxy = cv2.addWeighted(sobelx,0.5,sobely,0.5,0)
cv_show(sobelxy,'sobelxy')

在这里插入图片描述

Scharr算子

  • Scharr算子公式如下图所示:
    在这里插入图片描述
  • 相比较Sobel,Scharr算子距离点近的值很大,而距离较远的值相对较小,整体数值要比Sobel大,最终对计算结果的差异性会更明显。
  • 使用的函数为cv2.Scharr,具体实现与Sobel类似。

Laplacian算子

  • Sobel算子是模拟一阶求导,导数越大的地方说明变换越明显,越有可能是边缘,而Laplacian使用到了二阶导(一阶导的变化率),虽然对于变化更敏感,但是同时会对噪音点也会更加敏感,反而影响了最终结果。所以需要配合其他工具一起使用才能得到更好的效果。
  • Laplacian矩阵公式如下图所示
    在这里插入图片描述
  • 使用的函数为cv2.Laplacian,这个函数无需考虑到X,Y,用上去更简单了。

不同算子直接的比较

  • 我们继续使用Lena这个图片来进行操作
img = cv2.imread('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((sobelxy,scharrxy,laplacian))
cv_show(res,'res')

在这里插入图片描述

  • 从上面的图片我们可以到,相比于Sobel算子使用Scharr算子可以把本不是特别明显的边界也能展示出来。而拉普拉斯算子就好像有点拉胯了,当然它是需要配合其他工具一起使用的,效果才能更好。
  • 4
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值