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

本文详细介绍了Sobel、Scharr和Laplacian三种边缘检测算子的原理、数学表达式及OpenCV实现过程。Sobel算子通过卷积计算梯度,Scharr算子则采用更大的权重,Laplacian算子为二阶导数算子。通过实例展示了它们在边缘检测中的应用和效果对比,揭示了Scharr算子在边缘检测上的优势。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、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算子在边缘处会更加详尽。
### 不同边缘检测算子的特点 #### Sobel 算子 Sobel 算子用于计算图像的梯度,通常采用3×3的模板进行卷积操作。该算子不仅考虑了中心像素周围的灰度差异,还赋予了一定权重给距离稍远的像素,从而增强了抗噪能力[^1]。 对于水平和垂直方向上的梯度分量分别有如下定义: ```python import cv2 import numpy as np def sobel_operator(image): grad_x = cv2.Sobel(image, cv2.CV_64F, 1, 0, ksize=3) grad_y = cv2.Sobel(image, cv2.CV_64F, 0, 1, ksize=3) magnitude = np.sqrt(grad_x**2 + grad_y**2) angle = np.arctan2(grad_y, grad_x) * (180 / np.pi) return magnitude, angle ``` 此函数返回两个值:一个是梯度幅值矩阵;另一个是指向最大变化率的方向角矩阵(单位为度)。这使得Sobel算子非常适合用来识别具有明显方向性的边界特征[^4]。 #### Scharr 算子 相比于标准的Sobel算子Scharr算子提供了更高精度的方向敏感性以及更好的旋转不变特性。这意味着即使目标物体发生轻微转动,也能保持较为一致的结果质量[^3]。 实现上几乎相同于上述Sobel方法,只需更改内核参数即可获得更精确的效果: ```python grad_x = cv2.Scharr(image, cv2.CV_64F, 1, 0) grad_y = cv2.Scharr(image, cv2.CV_64F, 0, 1) ``` #### Laplacian 算子 不同于前两者的一阶微分性质,Laplacian算子依赖于二阶导数来进行边缘定位。其核心思想在于寻找局部极值点作为潜在边界的指示器。然而,这种方法容易受到随机噪声干扰而产生虚假响应,所以在实际应用之前往往先施加高斯模糊处理以减少此类影响[^2]. 具体来说,Laplacian算子不区分正负过渡区域,而是直接给出零交叉位置处的显著改变信号。因此,在某些场景下可能更适合捕捉细小结构或纹理细节。 ```python blurred_image = cv2.GaussianBlur(image, (5, 5), 0) laplacian_edges = cv2.Laplacian(blurred_image, cv2.CV_64F) ``` 这里展示了如何结合高斯滤波器预处理输入数据后再执行Laplacian变换的过程。 ### 比较与应用场景分析 - **抗噪性能**: 当面对含较多高频成分的数据集时,Sobel/Scharr组合表现优异;而对于低对比度环境下的精细描绘需求,则推荐优先尝试经过平滑后的Laplacian方案。 - **几何适应性**: 如果任务涉及大量倾斜线条或者复杂形状轮廓提取工作的话,那么具备更强各向异性特性的Scharr将会是一个不错的选择。 - **速度考量**: 对实时性要求较高的场合应当权衡不同算法的时间消耗因素。一般来说,简单的Sobel运算效率最高,其次是稍微复杂的Scharr版本,最后才是涉及到额外过滤步骤的Laplacian流程。 综上所述,选择合适的边缘检测工具取决于具体的视觉理解挑战所在的具体方面及其所关联的技术指标约束条件。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值