【计算机视觉】边缘检测

图像的边缘简单来说就是图像中灰度不连续的地方。

1.图像梯度

图像梯度是指图像像素灰度值在某个方向上的变化;图像梯度是图像的一阶导数,实际计算时可以使用差分来近似。

1.1 什么是图像梯度?

图像梯度是一种数学工具,用于描述图像中像素值变化的速度和方向。换句话说,它反映了图像亮度值在空间上的变化率,因此是边缘检测特征提取图像分析中常用的重要概念。

1.1.1 图像梯度的定义

给定一幅二维灰度图像 I ( x , y ) I(x, y) I(x,y),它的梯度是一个向量,定义如下:

∇ I = ( ∂ I ∂ x , ∂ I ∂ y ) \nabla I = \left( \frac{\partial I}{\partial x}, \frac{\partial I}{\partial y} \right) ∇I=(∂x∂I,∂y∂I)

  • ( ∂ I ∂ x ) ( \frac{\partial I}{\partial x} ) (∂x∂I):图像在 x x x-方向上的变化率(水平梯度)。
  • ( ∂ I ∂ y ) ( \frac{\partial I}{\partial y} ) (∂y∂I):图像在 y y y-方向上的变化率(垂直梯度)。

梯度的大小方向定义如下:

  • 梯度大小(Gradient Magnitude):
    ∣ ∇ I ∣ = ( ∂ I ∂ x ) 2 + ( ∂ I ∂ y ) 2 |\nabla I| = \sqrt{\left( \frac{\partial I}{\partial x} \right)^2 + \left( \frac{\partial I}{\partial y} \right)^2} ∣∇I∣=(∂x∂I)2+(∂y∂I)2
  • 梯度方向(Gradient Direction):
    θ = arctan ⁡ ( ∂ I ∂ y ∂ I ∂ x ) \theta = \arctan\left(\frac{\frac{\partial I}{\partial y}}{\frac{\partial I}{\partial x}}\right) θ=arctan(∂x∂I∂y∂I)
1.1.2 如何计算图像梯度

在离散图像中,梯度的计算通常使用滤波器(卷积核)近似求导数。以下是常见方法:

1. 基本差分(Finite Difference)

利用相邻像素值的差分近似求导数:

  • ( ∂ I ∂ x ≈ I ( x + 1 , y ) − I ( x , y ) ) ( \frac{\partial I}{\partial x} \approx I(x+1, y) - I(x, y) ) (∂x∂I≈I(x+1,y)−I(x,y))
  • ( ∂ I ∂ y ≈ I ( x , y + 1 ) − I ( x , y ) ) ( \frac{\partial I}{\partial y} \approx I(x, y+1) - I(x, y) ) (∂y∂I≈I(x,y+1)−I(x,y))
2. Sobel算子

Sobel算子是一种常用的离散梯度滤波器,使用以下卷积核:

  • 水平梯度核( G x G_x Gx):
    [ − 1 0 1 − 2 0 2 − 1 0 1 ] \begin{bmatrix} -1 & 0 & 1 \\ -2 & 0 & 2 \\ -1 & 0 & 1 \end{bmatrix} −1−2−1000121
  • 垂直梯度核( G y G_y Gy):
    [ − 1 − 2 − 1 0 0 0 1 2 1 ] \begin{bmatrix} -1 & -2 & -1 \\ 0 & 0 & 0 \\ 1 & 2 & 1 \end{bmatrix} −101−202−101

使用 Sobel 算子计算出的梯度既平滑了噪声,又能准确提取边缘。

3. Scharr算子

Scharr算子是 Sobel 算子的改进版,能更好地处理图像细节。它的权值分布更均匀,适合高精度梯度计算。

4. 拉普拉斯算子

拉普拉斯算子计算的是二阶导数,用于检测图像的变化区域,而不是简单的一阶变化。

