自学内容网 自学内容网

图像梯度-Sobel算子、scharrx算子和lapkacian算子

一、认识什么是图像梯度和Sobel算子

图像的梯度是指图像亮度变化的空间导数,它描述了图像在不同方向上的强度变化。在图像处理和计算机视觉中,梯度通常用来检测边缘,因为边缘往往是亮度变化最显著的地方。图像梯度可以用多种方式来计算,常见的方法包括:一阶导数(Sobel算子)、二阶导数(Laplacian算子)、Prewitt算子、Canny算子。

Sobel算子是一种在图像处理和计算机视觉领域广泛使用的边缘检测算子。Sobel算子使用两个3x3的核(kernel)来分别计算图像在水平和垂直方向上的梯度。这两个核通常被称为Sobel核。水平方向(Gx)的Sobel核与垂直方向(Gy)的Sobel核的具体如下:

在这里插入图片描述

dst = cv2.Sobel(src, ddepth, dx, dy, ksize) 是 OpenCV 库中用于计算图像的 Sobel 导数的函数。这个函数实现了 Sobel 算子,用于边缘检测。其中:
src:输入图像,可以是灰度图像或彩色图像。
ddepth:输出图像的深度。通常使用 cv2.CV_64F 表示64位浮点数,这可以避免计算过程中的溢出。
dx:指定求导的阶数,用于x方向。如果为1,则计算一阶导数;如果为2,则计算二阶导数。
dy:指定求导的阶数,用于y方向。如果为1,则计算一阶导数;如果为2,则计算二阶导数。
ksize:Sobel 核的大小。默认值为3,但也可以使用5或7。

二、Sobel算子的具体使用

  • x轴方向

在水平方向上,Sobel算子一般都是右边减去左边得到梯度值,并且如果求得的梯度值是负数的话,会进行截取为0的操作,也可以通过绝对值来进行修正参数。
拿下面这个圆来做例子,计算边缘的梯度(就例如红点位置的梯度):
在这里插入图片描述

# 导入OpenCV库,用于图像处理
import cv2
# 导入matplotlib的pyplot模块,用于图像显示
import matplotlib.pyplot as plt
# 导入numpy库,用于数值计算
import numpy as np

# 使用cv2.imread()函数读取位于指定路径的图像文件
img = cv2.imread("E:\\XUEXI\\Python_learn\\tupian\\4.jpg")

# 定义一个函数cv_show,用于显示图像
def cv_show(name, img):
    # 使用cv2.imshow()函数显示图像,名称为name
    cv2.imshow(name, img)
    # 使用cv2.waitKey(0)函数等待,直到用户按下任意键
    cv2.waitKey(0)
    # 使用cv2.destroyAllWindows()函数关闭所有OpenCV创建的窗口
    cv2.destroyAllWindows()

# 使用cv2.Sobel()函数计算图像的Sobel算子
# cv2.CV_64F指定输出图像的深度为64位浮点数
# 第三个参数1表示对x方向求导,第四个参数0表示对y方向不求导
# ksize=3指定Sobel算子的大小为3x3
sobelx = cv2.Sobel(img, cv2.CV_64F, 1, 0, ksize=3)

# 调用cv_show函数显示Sobel算子处理后的图像
cv_show("sobelx", sobelx)

运行结果:
在这里插入图片描述
可以看到上面只是显示了半圆的值。这是因为右减去左的原因,当白减去黑为正数,所以显示出了边界值。当右边是黑,左边是白的时候,右减去左的结果为负数,截取为0,所以显示黑色。(具体参考下图)

在这里插入图片描述

通过sobelx = cv2.convertScaleAbs(sobelx)可计算绝对值。cv2.convertScaleAbs:这个函数用于将输入数组的元素类型转换为 8 位无符号整数(uint8)。它首先将输入数组的每个元素乘以一个比例因子(默认为 1),然后加上一个偏移量(默认为 0)。最后,它计算结果的绝对值,并将其转换为 8 位无符号整数。

import cv2
import matplotlib.pyplot as plt
import numpy as np

img = cv2.imread("E:\\XUEXI\\Python_learn\\tupian\\4.jpg")

