图像梯度计算的是图像变化的速度,一般情况下图像梯度计算的是图像的边缘信息。本节重点讲述Sobel算法

图像梯度的概述

对于图像的边缘部分,其灰度值变化较大,梯度值也较大,相反,相对于平滑的部分及灰度值变化较小,相应的梯度值也较小。

如在下图中,上下两条红线梯度值变化较大,可以用来计算水平方向的边界。左右也是同理,这里不再赘述。

梯度示意

基于上述的基本原理,进一步优化可以得到更加复杂的边缘信息。本章将关注Sobel算子、Scharr算子和Laplacian算子的使用。

Sobel理论基础

Sobel是一种离散的微分算子,该算子结合了高斯平滑和微分求导运算,利用局部差分寻找边缘,计算所得到的是一个梯度的近似值。

计算水平方向偏导数的近似值

将Sobel算子与原始图像src进行卷积计算,可以计算水平方向上的像素值变化情况。

例如在下面地例子中,有:

数学运算

求解水平方向偏导数

计算垂直方向偏导数的近似值

垂直方向求偏导

Sobel算子及函数使用

dst = cv2.Sobel(src, ddepth, dx, dy[,ksize[,scale[,delta[,borderType]]]])
  • dst表示结果图像
  • src是原始图像
  • ddepth表示输出图像的深度

算子数学原理

  • dx表示x方向上的求导阶数
  • dy表示y方向上的求导阶数
  • scale表示计算导数时的缩放因子,默认为1,表示没有缩放
  • delta表示加在目标图像中的值
  • borderType表示边界样式

参数deepth

计算梯度值可能会出现负值。如果处理的图像是8位图类型,当参数为-1时,运算结果也是8位图类型,所有的负数会自动计算为0,发生信息丢失。为了避免信息丢失,在计算时要先使用更高的数据类型cv2.CV_64F,再通过取绝对值将其映射为cv2.CV_8U所以通常ddepth的值设为cv2.CV_64F

方向

在cv2.Sobel()函数中,参数dx表示x轴方向的求导阶数,参数dy表示y轴方向的求导阶数。参数dx和dy的值为0或1,最大为2.如果是0,表示再该方向上没有求导,dx和dy不能同时为0。

  • 计算x方向边缘:dx = 1,dy = 0

  • 计算y方向边缘:dy = 1,dx = 0

  • 参数dx与参数dy的值均为1:dx = 1,dy = 1

  • 计算x方向和y方向的边缘叠加:通过组合方式实现

代码演示

ddepth = -1导致信息丢失

import cv2
img1 = cv2.imread(r'E:\Blog\OpenCV\jin.png',0)
Soblex = cv2.Sobel(img1,-1,1,0)
cv2.imshow('ORIGINAL',img1)
cv2.imshow('X',Soblex)
cv2.waitKey()

演示结果

获得某方向的完整边缘

要想取得左边界的值,将其显示出来,必须将参数的值设置为更大范围的数据结构类型,并将其映射到8位图像内。

将ddepth的值设置为cv2.CV_64, 并使用函数cv2.convertScaleAbs()cv2.Sobel()的计算结果取绝对值。

import cv2
img1 = cv2.imread(r'E:\Blog\OpenCV\jin.png',0)
Soblex = cv2.Sobel(img1,cv2.CV_64F,1,0)   #ddepth设置为cv2.CV_64F
Soblex = cv2.convertScaleAbs(Soblex)      #对结果取绝对值
cv2.imshow('ORIGINAL',img1)
cv2.imshow('X',Soblex)
cv2.waitKey()

dx = 1,dy = 1获取边缘

import cv2
img1 = cv2.imread(r'E:\Blog\OpenCV\jin.png',0)
Soblex = cv2.Sobel(img1,cv2.CV_64F,1,1)   #dx和dy都是1
Soblex = cv2.convertScaleAbs(Soblex)      #对结果取绝对值
cv2.imshow('ORIGINAL',img1)
cv2.imshow('X',Soblex)
cv2.waitKey()

dx=1,dy=1仅获得了拐点处的轮廓

获取完整边缘

分别使用“dx = 1,dy = 0”和“dx = 0,dy=1”获得边缘,然后进行组合。使用函数cv2.addWeighted()对两个方向进行叠加。

import cv2
from cv2 import Sobel
img1 = cv2.imread(r'E:\Blog\OpenCV\jin.png',0)
Soblex = cv2.Sobel(img1,cv2.CV_64F,1,0)   #dx = 1,dy = 0
Sobley = cv2.Sobel(img1,cv2.CV_64F,0,1)   #dx = 0,dy = 1
Soblex = cv2.convertScaleAbs(Soblex)      #对x结果取绝对值
Sobley = cv2.convertScaleAbs(Sobley)      #对y结果取绝对值
Soblexy = cv2.addWeighted(Soblex,0.5,Sobley,0.5,0)
cv2.imshow('ORIGINAL',img1)
cv2.imshow('XY',Soblexy)
cv2.waitKey()

效果


博主个人公众号
版权声明 ▶ 本网站名称:陶小桃Blog
▶ 本文链接:https://www.52txr.cn/2022/OpenCV29.html
▶ 本网站的文章部分内容可能来源于网络,仅供大家学习与参考,如有侵权,请联系站长进行核实删除。
▶ 转载本站文章需要遵守:商业转载请联系站长,非商业转载请注明出处!!

最后修改:2022 年 06 月 12 日
如果觉得我的文章对你有用,请随意赞赏