图像基本处理——Sobel,Scharr,Laplacian算子

一、Sobel算子

(一)Sobel算子原理及数学表达

  1. Soble算子概念及原理
    Sobel算子是一种常用于边缘检测的方式,图像每个像素点的邻近像素点对其影响不同,从而邻近像素点的权重不相同。Sobel算子的原理是对传进来的图像像素做卷积,卷积的实质是在求梯度值(加权平均),其中权值就是所谓的卷积核;然后对生成的新像素灰度值做阈值运算,以此来确定边缘信息。
  2. 卷积核
    Sobel算子是把图像中每个像素的上下左右四领域的灰度值加权差,在边缘处达到极值从而检测边缘。
    举例3维的卷积核
    Gx表示横向做卷积,Gy表示纵向做卷积。
    G x = [ − 1 0 1 − 2 0 2 − 1 0 1 ] ∗ A a n d G y = [ − 1 − 2 − 1 0 0 0 1 2 1 ] ∗ A Gx= \begin{bmatrix} -1 & 0 & 1 \\ -2 & 0 & 2 \\ -1 & 0 & 1 \\ \end{bmatrix}*A \quad and \quad Gy= \begin{bmatrix} -1 & -2 & -1 \\ 0 & 0 & 0 \\ 1 & 2 & 1 \\ \end{bmatrix}*A Gx=121000121AandGy=101202101A

实际上Sobel算子进行边缘检测上是做了两个方向的卷积,所以最终卷积结果如下
G = G x 2 + G y x G=\sqrt{G_x^{2}+G_y^{x}} G=Gx2+Gyx

(二)Sobel算子的实现过程

  1. opencv实现Sobel算子函数

    def Sobel(src: Any,
              ddepth: Any,
              dx: Any,
              dy: Any,
              dst: Any = None,
              ksize: Any = None,
              scale: Any = None,
              delta: Any = None,
              borderType: Any = None)
    

    部分参数说明

    src:原始图像对象
    ddepth:图像深度,通常使用-1,表示与原始图像深度保持一致
    dx:表示x方向的梯度(导数)
    dy:表示y方向的梯度(导数)

  2. 对比x,y方向

    import cv2
    import numpy as np
    
    def showImg(img, name):
        cv2.imshow(name, img)
        cv2.waitKey(0)
        cv2.destroyAllWindows()
    
    circle = cv2.imread("circle.png")
    showImg(circle, "circle")
    sobel_x = cv2.Sobel(circle, cv2.CV_64F, 1, 0, ksize=3)
    sobel_y = cv2.Sobel(circle, cv2.CV_64F, 0, 1, ksize=3)
    sobel_x_y = np.hstack((sobel_x, sobel_y))
    # 显示结果
    showImg(sobel_x_y, 'circleXY')
    

    原始图像
    在这里插入图片描述
    检测结果
    在这里插入图片描述
    通过检测结果可以发现无论是在水平还是垂直方向上,都存在只检测出一半的情况。产生此种原因是由于后面边缘像素点在做卷积后得到的结果为负数,然而像素点的值是0~255之间,所以,所有负数部分都全部变为了0。
    解决只检测一半的方式

    #在显示之前添加如下代码,对得到结果进行一个取绝对值操作
    sobel_x = cv2.convertScaleAbs(sobel_x)
    sobel_y = cv2.convertScaleAbs(sobel_y)
    

    在这里插入图片描述
    对于取绝对值后的结果,会发现水平方向会在垂直方向上存在一些断点,垂直方向同理。出现此种原因是由于只做了某个方向的梯度计算。
    直接计算两个方向的梯度

    sobel_xy = cv2.Sobel(circle, cv2.CV_64F, 1, 1, ksize=3)
    sobel_xy = cv2.convertScaleAbs(sobel_xy)
    showImg(sobel_xy, 'circleX')
    

    在这里插入图片描述
    分别求解两个方向的梯度后,进行加权平均值

    sobel_x = cv2.Sobel(circle, cv2.CV_64F, 1, 0, ksize=3)
    sobel_y = cv2.Sobel(circle, cv2.CV_64F, 0, 1, ksize=3)
    sobel_x = cv2.convertScaleAbs(sobel_x)
    sobel_y = cv2.convertScaleAbs(sobel_y)
    sobel_x_y = cv2.addWeighted(sobel_x, 0.5, sobel_y, 0.5, 0)
    # 显示结果
    showImg(sobel_x_y, 'circleXY')
    

    在这里插入图片描述
    两种方式的结果对比可以发现,第一种方式在水平和垂直方向上都出现断点的情况,而第二种方式就比较好的解决断点的情况。

二、Scharr算子

