OpenCV–033_2: 图像梯度–Sobel算子

OpenCV–033_2: 图像梯度–Sobel算子索贝尔算子(Sobeloperator)主要用作边缘检测,在技术上,它是一离散性差分算子,用来运算图像亮度函数的灰度之近似值。在图像的任何一点使用此算子,将会产生对应的灰度矢量或是其法矢量。Sobel算子是一种常用的边缘检测算子,是一阶的梯度算法;Sobel算子是结合了高斯平滑与微分运算的结合方法,所以它的抗噪声能力很强。用户可以设定求导方向,水平或者垂直(通过参数yorder和xord…

大家好,欢迎来到IT知识分享网。

索贝尔算子(Sobel operator)

主要用作边缘检测,在技术上,它是一离散性差分算子,用来运算图像亮度函数的灰度之近似值。在图像的任何一点使用此算子,将会产生对应的灰度矢量或是其法矢量。

Sobel算子是一种常用的边缘检测算子,是一阶的梯度算法;Sobel算子是结合了高斯平滑与微分运算的结合方法,所以它的抗噪声能力很强。用户可以设定求导方向,水平或者垂直(通过参数yorder和xorder)。也可以指定卷积核大小,通过参数ksize。如果ksize=-1,那么一个3*3的scharr滤波器会被使用,该滤波器会得到比Sobel滤波器更好的效果

对噪声具有倾斜作用,提供精确的边缘信息,边缘定位精度不够高;当对精度要求不是很高时,是一种多种常用的边缘检测方法。

常见的应用和物理意义是边缘检测。

在这里插入图片描述


Sobel卷积因子为:
在这里插入图片描述
该算子包含两组3×3的矩阵,分别为横向及纵向,将之与图像作平面卷积,即可分别得出横向及纵向的亮度差分近似值。如果以A代表原始图像,Gx及Gy分别代表经横向及纵向边缘检测的图像灰度值,其公式如下:
在这里插入图片描述

具体计算如下:
其中f(a,b), 表示图像(a,b)点的灰度值;
G x = ( − 1 ) ∗ f ( x − 1 , y − 1 ) + 0 ∗ f ( x , y − 1 ) + 1 ∗ f ( x + 1 , y − 1 ) G_x=(-1)*f(x-1,y-1)+0*f(x,y-1)+1*f(x+1,y-1) Gx=(1)f(x1,y1)+0f(x,y1)+1f(x+1,y1)
         + ( − 2 ) ∗ f ( x − 1 , y ) + 0 ∗ f ( x , y ) + 2 ∗ f ( x + 1 , y ) + (-2)*f(x-1,y)+0*f(x,y)+2*f(x+1,y) +(2)f(x1,y)+0f(x,y)+2f(x+1,y)
         + ( − 1 ) ∗ f ( x − 1 , y + 1 ) + 0 ∗ f ( x , y + 1 ) + 1 ∗ f ( x + 1 , y + 1 ) +(-1)*f(x-1,y+1)+0*f(x,y+1)+1*f(x+1,y+1) +(1)f(x1,y+1)+0f(x,y+1)+1f(x+1,y+1)

结果: [f(x+1,y-1)+2f(x+1,y)+f(x+1,y+1)]-[f(x-1,y-1)+2f(x-1,y)+f(x-1,y+1)]

G y = 1 ∗ f ( x − 1 , y − 1 ) + 2 ∗ f ( x , y − 1 ) + 1 ∗ f ( x + 1 , y − 1 ) G_y=1*f(x-1,y-1)+2*f(x,y-1)+1*f(x+1,y-1) Gy=1f(x1,y1)+2f(x,y1)+1f(x+1,y1)
         + 0 ∗ f ( x − 1 , y ) + 0 ∗ f ( x , y ) + 0 ∗ f ( x + 1 , y ) + 0*f(x-1,y)+0*f(x,y)+0*f(x+1,y) +0f(x1,y)+0f(x,y)+0f(x+1,y)
         + ( − 1 ) ∗ f ( x − 1 , y + 1 ) + ( − 2 ) ∗ f ( x , y + 1 ) + ( − 1 ) ∗ f ( x + 1 , y + 1 ) +(-1)*f(x-1,y+1)+(-2)*f(x,y+1)+(-1)*f(x+1,y+1) +(1)f(x1,y+1)+(2)f(x,y+1)+(1)f(x+1,y+1)

结果:[f(x-1,y-1) + 2f(x,y-1) + f(x+1,y-1)]-[f(x-1, y+1) + 2*f(x,y+1)+f(x+1,y+1)]

  • 图像的每一个像素的横向及纵向灰度值通过以下公式结合,来计算该点灰度的大小:
    G = G x 2 + G y 2 G=\sqrt {G_x^2+G_y^2} G=Gx2+Gy2

    通常,为了提高效率 使用不开平方的近似值:
    ∣ G ∣ = ∣ G x ∣ + ∣ G y ∣ |G|=|G_x|+|G_y| G=Gx+Gy
    如果梯度G大于某一阀值 则认为该点(x,y)为边缘点。

梯度方向:
角 度 值 = a r c t a n ( G y G x ) 角度值=arctan(\frac{G_y}{G_x}) =arctan(GxGy)

Sobel提取边缘步骤:

  1. 高斯模糊平滑降噪

  2. 转灰度空间

  3. 求X和Y方向的梯度(求导)

     Sobel(src,xsrc,CV_16S,1,0,3);
     Sobel(src,ysrc,CV_16S,0,1,3);
    
  4. 像素取绝对值
    convertScaleAbs(A,B);//计算图像A的像素绝对值,输出到图像B

  5. 相加X和Y,得到综合梯度,称为振幅图像。
    addWeighted(A,0.5,B,0.5,0,AB);//混合权重相加,效果较差

OpenCV中的API

1. Sobel
  • 函数说明
    使用扩展的Sobel运算符计算第一,第二,第三或混合图像导数。
  • 函数声明
    void Sobel( 
         InputArray src, 
         OutputArray dst, 
         int ddepth,
         int dx, 
         int dy, 
         int ksize = 3,
         double scale = 1, 
         double delta = 0,
         int borderType = BORDER_DEFAULT
    );
    
  • 函数参数
    src 输入图像。
    dst 输出与src相同大小和相同通道数的图像。
    ddepth 输出图像深度
    dx 表示x方向上的差分阶数,1或0 。
    dy 表示y 方向上的差分阶数,1或0 。
    ksize 表示Sobel算子的大小;它必须是1、3、5或7。注意:只可以是小于7 的奇数。
    scale 表示缩放导数的比例常数,默认情况下没有伸缩系数。
    delta 表示一个可选的增量,将会加到最终的dst中,同样,默认情况下没有额外的值加到dst中。

    ddepth参数表示输出图像深度,针对不同的输入图像,输出目标图像有不同的深度。
    具体组合如下:

    • src.depth() = CV_8U,
      ddepth = -1 / CV_16S / CV_32F / CV_64F
    • src.depth() = CV_16U/CV_16S,
      ddepth = -1/CV_32F/CV_64F
    • src.depth() = CV_32F,
      ddepth = -1/CV_32F/CV_64F
    • src.depth() = CV_64F,
      ddepth = -1/CV_64F
    • 当 ddepth为-1时, 输出图像将和输入图像有相同的深度。输入8位图像则会截取顶端的导数。

在这里插入图片描述

2. convertScaleAbs
  • 函数说明
    缩放,计算绝对值,然后将结果转换为8位。

    在输入数组的每个元素上,函数convertScaleAbs依次执行三个操作:缩放,获取绝对值,转换为无符号的8位类型:
    d s t ( I ) = s a t u r a t e _ c a s t < u c h a r > ( ∣ s r c ( I ) ∗ a l p h a + b e t a ∣ ) dst(I)=saturate\_cast<uchar>(|src(I)∗alpha+beta|) dst(I)=saturate_cast<uchar>(src(I)alpha+beta)
    如果是多通道阵列,该函数将独立处理每个通道。当输出不是8位时,可以通过调用Mat :: convertTo方法(或使用矩阵表达式),然后通过计算结果的绝对值来模拟该操作。

  • 函数声明

    void convertScaleAbs(
           InputArray src, 
           OutputArray dst,
           double alpha = 1, 
           double beta = 0
           );
    
  • 函数参数

    src 输入数组
    dst 输出数组
    alpha 可选比例因子。
    beta 可选增量添加到缩放值。

在这里插入图片描述

3. addWeighted
  • 函数说明
    计算两个数组的加权和。

    函数addWeighted计算两个数组的加权和,如下所示:
    d s t ( I ) = s a t u r a t e ( s r c 1 ( I ) ∗ a l p h a + s r c 2 ( I ) ∗ b e t a + g a m m a ) dst(I)=saturate(src1(I)∗alpha+src2(I)∗beta+gamma) dst(I)=saturate(src1(I)alpha+src2(I)beta+gamma)
    I是数组元素的多维索引。在多通道阵列的情况下,每个通道都是独立处理的。该函数可以替换为矩阵表达式:
    d s t = s r c 1 ∗ a l p h a + s r c 2 ∗ b e t a + g a m m a dst = src1 * alpha + src2 * beta + gamma dst=src1alpha+src2beta+gamma

    注意
    当输出数组的深度为CV_32S时,不应用Saturation。在溢出的情况下,您甚至可能会得到错误符号的结果。

  • 函数声明

    void addWeighted(	
    			InputArray 	src1,
    			double 	alpha,
    			InputArray 	src2,
    			double 	beta,
    			double 	gamma,
    			OutputArray 	dst,
    			int 	dtype = -1 
              )	
    
  • 函数参数

    src1 第一个输入数组
    alpha 第一个数组元素的权重
    src2 第二个输入数组
    beta 第二个数组元素的权重
    gamma 参数表示一个加到权重总和上的标量值
    dst 输出数组,其大小和通道数与输入数组相同
    dtype 输出数组的可选深度;当两个输入数组的深度相同时,dtype可以设置为-1,等效于src1.depth()
  • 应用举例

    Mat src=imread("D:/test/src.jpg",0);
    Mat dst_x, dst_y,dst;
    
    GaussianBlur(src, dst_x, Size(3,3), 0,0);
    imshow("src", src);
    
    Sobel(src, dst_x, CV_16S,1, 0, 3);
    Sobel(src, dst_y, CV_16S,0, 1, 3);
    
    convertScaleAbs(dst_x , dst_x);
    convertScaleAbs(dst_y , dst_y);
    
    addWeighted(dst_x, 0.5, dst_y, 0.5,0, dst)imshow("src", src);
    imshow("dst_x", dst_x);
    imshow("dst_y", dst_y);
    imshow("dst", dst);
    

    在这里插入图片描述
    x梯度:在这里插入图片描述
    y梯度:在这里插入图片描述
    在这里插入图片描述
    仔细观察三张图不难发现,X方向梯度在Y方向上边缘较为清晰,而Y方向梯度在X方向上边缘较为清晰,合并后的图像则综合了两张图的特征。

学习:
Sobel边缘检测算法及OpenCV函数实现

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/15986.html

(0)

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

关注微信