欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-06-01 18:15:24
...

索贝尔算子(Sobel operator)

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


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


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

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

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


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

具体计算如下:
其中f(a,b), 表示图像(a,b)点的灰度值;
Gx=(1)f(x1,y1)+0f(x,y1)+1f(x+1,y1)G_x=(-1)*f(x-1,y-1)+0*f(x,y-1)+1*f(x+1,y-1)
        +(2)f(x1,y)+0f(x,y)+2f(x+1,y)+ (-2)*f(x-1,y)+0*f(x,y)+2*f(x+1,y)
        +(1)f(x1,y+1)+0f(x,y+1)+1f(x+1,y+1)+(-1)*f(x-1,y+1)+0*f(x,y+1)+1*f(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)]




Gy=1f(x1,y1)+2f(x,y1)+1f(x+1,y1)G_y=1*f(x-1,y-1)+2*f(x,y-1)+1*f(x+1,y-1)
        +0f(x1,y)+0f(x,y)+0f(x+1,y)+ 0*f(x-1,y)+0*f(x,y)+0*f(x+1,y)
        +(1)f(x1,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)


结果:[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=Gx2+Gy2G=\sqrt {G_x^2+G_y^2}
    通常,为了提高效率 使用不开平方的近似值:
    G=Gx+Gy|G|=|G_x|+|G_y|
    如果梯度G大于某一阀值 则认为该点(x,y)为边缘点。

梯度方向:
=arctan(GyGx)角度值=arctan(\frac{G_y}{G_x})

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位图像则会截取顶端的导数。

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

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

    在输入数组的每个元素上,函数convertScaleAbs依次执行三个操作:缩放,获取绝对值,转换为无符号的8位类型:
    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 可选增量添加到缩放值。

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

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

    函数addWeighted计算两个数组的加权和,如下所示:
    dst(I)=saturate(src1(I)alpha+src2(I)beta+gamma)dst(I)=saturate(src1(I)∗alpha+src2(I)∗beta+gamma)
    I是数组元素的多维索引。在多通道阵列的情况下,每个通道都是独立处理的。该函数可以替换为矩阵表达式:
    dst=src1alpha+src2beta+gammadst = src1 * alpha + src2 * beta + 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);
    

    OpenCV--033_2: 图像梯度--Sobel算子
    x梯度:OpenCV--033_2: 图像梯度--Sobel算子
    y梯度:OpenCV--033_2: 图像梯度--Sobel算子
    OpenCV--033_2: 图像梯度--Sobel算子
    仔细观察三张图不难发现,X方向梯度在Y方向上边缘较为清晰,而Y方向梯度在X方向上边缘较为清晰,合并后的图像则综合了两张图的特征。

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

相关标签: sobel算子