(一)Scharr算子的原理和数学表达

  1. Scharr算子的原理概念
    Scharr算子实现原理跟Sobel算子基本上是一致的,都是通过对上下左右四领域的灰度值加权差。两种区别在于后者设定的权重相对更大。
  2. 卷积核
    采用3维
    Gx表示横向做卷积,Gy表示纵向做卷积。
    G x = [ − 3 0 3 − 10 0 10 − 3 0 3 ] ∗ A a n d G y = [ − 3 − 10 − 3 0 0 0 3 10 3 ] ∗ A Gx= \begin{bmatrix} -3 & 0 & 3 \\ -10 & 0 & 10 \\ -3 & 0 & 3 \\ \end{bmatrix}*A \quad and \quad Gy= \begin{bmatrix} -3 & -10 & -3 \\ 0 & 0 & 0 \\ 3 & 10 & 3 \\ \end{bmatrix}*A Gx=31030003103AandGy=30310010303A
    最终结果也是通过分别求解取绝对值后,求解加权平均值。

(二)Scharr算子的实现

  1. opencv实现Scharr算子函数
    def Scharr(src: Any,
               ddepth: Any,
               dx: Any,
               dy: Any,
               dst: Any = None,
               scale: Any = None,
               delta: Any = None,
               borderType: Any = None)
    
    其参数具体含义同Sobel算子。
  2. 实际举例
    由于Scharr算子跟Sobel类似,所以就不过多分析。
    scharr_x = cv2.Scharr(circle, cv2.CV_64F, 1, 0)
    scharr_y = cv2.Scharr(circle, cv2.CV_64F, 0, 1)
    scharr_x = cv2.convertScaleAbs(scharr_x)
    scharr_y = cv2.convertScaleAbs(scharr_y)
    scharr_x_y = cv2.addWeighted(scharr_x, 0.5, scharr_y, 0.5, 0)
    showImg(scharr_x_y, 'scharr')
    
    在这里插入图片描述

三、Laplacian算子

(一) Laplacian算子原理及数学表达

  1. Laplacian算子概念及原理
    Laplacian算子是一个二阶算子,它是通过在水平方向运算两次,垂直方向运算两次,两个结果相叠加替换中心点(锚点)的像素值(灰度值),跟上面两种算子有着本质上的区别,也可以将该算子类似的看出二阶的Sobel算子。
  2. 卷积核
    3维卷积核
    G = [ 0 1 0 1 − 4 1 0 1 0 ] ∗ A G= \begin{bmatrix} 0 & 1 & 0 \\ 1 & -4 & 1 \\ 0 & 1 & 0 \\ \end{bmatrix}*A G=010141010A

(二) Laplacian算子实现过程

  1. opencv实现Laplacian算子函数

    def Laplacian(src: Any,
                  ddepth: Any,
                  dst: Any = None,
                  ksize: Any = None,
                  scale: Any = None,
                  delta: Any = None,
                  borderType: Any = None)
    

    其参数含义跟上面一致。

  2. 实际举例

    laplacian = cv2.Laplacian(circle, cv2.CV_64F, ksize=3)
    laplacian = cv2.convertScaleAbs(laplacian)
    showImg(laplacian, 'laplacian')
    

    在这里插入图片描述

四、三种算子的对比

  1. 对比过程
    lena = cv2.imread("C:/Users/Administrator/Downloads/Lena1.png", cv2.IMREAD_GRAYSCALE)
    # Sobel算子
    sobel_x = cv2.Sobel(lena, cv2.CV_64F, 1, 0, ksize=3)
    sobel_y = cv2.Sobel(lena, cv2.CV_64F, 0, 1, ksize=3)
    sobel_x = cv2.convertScaleAbs(sobel_x)
    sobel_y = cv2.convertScaleAbs(sobel_y)
    sobel_x_y = cv2.addWeighted(sobel_x, 0.5, sobel_y, 0.5, 0)
    # Scharr算子
    scharr_x = cv2.Scharr(lena, cv2.CV_64F, 1, 0)
    scharr_y = cv2.Scharr(lena, cv2.CV_64F, 0, 1)
    scharr_x = cv2.convertScaleAbs(scharr_x)
    scharr_y = cv2.convertScaleAbs(scharr_y)
    scharr_x_y = cv2.addWeighted(scharr_x, 0.5, scharr_y, 0.5, 0)
    # Laplacian算子
    laplacian = cv2.Laplacian(lena, cv2.CV_64F, ksize=3)
    laplacian = cv2.convertScaleAbs(laplacian)
    plt.subplot(221), plt.imshow(lena, 'gray'), plt.title('ORIGINAL')
    plt.xticks([]), plt.yticks([])
    plt.subplot(222), plt.imshow(sobel_x_y, 'gray'), plt.title('Sobel')
    plt.xticks([]), plt.yticks([])
    plt.subplot(223), plt.imshow(scharr_x_y, 'gray'), plt.title('Scharr')
    plt.xticks([]), plt.yticks([])
    plt.subplot(224), plt.imshow(laplacian, 'gray'), plt.title('Laplacian')
    plt.xticks([]), plt.yticks([])
    plt.show()
    
    在这里插入图片描述
  2. 对比结论
    通过上面对比,可以发现针对于Sobel和Scharr算子来说,Scharr在边缘检测上会更详尽。整体上来说,Scharr算子在边缘处会更加详尽。
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值