(计算机视觉课程-笔记1)图像边缘检测

图像边缘检测

1. sobel 算子

Sobel算子是一种常用于图像处理和计算机视觉中的边缘检测算法。它用于识别图像中的边缘区域,即图像中灰度值发生剧烈变化的地方。Sobel算子基于图像的灰度梯度,通过计算每个像素点周围像素的灰度值差异,来确定边缘的位置和方向。

Sobel算子主要由两个3x3的矩阵组成,分别用于计算图像在水平和垂直方向的梯度。这两个矩阵通常被称为Sobel算子模板或卷积核。下面是水平和垂直方向的Sobel算子模板示例:

水平方向Sobel算子模板(Gx):

-1  0  1
-2  0  2
-1  0  1

垂直方向Sobel算子模板(Gy):

-1 -2 -1
 0  0  0
 1  2  1

Sobel算子的计算过程如下:

首先,将Sobel算子模板与图像的每个像素进行卷积操作。对于每个像素,将其与周围的8个像素进行乘法运算,然后将乘积相加得到一个结果。

对于水平方向的Sobel算子,将像素与模板进行乘法运算后相加的结果表示图像在水平方向上的梯度。

对于垂直方向的Sobel算子,将像素与模板进行乘法运算后相加的结果表示图像在垂直方向上的梯度。

在水平和垂直方向上的梯度计算完成后,可以通过以下公式来计算图像中每个像素的梯度幅值和梯度方向:

梯度幅值(G):G = sqrt(Gx^2 + Gy^2)
梯度方向(θ):θ = atan2(Gy, Gx)
最后,可以根据梯度幅值进行边缘检测。一般来说,梯度幅值越大的像素点,很可能是图像中的边缘点。

Sobel算子是一种简单而有效的边缘检测算法,常用于图像处理任务中。它可以帮助我们在图像中找到边缘信息,并在计算机视觉领域中的对象检测、图像分割等任务中发挥重要作用。

1. 2sobel 算子(cv2实现)

import cv2
import numpy as np

# 读取图像
image = cv2.imread('image.jpg', cv2.IMREAD_GRAYSCALE)

# 计算水平方向和垂直方向上的Sobel梯度
sobel_x = cv2.Sobel(image, cv2.CV_64F, 1, 0, ksize=3)
sobel_y = cv2.Sobel(image, cv2.CV_64F, 0, 1, ksize=3)

# 将梯度值转换为绝对值
sobel_x = np.absolute(sobel_x)
sobel_y = np.absolute(sobel_y)

# 将梯度值缩放到0-255范围内
sobel_x = np.uint8(sobel_x)
sobel_y = np.uint8(sobel_y)

# 将水平和垂直方向上的梯度值合并
sobel_combined = cv2.bitwise_or(sobel_x, sobel_y)

# 显示原始图像和Sobel边缘检测结果
cv2.imshow('Original Image', image)
cv2.imshow('Sobel X', sobel_x)
cv2.imshow('Sobel Y', sobel_y)
cv2.imshow('Sobel Combined', sobel_combined)
cv2.waitKey(0)
cv2.destroyAllWindows()

# 函数cv2.Sobel()用于计算图像的Sobel梯度。下面是该函数的参数及其含义的解释:

# image:输入图像。这应该是一个单通道灰度图像(如使用参数cv2.IMREAD_GRAYSCALE加载的图像),或者可以是多通道图像,其中仅考虑一个通道进行边缘检测。

# cv2.CV_64F:输出图像的数据类型。这里我们使用cv2.CV_64F表示64位浮点型数据,以便在计算梯度时能够保留负数值。

# 1:x方向上的差分阶数。这指定了在x方向上计算梯度时使用的差分阶数,设置为1表示使用一阶导数。

# 0:y方向上的差分阶数。这指定了在y方向上计算梯度时使用的差分阶数,设置为0表示不在y方向上计算梯度。