def cv_show(name,img):
    cv2.imshow(name, img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

sobelx = cv2.Sobel(img, cv2.CV_64F, 1, 0, ksize=3)
sobelx = cv2.convertScaleAbs(sobelx)
cv_show("sobelx", sobelx)

运行结果:
在这里插入图片描述

  • y轴方向
    在竖直方向上,是用下面减去上面来得到所求值。
import cv2
import matplotlib.pyplot as plt
import numpy as np

img = cv2.imread("E:\\XUEXI\\Python_learn\\tupian\\4.jpg")

def cv_show(name,img):
    cv2.imshow(name, img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

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

运行结果:
在这里插入图片描述

通常突出图片的边缘检测,一般使用分别计算x和y的sobel算子,再通过sobelxy = cv2.addWeighted(sobelx, 0.5, sobely, 0.5, 0) cv2.addWeighted 函数将两个图像 sobelx 和 sobely 按照指定的权重进行加权融合。

import cv2
import matplotlib.pyplot as plt
import numpy as np

img = cv2.imread("E:\\XUEXI\\Python_learn\\tupian\\4.jpg")

def cv_show(name,img):
    cv2.imshow(name, img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    
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)

运行结果:
在这里插入图片描述
可以看到边边上缺失的地方有一条浅浅的线条连在一起。

一般不建议直接计算sobelxy = cv2.Sobel(img,cv2.CV_64F, 1, 1,ksize=3),这种方法确实可以得到图像的梯度信息,但在某些应用中,分别计算水平和垂直梯度然后再组合它们可能会更有利。例如分别计算梯度可以帮助你确定边缘的方向。这对于某些应用,如形状分析或纹理分类,可能是有用的。

直接计算:

import cv2
import matplotlib.pyplot as plt
import numpy as np

img = cv2.imread("E:\\XUEXI\\Python_learn\\tupian\\4.jpg")

def cv_show(name,img):
    cv2.imshow(name, img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

sobelxy = cv2.Sobel(img,cv2.CV_64F, 1, 1,ksize=3)
sobelxy = cv2.convertScaleAbs(sobelxy)
cv_show("sobelxy", sobelxy)

运行结果:
在这里插入图片描述

由上图和x,y分别计算再组合在一起的对比,也可以效果没有分开计算的好。

用下图的照片来更直观观察分开计算和合起来计算的区别:

在这里插入图片描述

合起来计算:

import cv2
import matplotlib.pyplot as plt
import numpy as np

img = cv2.imread("E:\\XUEXI\\Python_learn\\tupian\\5.jpg")

def cv_show(name,img):
    cv2.imshow(name, img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

sobelxy = cv2.Sobel(img,cv2.CV_64F, 1, 1,ksize=3)
sobelxy = cv2.convertScaleAbs(sobelxy)
cv_show("sobelxy", sobelxy)

运行结果:

在这里插入图片描述

分别计算x,y方向的sobel算子再组合在一起:

import cv2
import matplotlib.pyplot as plt
import numpy as np

img = cv2.imread("E:\\XUEXI\\Python_learn\\tupian\\5.jpg")


def cv_show(name, img):
    cv2.imshow(name, img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()


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)

运行结果:

在这里插入图片描述

通过两种方法对比,明显分开计算x,y的边缘检测效果要更加的好!

三、scharrx算子与lapkacian(拉普拉斯)算子

scharrx算子

Scharr算子是一种用于边缘检测的图像处理算子,它是Sobel算子的改进版本。Scharr算子在计算图像梯度时,提供了更高的精度,尤其是在使用3x3的核时。这使得Scharr算子在检测图像边缘时更为敏感,能够捕捉到更细小的边缘特征。Scharr算子的卷积核与Sobel算子不同,它在平滑部分给予了中心元素更大的权重,相当于使用了标准差更小的高斯函数,从而使得算子更加敏感。

Scharr算子能更加细致地描绘出细节,能够注意到更多细节。

Scharr算子的卷积核如下:
在这里插入图片描述

lapkacian(拉普拉斯)算子

拉普拉斯算子(Laplacian),在图像处理中通常称为Laplacian算子,是一种用于边缘检测的二阶导数算子。它用于增强图像中的快速强度变化,这些变化通常对应于图像中的边缘。拉普拉斯算子可以用于检测图像中的边缘和纹理。

拉普拉斯算子对于一些噪音点会更加敏感,该算子显示的细节相对较少,但是拉普拉斯算子一般都是配合其他工具一块使用的。

在这里插入图片描述

通过以下照片来更直观观察三种算子之间的差距:

在这里插入图片描述

#不同算子的差异
import cv2
import matplotlib.pyplot as plt
import numpy as np

img = cv2.imread("E:\\XUEXI\\Python_learn\\tupian\\5.jpg")

def cv_show(name, img):
    cv2.imshow(name, img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

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)

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)

laplacian = cv2.Laplacian(img,cv2.CV_64F)
laplacian = cv2.convertScaleAbs(laplacian)

res = np.hstack((sobelxy,scharrxy,laplacian))
cv_show("res", res)

运行结果:

在这里插入图片描述

其中第一幅是sobel算子,第二幅是scharrx算子,第三幅是lapkacian算子。

可以看到scharrx算子能够更加细腻的展示出照片的细节,是sobel算子的升级版。而lapkacian算子描绘的细节就更加的少,一般lapkacian算子是搭配其他工具一块使用的。


原文地址:https://blog.csdn.net/Mr_Happy_Li/article/details/143026888

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!