1.2 梯度的计算示例
python 复制代码
import cv2 as cv
import numpy as np

# 加载图像
img = cv.imread('example.jpg', cv.IMREAD_GRAYSCALE)

# 计算水平和垂直梯度
grad_x = cv.Sobel(img, cv.CV_64F, 1, 0, ksize=3)  # 水平梯度
grad_y = cv.Sobel(img, cv.CV_64F, 0, 1, ksize=3)  # 垂直梯度

# 计算梯度大小
magnitude = cv.magnitude(grad_x, grad_y)

# 显示结果
cv.imshow('Original', img)
cv.imshow('Gradient X', cv.convertScaleAbs(grad_x))
cv.imshow('Gradient Y', cv.convertScaleAbs(grad_y))
cv.imshow('Gradient Magnitude', cv.convertScaleAbs(magnitude))
cv.waitKey(0)
cv.destroyAllWindows()
1.3 梯度的应用
  1. 边缘检测:
    • 梯度强度大的地方往往是图像边缘,结合阈值可以提取轮廓(如 Canny 边缘检测)。
  2. 特征提取:
    • 梯度方向是许多特征描述符(如 SIFT、HOG)的基础。
  3. 图像增强:
    • 利用梯度信息可以增强图像的边缘或细节。
  4. 运动检测:
    • 梯度变化在时间序列中的对比可以用来检测运动或变化区域。

2.Canny边缘检测

Canny边缘检测是一种经典的多步骤边缘检测算法,由 John F. Canny 在 1986 年提出。它以鲁棒性、高准确性和抗噪性著称,广泛用于图像处理和计算机视觉任务中。

2.1 算法步骤

Canny 边缘检测分为以下几个步骤:

1. 噪声抑制(平滑处理)
  • 目标:减少噪声对边缘检测的影响。

  • 方法 :对图像进行高斯模糊。

    高斯模糊会平滑图像中的细节和噪声,同时保留大的结构边缘。

    公式(高斯滤波器):
    G ( x , y ) = 1 2 π σ 2 e − x 2 + y 2 2 σ 2 G(x, y) = \frac{1}{2\pi\sigma^2} e^{-\frac{x^2 + y^2}{2\sigma^2}} G(x,y)=2πσ21e−2σ2x2+y2

    其中, σ \sigma σ 决定平滑程度(模糊核的标准差)。

2. 计算图像梯度
  • 目标:找出图像中的边缘,即像素值变化剧烈的区域。

  • 方法 :使用 Sobel 算子计算水平梯度 ( G x G_x Gx) 和垂直梯度 ( G y G_y Gy),然后计算梯度的大小和方向。

    梯度大小(强度)计算公式:
    ∣ G ∣ = G x 2 + G y 2 |G| = \sqrt{G_x^2 + G_y^2} ∣G∣=Gx2+Gy2

    梯度方向计算公式:
    θ = arctan ⁡ ( G y G x ) \theta = \arctan\left(\frac{G_y}{G_x}\right) θ=arctan(GxGy)

    • 梯度强度大的地方可能是边缘。
    • 梯度方向用于后续的非极大值抑制。
3. 非极大值抑制(Non-Maximum Suppression)
  • 目标:精确定位边缘,去除非边缘的噪声响应。

  • 方法

    • 在梯度方向上检查当前像素值是否为局部极大值。
    • 如果不是局部极大值,则将该像素设为 0(非边缘)。

    操作:

    • 将梯度方向分为四个主方向(0°、45°、90°、135°)。
    • 比较当前像素与梯度方向上相邻两个像素的大小。
4. 双阈值边缘检测
  • 目标:区分强边缘、弱边缘和非边缘。
  • 方法
    • 设置两个阈值:高阈值 ( T h i g h T_{high} Thigh) 和低阈值 ( T l o w T_{low} Tlow)。
    • 对梯度强度进行分类:
      • 强边缘 :梯度强度 > T h i g h > T_{high} >Thigh。
      • 弱边缘 : T l o w < 梯度强度 ≤ T h i g h T_{low} < \text{梯度强度} \leq T_{high} Tlow<梯度强度≤Thigh。
      • 非边缘 :梯度强度 l e q T l o w leq T_{low} leqTlow。