# ksize=3:Sobel算子的卷积核大小。它定义了在计算梯度时要使用的卷积核的大小。在这种情况下,ksize=3表示使用一个3x3的卷积核。

# 请注意,Sobel算子可以在x方向和y方向上分别计算梯度,通过使用不同的差分阶数来指定。在上述示例中,我们选择在x方向上计算一阶导数(水平方向)
# ,而在y方向上不计算梯度。这是因为Sobel算子通常用于检测图像中的水平边缘。如果您希望检测垂直边缘,可以将x和y方向的差分阶数进行交换。

2. Prewitt算子

Prewitt算子是一种常用于图像处理和计算机视觉中的边缘检测算法,类似于Sobel算子。它也用于检测图像中的边缘区域,即图像中灰度值发生剧烈变化的地方。Prewitt算子基于图像的灰度梯度,通过计算每个像素点周围像素的灰度值差异来确定边缘的位置和方向。

Prewitt算子与Sobel算子类似,都使用两个3x3的矩阵来计算图像的梯度。下面是水平和垂直方向的Prewitt算子模板示例:

水平方向Prewitt算子模板(Gx):

-1  0  1
-1  0  1
-1  0  1

垂直方向Prewitt算子模板(Gy):

-1 -1 -1
 0  0  0
 1  1  1

Prewitt算子的计算过程与Sobel算子类似:

首先,将Prewitt算子模板与图像的每个像素进行卷积操作。对于每个像素,将其与周围的8个像素进行乘法运算,然后将乘积相加得到一个结果。

对于水平方向的Prewitt算子,将像素与模板进行乘法运算后相加的结果表示图像在水平方向上的梯度。

对于垂直方向的Prewitt算子,将像素与模板进行乘法运算后相加的结果表示图像在垂直方向上的梯度。

可以通过以下公式计算图像中每个像素的梯度幅值和梯度方向:

梯度幅值(G):G = sqrt(Gx^2 + Gy^2)
梯度方向(θ):θ = atan2(Gy, Gx)
最后,可以根据梯度幅值进行边缘检测。梯度幅值较大的像素点可能表示图像中的边缘点。

Prewitt算子与Sobel算子相比,差别较小。它们的模板略有不同,因此在某些情况下,Prewitt算子可能产生略微不同的边缘检测结果。在实际应用中,您可以根据任务的要求选择使用Sobel算子还是Prewitt算子。

2.2 Prewitt算子(cv2实现)

import cv2
import numpy as np

# 读取图像
image = cv2.imread('image.jpg', cv2.IMREAD_GRAYSCALE)

# 构建Prewitt算子的卷积核
kernel_x = np.array([[-1, 0, 1], [-1, 0, 1], [-1, 0, 1]], dtype=np.float32)
kernel_y = np.array([[-1, -1, -1], [0, 0, 0], [1, 1, 1]], dtype=np.float32)

# 使用filter2D函数进行卷积运算
prewitt_x = cv2.filter2D(image, -1, kernel_x)
prewitt_y = cv2.filter2D(image, -1, kernel_y)

# 将梯度值转换为绝对值
prewitt_x = np.absolute(prewitt_x)
prewitt_y = np.absolute(prewitt_y)

# 将梯度值缩放到0-255范围内
prewitt_x = np.uint8(prewitt_x)
prewitt_y = np.uint8(prewitt_y)

# 将水平和垂直方向上的梯度值合并
prewitt_combined = cv2.bitwise_or(prewitt_x, prewitt_y)

# 显示原始图像和Prewitt边缘检测结果
cv2.imshow('Original Image', image)
cv2.imshow('Prewitt X', prewitt_x)
cv2.imshow('Prewitt Y', prewitt_y)
cv2.imshow('Prewitt Combined', prewitt_combined)
cv2.waitKey(0)
cv2.destroyAllWindows()

2.3 Prewitt算子与sobel算子对比

Sobel算子和Prewitt算子是两种常用的边缘检测算子,它们在计算边缘梯度时略有不同。下面是Sobel算子和Prewitt算子之间的主要差别:
1 模板差异:
Sobel算子的水平方向和垂直方向的模板分别为:

