cv2.Sobel()

2022-09-02 19:52:54 浏览数 (1)

函数cv2.Sobel(src, ddepth, dx, dy[, ksize[, scale[, delta[, borderType]]]])

概述:利用Sobel算子进行图像梯度计算

参数

  • src:输入图像
  • ddepth: 输出图像的深度(可以理解为数据类型),-1表示与原图像相同的深度
  • dx,dy:当组合为dx=1,dy=0时求x方向的一阶导数,当组合为dx=0,dy=1时求y方向的一阶导数(如果同时为1,通常得不到想要的结果)
  • ksize:(可选参数)Sobel算子的大小,必须是1,3,5或者7,默认为3。求X方向和Y方向一阶导数时,卷积核分别为:
  • scale:(可选参数)将梯度计算得到的数值放大的比例系数,效果通常使梯度图更亮,默认为1
  • delta:(可选参数)在将目标图像存储进多维数组前,可以将每个像素值增加delta,默认为0
  • borderType:(可选参数)决定图像在进行滤波操作(卷积)时边沿像素的处理方式,默认为BORDER_DEFAULT

返回值

梯度图

细节讲解:

1. 图像深度

图像深度是指存储每个像素值所用的位数,例如cv2.CV_8U,指的是8位无符号数,取值范围为0~255,超出范围则会被截断(截断指的是,当数值大于255保留为255,当数值小于0保留为0,其余不变)。

具体还有:CV_16S(16位无符号数),CV_16U(16位有符号数),CV_32F(32位浮点数),CV_64F(64位浮点数)

e.g.

代码语言:javascript复制
  1. import cv2
  2. #载入原图,图像深度为CV_8U
  3. img_original=cv2.imread('E:ShannonT\notebook workspace\images\4.28.9.jpg',0)
  4. #求X方向梯度,并且输出图像一个为CV_8U,一个为CV_64F
  5. img_gradient_X_8U=cv2.Sobel(img_original,-1,1,0)
  6. img_gradient_X_64F=cv2.Sobel(img_original,cv2.CV_64F,1,0)
  7. #将图像深度改为CV_8U
  8. img_gradient_X_64Fto8U=cv2.convertScaleAbs(img_gradient_X_64F)
  9. #图像显示
  10. cv2.imshow('X_gradient_8U',img_gradient_X)
  11. cv2.imshow('X_gradient_64Fto8U',img_gradient_X_64Fto8U)
  12. cv2.waitKey()
  13. cv2.destroyAllWindows()

效果如下:

当输出图像深度采用CV_8U,由于Sobel算子在计算X方向梯度时,如果某像素点右侧像素值大于左侧像素值,则梯度大小为正保留,相反梯度大小为负被截断,梯度大小保存为0。从案例上看就表现一条线和两条线的区别。

2. 函数cv2.convertScaleAbs()的使用

在上述案例案例中,我们使用了函数cv2.convertScaleAbs()将图像深度为CV_64F的梯度图像重新转化为CV_8U,这是由于函数cv2.imshow()的默认显示为8位无符号数,即[0,255]。先来看一下两者显示的差别(左图为8U,右图为64F):

可以发现当图像深度为CV_64F时,显示时有明显缺陷,具体原因可以参考:https://blog.csdn.net/weixin_42216109/article/details/89707220

下面具体介绍函数cv2.convertScaleAbs()

函数cv2.convertScaleAbs(src[,alpha[,beta]])

概述:

先计算数组绝对值,后转化为8位无符号数

参数:

  • src:输入图像(多维数组)
  • alpha:比例因子
  • beta:保存新图像(数组)前可以增加的值

e.g.

将一个numpy数组通过cv2.convertScaleAbs()转化

代码语言:javascript复制
  1. import numpy as np
  2. test=np.array([[100,56.4,300],[-200,-280,-34.6]])
  3. result=cv2.convertScaleAbs(test)
  4. result

结果显示如下:

3. 原图归一化

防止梯度大小被截断最简单的方法就是先将输入图像归一化(实际归一化的过程就已经实现了图像深度的转变),通过下面的例子实际说明

代码语言:javascript复制
  1. import cv2
  2. import numpy as np
  3. #载入灰度原图,图像深度为CV_8U
  4. img_original=cv2.imread('E:ShannonT\notebook workspace\images\4.28.9.jpg',0)
  5. #原图归一化,实际图像深度已经变为CV_64F
  6. img_standard=img_original/255
  7. #采用灰度原图求X方向梯度
  8. original_gradient_X_64F=cv2.Sobel(img_original,cv2.CV_64F,1,0)
  9. original_gradient_X_64Fto8U=cv2.convertScaleAbs(original_gradient_X_64F)
  10. #采用归一化的图像求X方向梯度
  11. standard_gradient_X=cv2.Sobel(img_standard,-1,1,0)
  12. #图像显示
  13. cv2.imshow('original',img_original)
  14. cv2.imshow('original_X',original_gradient_X_64Fto8U)
  15. cv2.imshow('standard_X',standard_gradient_X)
  16. cv2.waitKey()
  17. cv2.destroyAllWindows()

效果如下,可以看出,两种方法作用相同,而归一化的方法更方便

4. 梯度图像的计算

通过cv2.Sobel()我们可以轻松计算出X,Y方向的梯度大小,根据公式

可以求出梯度图像,实际操作时,为了简化运算,我们使用公式

求梯度图像,以下是代码实现,利用的函数为cv2.addWeighted(),有关函数更多信息可以参考:https://blog.csdn.net/zh_jessica/article/details/77992578

代码语言:javascript复制
  1. import cv2
  2. import numpy as np
  3. #载入灰度原图,并且归一化
  4. img_original=cv2.imread('E:ShannonT\notebook workspace\images\4.28.9.jpg',0)/255
  5. #分别求X,Y方向的梯度
  6. grad_X=cv2.Sobel(img_original,-1,1,0)
  7. grad_Y=cv2.Sobel(img_original,-1,0,1)
  8. #求梯度图像
  9. grad=cv2.addWeighted(grad_X,0.5,grad_Y,0.5,0)
  10. cv2.imshow('gradient',grad)
  11. cv2.waitKey()
  12. cv2.destroyAllWindows()

结果如下:

0 人点赞