• 【Opencv入门到项目实战】(四):图像梯度计算|Sobel算子|Scharr算子|Laplacian算子


    0.引言

    在图像处理中,梯度是指图像中像素灰度变化的速率或幅度,我们先来看下面这张图

    假设我们想要计算出A点的梯度,我们可以发现A点位于边缘点,A点左边为黑色,右边为白色,而计算图像的梯度可以提取出图像中的边缘信息,我们常用的方法是使用Sobel算子Scharr算子进行梯度计算。接下来我们分别来看看具体是如何做的

    1. Sobel算子

    和我们之前介绍的各种图像计算的方法类似,我们利用某一个大小的卷积核来进行计算,我们这里也一样,Sobel算子有两个核,一个用于计算图像在水平方向上的差异(x方向梯度),另一个用于计算图像在垂直方向上的差异(y方向梯度)。这两个核可以在水平和垂直方向上检测出图像中的边缘信息。

    下面是Sobel算子在x和y方向上的核矩阵:

    image-20230801222810068

    我们来看他这个是如何来识别边缘的,以x方向为例,如果两边相差太大了,那么结果的绝对值也会比较大,说明应该在边缘点附近,如果两边值非常接近,则结果也会趋于0,此时说明不在边缘地附近。y方向也是同理。接下来我们看一下如何在Opencv中实现,我们调用cv2.Sobel()函数,

    dst = cv2.Sobel(src, ddepth, dx, dy, ksize)
    
    • 1
    • ddepth:输出图像的深度(数据类型),一般我们指定为64位浮点数型,设为CV_64F
    • dx和dy分别表示水平和竖直方向
    • ksize是Sobel算子的大小

    我们以下面这张图为例计算梯度,

    # 导入原始图
    img = cv2.imread('pie.png',cv2.IMREAD_GRAYSCALE)
    cv2.imshow("img",img)
    cv2.waitKey()
    cv2.destroyAllWindows()
    
    • 1
    • 2
    • 3
    • 4
    • 5

    image-20230801224507395

    x方向计算梯度

    # 定义图像展示函数
    def cv_show(img,name):
        cv2.imshow(name,img)
        cv2.waitKey()
        cv2.destroyAllWindows()
    
    sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3)
    cv_show(sobelx,'sobelx')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    image-20230801224706224

    我们发现只有一半。我们来思考一个问题哈,从黑到白是正数,白到黑就是负数了,所有的负数会被截断成0,所以导致我们右半边的边缘无法显示,因此我们要取绝对值来解决这个问题。

    我们调用cv2.convertScaleAbs(sobelx) 实现将结果转换为无符号8位整数

    sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3)
    sobelx = cv2.convertScaleAbs(sobelx) #实现将结果转换为无符号8位整数
    cv_show(sobelx,'sobelx')
    
    • 1
    • 2
    • 3

    image-20230801224952929

    现在我们基本找到了边缘,接下来我们还需要看y方向的情况

    计算y方向的梯度

    sobely = cv2.Sobel(img,cv2.CV_64F,0,1,ksize=3)
    sobely = cv2.convertScaleAbs(sobely)  
    cv_show(sobely,'sobely')
    
    • 1
    • 2
    • 3

    image-20230801225145764

    现在我们分别得到了x方向和y方向的边缘,接下来我们进行求和处理。

    求和

    调用cv2.addWeighted函数

    sobelxy = cv2.addWeighted(sobelx,0.5,sobely,0.5,0)
    cv_show(sobelxy,'sobelxy')
    
    • 1
    • 2

    image-20230801225247382

    接下来,我们以之前小狗洋气的图片来看一下它的梯度结果

    # 原始图像
    img = cv2.imread('yangqi.jpg',cv2.IMREAD_GRAYSCALE)
    cv_show(img,'img')
    
    • 1
    • 2
    • 3

    image-20230801230038445

    接下来我们来看一下求梯度后的结果

    img = cv2.imread('yangqi.jpg',cv2.IMREAD_GRAYSCALE)
    sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3)
    sobelx = cv2.convertScaleAbs(sobelx)
    sobely = cv2.Sobel(img,cv2.CV_64F,0,1,ksize=3)
    sobely = cv2.convertScaleAbs(sobely)
    sobelxy = cv2.addWeighted(sobelx,0.5,sobely,0.5,0)
    cv_show(sobelxy,'sobelxy')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在这里插入图片描述

    可以看到,我们把图片所有的轮廓都给提取出来了。

    Sobel算子具有简单且易于实现的优点,它对噪声有一定的抑制作用,并可以快速检测出图像中的边缘。然而,Sobel算子也存在一些局限性,如对于较弱的边缘响应不敏感,并且可能会产生较粗的边缘。对于更复杂的场景,可能需要结合其他的边缘检测算法或采用更高级的技术。

    2. Scharr算子

    Scharr算子和Sobel算子很像,但在边缘检测方面具有更好的性能。Scharr算子也是基于一阶导数的近似,和Sobel算子一样,Scharr算子也有两个3x3的核、

    具体核矩阵如下:

    image-20230801230310957

    在Opencv中,我们调用cv2.Scharr()函数实现。

    scharrx = cv2.Scharr(img,cv2.CV_64F,1,0)
    scharry = cv2.Scharr(img,cv2.CV_64F,0,1)
    scharrx = cv2.convertScaleAbs(scharrx)   
    scharry = cv2.convertScaleAbs(scharry)  
    scharrxy =  cv2.addWeighted(scharrx,0.5,scharry,0.5,0) cv_show(scharrxy,'scharr')
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    image-20230801232322062

    从结果来看,与Sobel算子相比,检测出来的边缘更多,因为Scharr算子具有更高的方向敏感性和更好的旋转不变性,能够更准确地检测到边缘,并且在边缘方向变化较大的情况下效果更好。因此,在很多应用中,Scharr算子常常被用作替代Sobel算子的选择。

    3. Laplacian算子

    Laplacian算子常用于检测图像中的边缘和纹理,但是它计算图像的二阶导数,以此捕捉到图像中的灰度变化,它只有一个核

    image-20230801232016698

    在Opencv中,我们调用cv2.Laplacian()函数实现,因为这里只有一个核,因此不用分别计算x方向和y方向,直接计算一个即可

    laplacian = cv2.Laplacian(img,cv2.CV_64F)
    laplacian = cv2.convertScaleAbs(laplacian)   
    
    • 1
    • 2

    image-20230801232556834

    从结果来看,Laplacian单独使用对边缘检测的效果一般,因为它是一个二阶导数运算,所以图像中的噪声会被放大。因此,在应用Laplacian算子之前,可能需要对图像进行预处理,例如平滑/模糊来降低噪声的影响,我们一般不会单独使用Laplacian算子,而是结合其他的方法使用。

    🔎本章的介绍到此介绍,如果文章对你有帮助,请多多点赞、收藏、评论、订阅支持!!《Opencv入门到项目实战》

  • 相关阅读:
    Flink Checkpoint
    【在线编程-Python篇】Python入门 04 列表(上)
    c++排序算法
    在linux中详细解释下kill命令,不同信号的含义及使用场景
    常见的C/C++开源QP问题求解器
    Codeforces Round #820 (Div. 3) G-Cut Substrings(kmp状态机dp)
    安装jdk1.6
    js函数新东西——匿名函数
    开发工具-压力测试工具 ab
    忘记Docker的NextCloud密码
  • 原文地址:https://blog.csdn.net/weixin_45052363/article/details/132130318