Gx = [[-1, 0, 1],
      [-2, 0, 2],
      [-1, 0, 1]]
      
Gy = [[-1, -2, -1],
      [ 0,  0,  0],
      [ 1,  2,  1]]

Prewitt算子的水平方向和垂直方向的模板分别为:

Gx = [[-1, 0, 1],
      [-1, 0, 1],
      [-1, 0, 1]]
      
Gy = [[-1, -1, -1],
      [ 0,  0,  0],
      [ 1,  1,  1]]

2 灵敏度差异:
Sobel算子的模板在中心位置权重较大,因此对中心像素的梯度响应更为敏感。
Prewitt算子的模板在水平和垂直方向上的权重相等,对中心像素和周围像素的梯度响应相对均衡。
3 梯度估计:
由于Sobel算子的模板权重较大,它更适合在边缘具有较高对比度的图像中进行梯度估计。
Prewitt算子在边缘具有较弱对比度的图像中也能提供较好的梯度估计。
4 计算效率:
由于Sobel算子的模板中存在更多非零权重,计算Sobel算子的梯度可能稍微更为耗时。
Prewitt算子的模板中非零权重较少,计算Prewitt算子的梯度相对较快。

3. canny算子

Canny算子是一种常用的边缘检测算法,由John F. Canny于1986年提出。它被广泛应用于计算机视觉和图像处理领域,用于检测图像中的边缘。Canny算子在边缘检测中具有较高的准确性和良好的噪声抑制能力。

Canny算子的边缘检测过程包括以下几个步骤:

1:噪声抑制: 首先,对输入图像进行高斯滤波以减少噪声的影响。高斯滤波平滑图像,通过计算每个像素周围邻域内像素的加权平均值来达到这一目的。

2:梯度计算: 然后,使用Sobel算子计算图像的梯度。Sobel算子分别在水平和垂直方向上对图像进行卷积操作,得到每个像素点的梯度强度和梯度方向。

3:非极大值抑制: 接下来,执行非极大值抑制来细化边缘。对于每个像素点,根据其梯度方向,检查它是否为该方向上局部梯度的极大值。如果不是极大值,则被抑制。

4:双阈值处理: 通过双阈值处理来确定真正的边缘。设置两个阈值:低阈值和高阈值。根据像素的梯度强度,将像素分为强边缘、弱边缘和非边缘三类。只有当像素的梯度强度超过高阈值时,才被认为是强边缘。如果像素的梯度强度低于低阈值,则被视为非边缘。位于两个阈值之间的像素被认为是弱边缘。可以选择执行边缘连接来连接强边缘与与之相邻的弱边缘。

5:边缘连接: 可选的边缘连接步骤可以通过将弱边缘与相邻的强边缘连接起来,从而形成完整的边缘。这可以通过在弱边缘的邻域内查找强边缘来实现。

Canny算子的输出结果是二进制图像,其中边缘像素被标记为白色(255),非边缘像素被标记为黑色(0)。

3.2 非极大值抑制

非极大值抑制(Non-Maximum Suppression,简称NMS)是Canny边缘检测算法中的一个重要步骤,用于细化边缘并保留边缘的细节信息。该步骤通过在梯度方向上进行比较,仅保留局部梯度的极大值,将非极大值抑制。

以下是非极大值抑制的详细步骤:

梯度计算: 首先,在Canny算子的边缘检测过程中,通过应用Sobel算子计算图像的梯度。这会得到每个像素点的梯度强度(Gradient Magnitude)和梯度方向(Gradient Direction)。

梯度方向量化: 将梯度方向量化为四个主要方向之一:0°(垂直)、45°(对角线)、90°(水平)和135°(对角线)。这样可以将梯度方向划分为四个离散的方向。

非极大值抑制: 对于每个像素点,沿着梯度方向的正负两个方向上比较其梯度强度。如果该像素点的梯度强度大于其两侧的像素点(在梯度方向上)的梯度强度,则保留该像素点。否则,将其抑制为非边缘点。

