OpenCV(17-1):图像梯度之一:Sobel算子

图像梯度计算的是图像变化的速度。对于图像的边缘部分,其灰度值变化较大,梯度值也较大;相反,对于图像中比较平滑的部分,其灰度值变化较小,相应的梯度值也较小。一般情况下,图像梯度计算的是图像的边缘信息。严格来讲,图像梯度计算需要求导数,但是图像梯度一般通过计算像素值的差来得到梯度的近似值(近似导数值)。

  1. 我们已经学习了卷积操作。一个最重要的卷积运算就是导数的计算(或者近似计算)。
  2. 为什么对图像进行求导是重要的呢? 假设我们需要检测图像中的 边缘 ,如下图:

可以看到在 边缘 ,相素值显著的 改变 了。表示这一 改变 的一个方法是使用 导数 。 梯度值的大变预示着图像中内容的显著变化。

用更加形象的图像来解释,假设我们有一张一维图形。下图中灰度值的”跃升”表示边缘的存在:

使用一阶微分求导我们可以更加清晰的看到边缘”跃升”的存在(这里显示为高峰值)

从上面我们可以推论检测边缘可以通过定位梯度值大于邻域的相素的方法找到(或者推广到大于一个阀值)。

17.1 什么是图像梯度?

定义

可以把图像看成二维离散函数:

图像梯度其实就是这个二维离散函数的求导:

其中:


其中, 是图像像素的值(如:RGB值), 为像素的坐标。

图像梯度一般也可以用中值差分:



图像边缘一般都是通过对图像进行梯度运算来实现的。

图像梯度的最重要性质是,梯度的方向在图像灰度最大变化率上,它恰好可以反映出图像边缘上的灰度变化。

上面说的是简单的梯度定义,其实还有更多更复杂的梯度公式。

种类

一阶导数与Soble算子

二阶导数与拉普拉斯算子

17.2 Sobel算子

Sobel理论基础

传统计算机视觉利用算子(Operator),以及算子集对进行图像处理,从而获得特征图像。Sobel算子(Sobel operator)Irwin Sobel设计的,广泛用于边缘提取的算子。

  1. Sobel 算子是一个离散微分算子 (discrete differentiation operator)。 它用来计算图像灰度函数的近似梯度。
  2. Sobel 算子结合了高斯平滑和微分求导。

计算过程

第一步:假设被作用图像为I ,在两个方向上求导:

1. 水平变化: 将 I 与一个奇数大小的内核 Gx 进行卷积。比如,当内核大小为3时, Gx 的计算结果为:

2. 垂直变化: 将 I 与一个奇数大小的内核 Gy 进行卷积。比如,当内核大小为3时, Gy 的计算结果为:

第二步:在图像的每一点,结合以上两个结果求出近似 梯度:


有时也用下面更简单公式代替:


 

cv2.Sobel() 函数

原型:dst=cv2.Sobel(src,ddepth,dx,dy[,ksize[,scal[,delta[,borderType]]]])

参数:

  1. dst 代表目标图像。
  2. src 代表原始图像。
  3. ddepth 代表输出图像的深度。
  4. dx 代表 x 方向上的求导阶数。
  5. dy 代表 y 方向上的求导阶数。
  6. ksize 代表 Sobel 核的大小。该值为-1 时,则会使用 Scharr 算子进行运算。
  7. scale 代表计算导数值时所采用的缩放因子,默认情况下该值是 1,是没有缩放的。
  8. delta 代表加在目标图像 dst 上的值,该值是可选的,默认为 0。
  9. borderType 代表边界样式。

返回值:dst

cv2.convertScaleAbs() 函数

在实际操作中,计算梯度值可能会出现负数。通常处理的图像

是 8 位图类型,如果结果也是该类型,那么所有负数会自动截断为 0,发生信息丢失。所以,为了避免信息丢失,我们在计算时使用更高的数据类型 cv2.CV_64F,再通过取绝对值将其映射为 cv2.CV_8U(8 位图)类型。

故此我们还需要调用convertScaleAbs()函数计算绝对值,并将图像转换为8位图进行显示。其算法原型如下:

原型:dst=cv2.convertScaleAbs(src[,dst[,alpha[,beta]]])

参数:

  1. dst 代表处理结果。
  2. src 代表原始图像。
  3. alpha 代表调节系数(透明度),该值是可选值,默认为1
  4. beta 代表调节亮度值,该值是默认值,默认为 0

返回值:dst

示例

import cv2
import numpy as np
import matplotlib.pyplot as plt

#####################################################
# 使用函数 cv2.Sobel()获取图像垂直方向的完整边缘信息#
#####################################################
def sobelx(img):
    sobelx = cv2.Sobel(img,cv2.CV_64F,1,0)
    sobelx = cv2.convertScaleAbs(sobelx) #转回uint8
    return sobelx

#####################################################
# 使用函数 cv2.Sobel()获取图像水平方向的完整边缘信息#
#####################################################
def sobely(img):
    sobely = cv2.Sobel(img,cv2.CV_64F,0,1)
    sobely = cv2.convertScaleAbs(sobely) #转回uint8
    return sobely

########################################################
#计算函数 cv2.Sobel()在水平、垂直两个方向叠加的边缘信息#
#######################################################
def sobelxy(sobelx,sobely):
    sobelxy = cv2.addWeighted(sobelx,0.5,sobely,0.5,0)
    return sobelxy

img = cv2.imread('C:\\Users\\xxx\\Downloads\\pie.png')
sobelx=sobelx(img)
sobely=sobely(img)
sobelxy=sobelxy(sobelx,sobely)

names=['original','sobelx','sobely','sobelxy']
images=[img,sobelx,sobely,sobelxy]

plt.figure(figsize=(25.6,4.8))
for i in range(4):
    plt.subplot(1,4,i+1),plt.imshow(images[i])
    plt.title(names[i],fontsize=30), plt.xticks([]), plt.yticks([])
    num=i
    if num >= len(names)-1:
        break
plt.show()

输入不同的原图(下图中的original,第一个是水平、垂直边缘;第二个是圆边缘),运行结果如下:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值