OpenCV计算机视觉实战 | 第5章 图像梯度算子

本文为课程《OpenCV计算机视觉实战》的课程笔记。

本章节讲述了图像梯度的计算方法。图像的梯度表征每个像素点和周围像素点差异程度。

上:梯度值公式;下:梯度方向公式

1 Sobel算子

Sobel算子关注像素点和上下左右四个像素点的差异程度,即分别从x方向和y方向计算锚点梯度。

首先用 G x × A G_x×A Gx×A得到锚点 x x x方向的梯度,再用 G y × A G_y×A Gy×A得到 y y y方向的梯度。最后将两个方向的梯度加权相加,即可得到锚点的梯度值。※这里的“×”是相同位置元素相乘

捕获

根据上图模型,可知Sobel算子是用锚点右边的像素值减去左边像素值,用下边像素值减去上边像素值注意不是形状外部减去内部)。

CV2中Sobel算子的函数原型如下:

cv2.Sobel(src, ddepth, dx, dy, ksize)
  • ddepth:输出图像的深度(所占位数),-取1表示与原图像一致

  • dx、dy:待计算的梯度方向。例如,当 d x = 1 dx=1 dx=1 d y = 0 dy=0 dy=0时,表示求 x x x方向的一阶导数。

    ※不建议dx、dy同时取1,这样效果不佳。

  • ksize:算子的大小,必须为不大于31的奇数,默认取3(当 k s i z e ≤ 0 ksize\le0 ksize0时,应该取的是默认值)

可选参数还有scaledeltaborderType,具体含义参考这篇博文。

返回值为图像梯度图。


首先看一下用Sobel算子计算圆形图像的结果:

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)

# 求sobelx和sobely的加权和
sobelxy = cv2.addWeighted(sobelx, 0.5, sobely, 0.5, 0)
cv_show('sobelxy',np.hstack((sobelx, sobely, sobelxy)))
image-20220212181305022
左:sobelx;中:sobely;右:sobelxy

计算深度选取了cv2.CV_64F表示64位浮点数(可以存储负数,防止溢出后cv2截断),这篇博文表示imshow()在显示图像时像素点的取值范围为[0, 1]:

  • 若像素值为负数:取绝对值
  • 若像素值大于1:映射为1,否则保留原值

cv2.imshow()处理不同深度的图像时的映射方式如下:

  • CV_8U,范围[0, 255]:显示原图
  • CV_16U,范围[0, 65535]:除以256映射到[0, 255]
  • CV_32F和CV_64F,范围[0, 1]:乘以255映射到[0, 255]

课程讲说,由于 G x G_x Gx是右侧像素点减去左侧像素点,故cv2.Sobel(img, cv2.CV_64F, 1, 0, ksize=3)左半圆的计算结果为正,右半圆的计算结果为负,而cv2.imshow()语句将负数显示为0(说法跟上述博文冲突),因此最后cv2.Sobel(img, cv2.CV_64F, 1, 0, ksize=3)的显示结果为半个圆的轮廓。 G y G_y Gy同理。

sobelx = cv2.convertScaleAbs(sobelx)

cv2.convertScaleAbs()方法先对传入数组取绝对值,然后转换为8位无符号数,从而能够显示完整的轮廓。

2 Scharr算子

靠近锚点的像素点权重更大,因此效果更显著。

cv2中的写法与Sobel算子相近,详见4。

3 Laplacian算子

是二阶导方法,表征的是锚点和周围像素点的差异程度,即变化率。该算子要比Scharr算子和Sobel算子要更敏感,因此更容易受噪音影响。

通常搭配其他方法使用。

cv2中的写法详见4。

4 三种算子的比较

# 不同算子之间的差异
img = cv2.resize(cv2.imread('./img/cat.jpg',cv2.IMREAD_GRAYSCALE),(300, 300))

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)

在这里插入图片描述

原图,Sobel,Scharr,Laplacian

从上图可以看出,通过Sobel算子得到的轮廓较为干净,但细节有限;通过Scharr算子得到的梯度对比强烈,且蕴含信息更丰富;Laplacian算子的计算结果中包含的信息较少。

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值