具体步骤如下:

对于每个像素点P,找到其相邻的两个像素点(在梯度方向上),即正方向像素点和负方向像素点。
检查像素点P的梯度强度是否大于这两个相邻像素点的梯度强度。如果是,则保留像素点P为边缘点。否则,将像素点P抑制为非边缘点。
这个过程将会细化边缘,并保留了局部梯度的极大值,去除了不符合极大值条件的非边缘像素。

非极大值抑制的结果是一个二值图像,其中只有边缘像素被标记为白色(255),非边缘像素被标记为黑色(0)。

通过应用非极大值抑制,Canny算子可以在梯度方向上细化边缘,使其变得更细,并保留了边缘的细节信息。这一步骤对于提高边缘检测的准确性和保留重要边缘特征至关重要。

3.3canny算子cv代码

import cv2

# 读取图像
image = cv2.imread('image.jpg', cv2.IMREAD_GRAYSCALE)

# 高斯滤波
blurred = cv2.GaussianBlur(image, (5, 5), 0)

# 计算梯度
gradient = cv2.Canny(blurred, 50, 150)  # 低阈值和高阈值

# 显示结果
cv2.imshow('Original Image', image)
cv2.imshow('Canny Edge Detection', gradient)
cv2.waitKey(0)
cv2.destroyAllWindows()

使用cv2.imread()函数读取图像,并将其转换为灰度图像(使用cv2.IMREAD_GRAYSCALE参数)。

对图像进行高斯滤波,通过cv2.GaussianBlur()函数实现。这一步骤可以减少噪声对边缘检测的影响。函数的第二个参数是滤波器的大小,这里设置为(5, 5),第三个参数是高斯核的标准差,设置为0表示根据滤波器大小自动计算。

使用cv2.Canny()函数进行Canny边缘检测。函数的第二个和第三个参数是低阈值和高阈值,根据图像的特性可以调整这两个阈值。一般来说,低阈值用于边缘连接,高阈值用于边缘起始。

最后,使用cv2.imshow()函数显示原始图像和Canny边缘检测结果。

注意:在运行代码之前,需要将image.jpg替换为实际的图像文件路径。

4 Roberts算子

Roberts算子是一种经典的边缘检测算子,用于在图像中检测边缘。它是由Lawrence Roberts于1963年提出的。Roberts算子基于离散微分的概念,通过计算像素点与其邻域像素之间的差异来确定边缘的存在。

Roberts算子使用两个2×2的卷积核来计算图像的水平和垂直梯度。这两个卷积核如下:

水平梯度卷积核(Gx):

 1  0
 0 -1

垂直梯度卷积核(Gy):

 0  1
-1  0

Roberts算子的边缘检测步骤如下:

将输入图像转换为灰度图像(如果不是灰度图像)。

对灰度图像分别使用水平梯度卷积核(Gx)和垂直梯度卷积核(Gy)进行卷积操作,得到水平梯度图像和垂直梯度图像。

计算边缘强度图像。可以使用以下公式计算每个像素点的边缘强度:

edge_strength = sqrt(Gx^2 + Gy^2)

其中,Gx和Gy分别为水平梯度图像和垂直梯度图像中的像素值。

可选的阈值处理:根据设定的阈值,将边缘强度图像进行阈值处理,将高于阈值的像素标记为边缘点,低于阈值的像素标记为非边缘点。

Roberts算子的输出结果是一个二值图像,其中边缘像素被标记为白色(255),非边缘像素被标记为黑色(0)。

尽管Roberts算子是边缘检测的一种基础算子,但由于其简单性和计算效率,仍然在某些场景下使用。然而,它对于噪声敏感,并且在边缘检测的准确性和连续性方面可能不如其他更高级的算子(如Sobel、Prewitt和Canny等)。

猜你喜欢

转载自blog.csdn.net/X131644/article/details/130814877