5. 边缘连接(Hysteresis Thresholding)
  • 目标:确定最终的边缘。
  • 方法
    • 强边缘直接保留。
    • 弱边缘若与强边缘相连,则保留为边缘;否则丢弃。
2.2 Canny 边缘检测的代码实现
python 复制代码
import cv2 as cv
import numpy as np

# 加载图像(灰度模式)
img = cv.imread('example.jpg', cv.IMREAD_GRAYSCALE)

# Canny 边缘检测
edges = cv.Canny(img, threshold1=50, threshold2=150)

# 显示结果
cv.imshow('Original Image', img)
cv.imshow('Canny Edges', edges)
cv.waitKey(0)
cv.destroyAllWindows()
2.3 Canny 函数参数详解
python 复制代码
cv.Canny(image, threshold1, threshold2, apertureSize=3, L2gradient=False)
  1. image:输入图像,必须为灰度图像。
  2. threshold1:低阈值,用于区分弱边缘和非边缘。
  3. threshold2:高阈值,用于区分强边缘和弱边缘。
  4. apertureSize:Sobel 算子的核大小(默认为 3)。常用值:3、5、7。
  5. L2gradient :布尔值,是否使用更精确的梯度计算(默认为 False)。
    • 如果为 True,则使用 L2 范数( G x 2 + G y 2 \sqrt{G_x^2 + G_y^2} Gx2+Gy2 )。
    • 如果为 False,则使用 L1 范数( ∣ G x ∣ + ∣ G y ∣ |G_x| + |G_y| ∣Gx∣+∣Gy∣)。
2.4 Canny 边缘检测的优点
  1. 鲁棒性:可以很好地抵抗噪声,适用于复杂场景。
  2. 多步骤处理:包括平滑、梯度计算和非极大值抑制,结果更加精确。
  3. 边缘连接:通过双阈值和滞后连接有效去除了孤立的边缘点。
2.5 Canny 边缘检测的缺点
  1. 参数敏感:双阈值的选择对结果影响很大,需要手动调整。
  2. 计算成本高:多步骤处理增加了算法复杂度,不适合实时性要求高的应用。
2.6 应用场景
  1. 边缘检测:
    • 图像分割前的边缘提取。
  2. 特征提取:
    • 用于形状识别或物体检测。
  3. 运动检测:
    • 对帧差图像进行边缘检测,以识别移动物体的轮廓。
相关推荐
___波子 Pro Max.4 分钟前
pdf merge
python·pdf
数据小爬虫@9 分钟前
利用Python爬虫技术获取商品销量详情
开发语言·爬虫·python
摇光~11 分钟前
【数据分析岗】关于数据分析岗面试python的金典问题+解答,包含数据读取、数据清洗、数据分析、机器学习等内容
python·面试·数据分析
铭瑾熙13 分钟前
深度学习之全景分割
人工智能·深度学习
Yan-英杰13 分钟前
利用代理IP爬取Zillow房产数据用于数据分析
网络·python·网络协议·tcp/ip·数据分析
编码小哥15 分钟前
YOLO简史
yolo·计算机视觉
深度学习lover16 分钟前
<项目代码>YOLOv8 车牌识别<目标检测>
python·yolo·目标检测·计算机视觉·车牌识别
醉后才知酒浓34 分钟前
OpenCV--特征匹配
人工智能·opencv·计算机视觉
小李飞刀李寻欢39 分钟前
opencv实现给图像加上logo图像
人工智能·opencv·计算机视觉
qq_3384323741 分钟前
Jupyter Notebook 切换虚拟环境
ide·python·jupyter