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

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

本章介绍如何计算图像梯度。图像的梯度表示每个像素与周围像素之间的差异程度。
OpenCV计算机视觉实战 | 第5章 图像梯度算子

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

1 Sobel算子

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

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

捕获

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

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

cv2.Sobel(src, ddepth, dx, dy, ksize)
  • ddepth:输出图像的深度(所占位数),-取1表示与原图像一致
  • dx、dy:待计算的梯度方向。例如,当dx%3D1dy%3D0时,表示求x方向的一阶导数。
    ※不建议dx、dy同时取1,这样效果不佳。
  • ksize:算子的大小,必须为不大于31的奇数,默认取3(当ksize%5Cle0时,应该取的是默认值)

可选参数还有scale、delta、borderType,具体含义参考这篇博文。

返回值是图像梯度图。

首先看一下用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是右侧像素点减去左侧像素点,故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同理。

sobelx = cv2.convertScaleAbs(sobelx)

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

2 Scharr算子

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

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

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

3 Laplacian算子

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

通常与其他方法结合使用。

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

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)

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

原图,Sobel,Scharr,Laplacian

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

版权声明:本文为博主mustuo原创文章,版权归属原作者,如果侵权,请联系我们删除!

原文链接:https://blog.csdn.net/mustuo/article/details/122979626

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
乘风的头像乘风管理团队
上一篇 2022年2月19日 下午1:57
下一篇 2022年2月19日 下午2:34

相关推荐