Sobel算子

1.Sobel算子

  • 卷积的作用除了实现图像模糊或者去噪,还可以寻找一张图像上所有梯度信息,这些梯度信息是图像的最原始特征数据,进一步处理之后就可以生成一些比较高级的特征用来表示一张图像实现基于图像特征的匹配,图像分类等应用。
  • Sobel算子是一种很经典的图像梯度提取算子,其本质是基于图像空间域卷积,背后的思想是图像一阶导数算子的理论支持。
  • sobel算子主要用于获得数字图像的一阶梯度,常见的应用和物理意义是边缘检测。(Laplacian边缘检测并不局限于水平方向或垂直方向,这是Laplacian与soble的区别)

 

2.Sobel算子的实现

Sobel本质是基于图像空间域卷积,先来理解下卷积的基础知识。

2.1 卷积

    1. 待处理的数字图像可以看做是一个大矩阵,图像的每个像素对应着矩阵的每个元素,假设我们的图像分辨率为1024x768,那么对应大矩阵的的行数则为1024,列数为768.
    2. 用于滤波(卷积核不止用于滤波)的小矩阵(也叫卷积核),一般是一个方阵,也就是行数和列数相同,比如常见的边缘检测Sobel算子为3x3的矩阵。
    3. 滤波就是对于大矩阵中的每个像素,计算它周围和滤波器矩阵对应位置元素的乘积,最后把乘积结果相加到一起,最终得到的值就作为该像素的新值。这样就对一个像素完成了一次滤波 

 

 

2.2 Sobel算子

该算子包含两组3x3的矩阵,分别为横向及纵向,将之与图像作平面卷积,即可分别得出横向及纵向的亮度差分近似值。其公式如下: 

 

 

其中:

  • I代表原始图像,
  • Gx及Gy分别代表经横向及纵向边缘检测的图像灰度值
  • G表示图像的每一个像素的横向及纵向灰度值 有两种计算方式
  • Scharr,比Sobel算子的值更大,因此对于灰度变化更为敏感,会得到较强的边缘强度,但是也会损失一些细节

如果想计算x方向梯度,我们就需要这样的一个卷积核

 

 

以卷积核的中心为中心,将卷积核与图像上像素值一一对应,卷积核上的数字相当于系数。利用如下公式即可计算出卷积核中心的x方向梯度。

 

 

同理,如果想要计算y方向的梯度,卷积核应该是这样的,公式也是同理。

 

 

我们求得了某一像素x方向和y方向的梯度,那么该像素的梯度容易得出:

 

 

但是这个公式比较难算,对公式进行简化,所以我们一般直接把这个公式化作:

 

 

Sobel函数

opencv中提供给我们封装好的Sobel算子函数,不需要我们一一计算。
其构造函数如下:

cv2.Sobel(src,ddepth,dx,dy,ksize)

参数解释:

src:原图
ddepth:处理结果图像深度,一般我们都填-1,即与原图深度相同。但在这里我们需要填写cv2.CV_64F。简单来说就是如果填写-1,我们在计算梯度时产生的负数就会被程序默认为0,导致有一边的边缘出不来。而cv2.CV_64F范围更大,可以保留负数。
dx:计算x方向的梯度
dy:计算y方向的梯度
ksize:卷积核的尺寸。默认为3,即3*3的矩阵。

函数在使用时。如果我们想要计算x方向的梯度:

cv2.Sobel(src,ddepth,1,0,ksize)

反之,计算y方向的梯度

cv2.Sobel(src,ddepth,0,1,ksize)

当然,想要计算总梯度直接dx=1,dy=1也是可以的,但是效果十分不好。不建议使用这种方法。
我们通常使用的方法是按权相加法。按权相加x方向梯度和y方向梯度。使用cv2.addWeight()函数,该函数支持五个参数:

  • src1:第一幅图像
  • weight1:第一幅图像的权重
  • src2:第二幅图像
  • weight2:第二幅图像的权重
  • 偏置值

我们还要注意一件事。在我们分别计算完x、y方向的权值时,里面是有负数的。我们需要对这些负数取绝对值,否则照样会被归为0。
取绝对值的函数是cv2.convertScaleAbs(img)

import numpy as np
import cv2
img=cv2.imread('D://zopencv//qi.jpg',0)
mask_x=cv2.Sobel(img,cv2.CV_64F,1,0)#计算x方向梯度
mask_y=cv2.Sobel(img,cv2.CV_64F,0,1)
img_x=cv2.convertScaleAbs(mask_x)#取绝对值
img_y=cv2.convertScaleAbs(mask_y)
mask=cv2.addWeighted(img_x,0.5,img_y,0.5,0)#按权相加
#mask=cv2.Sobel(img,cv2.CV_64F,1,1)
Archie=cv2.resize(mask,None,fx=0.5,fy=0.5,interpolation=cv2.INTER_AREA)#图片太大了,缩小图片
cv2.imshow('Archie',Archie)
cv2.waitKey(0)
cv2.destroyAllWindows()

 

posted @ 2022-04-29 15:53  IllidanStormrage  阅读(4831)  评论(0编辑  收藏  举报