OpenCV(6):图像边缘检测

发布于:2025-02-23 ⋅ 阅读:(99) ⋅ 点赞:(0)

        图像边缘检测是计算机视觉和图像处理中的一项基本任务,它用于识别图像中亮度变化明显的区域,这些区域通常对应于物体的边界。是 OpenCV 中常用的边缘检测函数及其说明:

函数 算法 说明 适用场景
cv2.Canny() Canny 边缘检测 多阶段算法,检测效果较好,噪声抑制能力强。 通用边缘检测,适合大多数场景。
cv2.Sobel() Sobel 算子 基于一阶导数的边缘检测,可以检测水平和垂直边缘。 检测水平和垂直边缘。
cv2.Scharr() Scharr 算子 Sobel 算子的改进版本,对边缘的响应更强。 检测细微的边缘。
cv2.Laplacian() Laplacian 算子 基于二阶导数的边缘检测,对噪声敏感。 检测边缘和角点。

1 Canny 边缘检测 (cv2.Canny())

        Canny 边缘检测是一种多阶段的边缘检测算法,由 John F. Canny 在 1986 年提出。Canny 边缘检测被认为是边缘检测的"金标准",因为它能够在噪声抑制和边缘定位之间取得良好的平衡。

1.1 Canny 边缘检测的步骤

        Canny 边缘检测算法主要包括以下几个步骤:

  1. 噪声抑制:使用高斯滤波器对图像进行平滑处理,以减少噪声的影响。
  2. 计算梯度:使用 Sobel 算子计算图像的梯度幅值和方向。
  3. 非极大值抑制:沿着梯度方向,保留局部梯度最大的像素点,抑制其他像素点。
  4. 双阈值检测:使用两个阈值(低阈值和高阈值)来确定真正的边缘。高于高阈值的像素点被认为是强边缘,低于低阈值的像素点被抑制,介于两者之间的像素点如果与强边缘相连则保留。
  5. 边缘连接:通过滞后阈值处理,将弱边缘与强边缘连接起来,形成完整的边缘。

1.2 使用 OpenCV 实现 Canny 边缘检测

        在 OpenCV 中,可以使用 cv2.Canny() 函数来实现 Canny 边缘检测。该函数的原型如下:

edges = cv2.Canny(image, threshold1, threshold2, apertureSize=3, L2gradient=False)
  • image:输入图像,必须是单通道的灰度图像。
  • threshold1:低阈值。
  • threshold2:高阈值。
  • apertureSize:Sobel 算子的孔径大小,默认为 3。
  • L2gradient:是否使用 L2 范数计算梯度幅值,默认为 False(使用 L1 范数)。
import cv2

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

# 应用 Canny 边缘检测
edges = cv2.Canny(image, 100, 200)

# 显示结果
cv2.imshow('Canny Edges', edges)
cv2.waitKey(0)
cv2.destroyAllWindows()

2 Sobel 算子 (cv2.Sobel())

        Sobel 算子是一种基于梯度的边缘检测算子,它通过计算图像在水平和垂直方向上的梯度来检测边缘。Sobel 算子结合了高斯平滑和微分操作,因此对噪声具有一定的抑制作用。

2.1 Sobel 算子的原理

        Sobel 算子使用两个 3x3 的卷积核分别计算图像在水平和垂直方向上的梯度:

  • 水平方向的卷积核:
    [-1, 0, 1]
    [-2, 0, 2]
    [-1, 0, 1]
  • 垂直方向的卷积核:
    [-1, -2, -1]
    [ 0,  0,  0]
    [ 1,  2,  1]

        通过这两个卷积核,可以分别得到图像在水平和垂直方向上的梯度 Gx 和 Gy。最终的梯度幅值可以通过以下公式计算:

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

2.2 使用 OpenCV 实现 Sobel 算子

        在 OpenCV 中,可以使用 cv2.Sobel() 函数来计算图像的梯度。该函数的原型如下:

dst = cv2.Sobel(src, ddepth, dx, dy, ksize=3, scale=1, delta=0, borderType=cv2.BORDER_DEFAULT)
  • src:输入图像。
  • ddepth:输出图像的深度,通常使用 cv2.CV_64F
  • dx:x 方向上的导数阶数。
  • dy:y 方向上的导数阶数。
  • ksize:Sobel 核的大小,默认为 3。
  • scale:缩放因子,默认为 1。
  • delta:可选的 delta 值,默认为 0。
  • borderType:边界填充类型,默认为 cv2.BORDER_DEFAULT
import cv2
import numpy as np

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

# 计算 x 方向的梯度
sobel_x = cv2.Sobel(image, cv2.CV_64F, 1, 0, ksize=3)

