Edge detector

边缘是图像中沿某一方向强度发生剧烈变化的位置。边缘检测是一种基础的图像处理操作,其核心成分——图像梯度——同样是角点检测、光流以及直接法 SLAM 的基础。

首先是灰度化和平滑

边缘检测(和大多数 SLAM 前端处理一样)作用于灰度图像:梯度只需要强度信息,一个通道的处理速度比三个通道快 3 倍,而且颜色在不同光照条件下并不一致。标准的转换方式是亮度公式 I=0.299R+0.587G+0.114BI = 0.299R + 0.587G + 0.114B

由于求导会放大噪声,图像在计算梯度之前会先用高斯模糊进行平滑——即与如下核进行卷积

G(x,y)=12πσ2exp ⁣(x2+y22σ2)G(x,y) = \frac{1}{2\pi\sigma^2}\exp\!\left(-\frac{x^2+y^2}{2\sigma^2}\right)

σ\sigma 的选择决定了你所检测边缘的尺度:小的 σ\sigma 保留细节(也保留噪声),大的 σ\sigma 只保留粗略的结构。

Sobel 算子

Sobel 算子通过与两个 3×33 \times 3 核的卷积来计算图像梯度:

Kx=[101202101],Ky=[121000121]K_x = \begin{bmatrix} -1 & 0 & 1 \\ -2 & 0 & 2 \\ -1 & 0 & 1 \end{bmatrix}, \qquad K_y = \begin{bmatrix} -1 & -2 & -1 \\ 0 & 0 & 0 \\ 1 & 2 & 1 \end{bmatrix}

梯度大小为 I=(KxI)2+(KyI)2|\nabla I| = \sqrt{(K_x * I)^2 + (K_y * I)^2},梯度方向为 atan2(KyI,KxI)\mathrm{atan2}(K_y * I,\, K_x * I)。Sobel 算子把求导([1,0,1][-1, 0, 1] 模式)和与之垂直方向上的平滑([1,2,1][1, 2, 1] 权重)结合起来,因此比朴素的有限差分更能抵抗噪声。

Canny 边缘检测器

Canny 检测器是一个多阶段算法,能把原始梯度转化为细而定位良好的边缘曲线:

  1. 高斯平滑以抑制噪声。
  2. Sobel 梯度计算(大小和方向)。
  3. 沿梯度方向进行非极大值抑制,把脊线细化为单像素宽度:只有当某像素的梯度大小在沿梯度方向的两个邻居中都最大时,该像素才会被保留。
  4. 双阈值滞后处理,设置一个高阈值和一个低阈值:强边缘(高于高阈值)被保留,弱边缘(介于低阈值和高阈值之间)只有在与强边缘相连时才被保留。这样可以保留连续的轮廓,同时剔除孤立的噪声响应。
import cv2
edges = cv2.Canny(gray, threshold1=50, threshold2=150)  # low, high

这两种检测器在 OpenCV 中都只需一行代码(cv::Sobelcv::Canny),但值得从零实现一次,以便真正理解卷积和梯度的工作原理。

常见陷阱

对SLAM的意义

Sobel 计算出的图像梯度是 Harris 结构张量以及 Lucas-Kanade 光流法的输入,因此边缘检测是通往 SLAM 前端特征机制的一块垫脚石。边缘本身也被直接使用:在纹理稀少的人工环境中,线/边缘特征可以对点特征形成补充(例如 PL-SLAM),而 LSD-SLAM 等直接法则隐式地依赖高梯度(类似边缘)的像素来进行光度对齐。

相关条目