# 计算 y 方向的梯度
sobel_y = cv2.Sobel(image, cv2.CV_64F, 0, 1, ksize=3)

# 计算梯度幅值
sobel_combined = np.sqrt(sobel_x ** 2 + sobel_y ** 2)

# 显示结果
cv2.imshow('Sobel X', sobel_x)
cv2.imshow('Sobel Y', sobel_y)
cv2.imshow('Sobel Combined', sobel_combined)
cv2.waitKey(0)
cv2.destroyAllWindows()

3 Scharr算子(cv2.Scharr())

3.1 Scharr算子的原理

        在离散的空间上,有很多方法可以用来计算近似导数,在使用 3×3 的 Sobel 算子时,可能计算结果并不太精准。OpenCV 提供了 Scharr 算子,该算子具有和 Sobel 算子同样的速度,且精度更高。可以将 Scharr 算子看作对 Sobel 算子的改进,其核通常为:

3.2 使用 OpenCV 实现 Scharr 算子

        OpenCV 提供了函数 cv2.Scharr()来计算 Scharr 算子,其语法格式如下:

dst = cv2.Scharr( src, ddepth, dx, dy[, scale[, delta[, borderType]]] )
  •  dst 代表输出图像。
  • src 代表原始图像。
  • ddepth 代表输出图像深度。该值与函数 cv2.Sobel()中的参数 ddepth 的含义相同。
  • dx 代表 x 方向上的导数阶数。
  • dy 代表 y 方向上的导数阶数。
  • scale 代表计算导数值时的缩放因子,该项是可选项,默认值是 1,表示没有缩放。
  • delta 代表加到目标图像上的亮度值,该项是可选项,默认值为 0。
  • borderType 代表边界样式。
import cv2

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

# 计算 x 方向的梯度
scharr_x = cv2.Scharr(image, cv2.CV_64F, 1, 0)

# 计算 y 方向的梯度
scharr_y = cv2.Scharr(image, cv2.CV_64F, 0, 1)

# 计算梯度幅值
scharr_combined = cv2.addWeighted(scharr_x, 0.5, scharr_y, 0.5, 0)

# 显示结果
cv2.imshow('Scharr X', scharr_x)
cv2.imshow('Scharr Y', scharr_y)
cv2.imshow('Scharr Combined', scharr_combined)
cv2.waitKey(0)
cv2.destroyAllWindows()

4 Laplacian 算子 (cv2.Laplacian())

        Laplacian 算子是一种二阶微分算子,它通过计算图像的二阶导数来检测边缘。Laplacian 算子对噪声比较敏感,因此通常在使用之前会对图像进行高斯平滑处理。

4.1 Laplacian 算子的原理

        Laplacian 算子使用以下卷积核来计算图像的二阶导数:

[ 0,  1,  0]
[ 1, -4,  1]
[ 0,  1,  0]

        通过这个卷积核,可以得到图像的 Laplacian 值。Laplacian 值较大的区域通常对应于图像的边缘。

4.2 使用 OpenCV 实现 Laplacian 算子

        在 OpenCV 中,可以使用 cv2.Laplacian() 函数来计算图像的 Laplacian 值。该函数的原型如下:

dst = cv2.Laplacian(src, ddepth, ksize=1, scale=1, delta=0, borderType=cv2.BORDER_DEFAULT)
  • src:输入图像。
  • ddepth:输出图像的深度,通常使用 cv2.CV_64F
  • ksize:Laplacian 核的大小,默认为 1。
  • scale:缩放因子,默认为 1。
  • delta:可选的 delta 值,默认为 0。
  • borderType:边界填充类型,默认为 cv2.BORDER_DEFAULT
import cv2

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

# 应用 Laplacian 算子
laplacian = cv2.Laplacian(image, cv2.CV_64F)

# 显示结果
cv2.imshow('Laplacian', laplacian)
cv2.waitKey(0)
cv2.destroyAllWindows()

5 常用边缘检测函数对比

函数 算法 优点 缺点 适用场景
cv2.Canny() Canny 边缘检测 噪声抑制能力强,边缘检测效果好。 参数调节较为复杂。 通用边缘检测,适合大多数场景。
cv2.Sobel() Sobel 算子 计算简单,适合检测水平和垂直边缘。 对噪声敏感,边缘检测效果一般。 检测水平和垂直边缘。
cv2.Scharr() Scharr 算子 对边缘的响应更强,适合检测细微边缘。 对噪声敏感。 检测细微的边缘。
cv2.Laplacian() Laplacian 算子 可以检测边缘和角点。 对噪声非常敏感。 检测边缘和角点。

网站公告

今日签到

点亮在社区的每一天
去签到