4、特征点法前端:ORB特征、SIFT特征、特征匹配与误匹配剔除

聊到SLAM前端,说白了就是解决一个核心问题:怎么让相机认出自己看过的地方

我刚开始做SLAM的时候,觉得这事儿挺玄乎的。相机就是个镜头加传感器,它又没长脑子,怎么知道「哦,这个墙角我三秒前见过」?

嗯,答案就是特征点。

特征点就像图像的「指纹」。我们提取出这些指纹,然后让算法去比对。今天这一讲,我们就来聊聊两种最经典的特征——ORBSIFT,以及怎么把匹配做准。


4.1 特征点:图像里的「地标」

先问个问题:什么样的点适合做特征?

我个人习惯用三个标准来衡量:

  • 可重复性:换个角度、换个光照,还能找到它
  • 独特性:这个点跟周围不一样,一眼就能认出来
  • 高效性:计算要快,毕竟SLAM是实时系统

你想想看,如果一张图里全是白墙,那特征点就提取不出来。所以特征点往往出现在角点、边缘、纹理丰富的区域。

核心概念:特征点 = 关键点(位置) + 描述子(身份信息)

关键点告诉你「在哪」,描述子告诉你「它是谁」。


4.2 SIFT特征:老牌劲旅,稳但慢

SIFT(Scale-Invariant Feature Transform)是2004年Lowe提出的。说实话,这算法在学术界地位很高,但在工程界——嗯,我很少在实时SLAM里用它。

为什么?因为太慢了。

SIFT的核心思想是:在尺度空间中检测极值点。它用高斯金字塔构建多尺度图像,然后找那些在不同尺度下都能稳定出现的点。

SIFT的主要步骤

  1. 尺度空间极值检测:用DoG(高斯差分)近似LoG,找候选点
  2. 关键点定位:去掉低对比度的点和边缘响应点
  3. 方向分配:统计梯度方向直方图,给每个点分配主方向
  4. 生成描述子:在关键点周围取16x16区域,分成4x4子块,每个子块统计8方向梯度直方图

最终得到一个128维的描述子向量。

我的经验:SIFT的128维描述子虽然鲁棒性极强,但在嵌入式设备上跑不动。我曾经在树莓派上试过,一帧640x480的图像要处理将近1秒——这还做什么SLAM?直接放弃。

SIFT的优点很明显:旋转不变性、尺度不变性、光照鲁棒性都很好。但缺点就是计算量太大,不适合实时系统。


4.3 ORB特征:工程界的「万金油」

ORB(Oriented FAST and Rotated BRIEF)是2011年提出的。说白了,它就是FAST角点 + BRIEF描述子的改良版。

我个人非常喜欢ORB,因为它做到了速度与精度的平衡。在ORB-SLAM系列中,它就是绝对的主角。

ORB的两大组件

1. FAST角点检测

FAST的思路很简单:如果一个像素点跟它周围一圈的像素差别很大,那它就是角点。

  • 取一个像素p,亮度为Ip
  • 以p为圆心,半径为3的圆上取16个像素
  • 如果连续N个点的亮度 > Ip + t 或 < Ip - t,则p是角点
  • 通常N取12(FAST-12)

注意:FAST本身不具备尺度不变性。ORB的解决办法是——构建图像金字塔,在每层金字塔上分别提取FAST角点。这样就能应对尺度变化了。

2. BRIEF描述子

BRIEF是一种二进制描述子。它不计算梯度,而是比较像素对的亮度大小。

  • 在关键点周围选256对像素点
  • 每对比较:如果第一个点比第二个点亮,记为1,否则记为0
  • 最终得到一个256位的二进制串

ORB给BRIEF加上了方向信息(steered BRIEF),让它具备旋转不变性。具体做法是:根据关键点的灰度质心方向,旋转像素对的位置。

ORB vs SIFT 对比

特性 SIFT ORB
描述子维度 128维(浮点) 256位(二进制)
匹配速度 慢(欧氏距离) 快(汉明距离)
尺度不变性 优秀(尺度空间) 一般(金字塔)
旋转不变性 优秀 良好(灰度质心法)
计算速度 快(约SIFT的30倍)
适用场景 离线、高精度 实时SLAM、嵌入式

4.4 特征匹配:让两张图「认亲」

提取完特征点,下一步就是匹配。说白了,就是找两张图里「长得像」的特征点对。

暴力匹配(Brute-Force Matcher)

最简单粗暴的方法:对于左图的每个特征点,计算它与右图所有特征点的距离,取最近的那个。

  • ORB用汉明距离:两个二进制串异或后统计1的个数
  • SIFT用欧氏距离:向量差的L2范数

避坑指南:我曾经在项目中直接用暴力匹配,结果一帧图像匹配耗时200ms。后来改用FLANN(快速最近邻搜索库),速度提升了5倍。对于ORB这种二进制描述子,用FLANN的LSH索引效果很好。

快速最近邻搜索(FLANN)

FLANN不是一种匹配算法,而是一种索引结构。它构建KD-Tree或LSH哈希表,加速最近邻搜索。

对于高维浮点描述子(如SIFT),用KD-Tree;对于二进制描述子(如ORB),用LSH。


4.5 误匹配剔除:别让「假亲戚」混进来

匹配完你会发现,总有一些错误的匹配对。嗯,这是不可避免的。我刚开始做的时候,看到匹配结果里那些交叉的线,心里就发毛。

怎么办?用下面这些方法。

方法一:距离阈值法

最简单的过滤:如果最近距离 > 某个阈值,就认为这个匹配不可靠。

// 伪代码示例
if (best_distance > threshold) {
    reject_match();
}

但阈值不好设。设大了误匹配多,设小了正确匹配也被删了。

方法二:最近邻与次近邻比值法(Lowe's Ratio Test)

这是SIFT论文里提出的方法,非常经典。

  • 对于左图的一个特征点,找到右图中距离最近的两个点
  • 计算最近距离d1和次近距离d2
  • 如果 d1 / d2 < 0.7(经验值),则接受这个匹配

为什么有效?因为正确的匹配,最近距离会远小于次近距离;而错误的匹配,两个距离往往差不多。

我的习惯:在ORB-SLAM中,我一般把比值设为0.75~0.8。太严格会丢失匹配,太宽松会引入误匹配。具体调参要看你的场景——纹理丰富的场景可以严格点,纹理少的场景要放宽。

方法三:RANSAC(随机采样一致性)

RANSAC是SLAM里的大杀器。它不直接过滤匹配,而是估计一个几何模型(比如单应矩阵或基础矩阵),然后剔除不符合模型的匹配。

步骤很简单:

  1. 随机选4对匹配点,计算单应矩阵H
  2. 用H去投影所有点,计算投影误差
  3. 误差小于阈值的点算「内点」,否则是「外点」
  4. 重复N次,取内点最多的那次结果
// OpenCV中的RANSAC用法
cv::Mat mask;
cv::findHomography(srcPoints, dstPoints, cv::RANSAC, 3.0, mask);
// mask中为1的点是内点,为0的是外点

注意:RANSAC不是万能的。如果误匹配比例超过50%,RANSAC可能失效。我曾经在一个低纹理走廊里遇到过这种情况——匹配全乱了,RANSAC怎么迭代都找不到正确的模型。后来我加了IMU辅助,才把问题解决。


4.6 本章知识体系

下面这张图总结了特征点法前端的核心流程:

特征点法前端核心流程 输入图像帧 特征提取:ORB / SIFT 特征匹配:暴力 / FLANN 误匹配剔除:距离阈值 / Lowe比值 / RANSAC 输出:可靠匹配对 → 位姿估计 关键点+描述子 汉明/欧氏距离 几何一致性检查

4.7 小结

这一讲我们聊了:

  • SIFT:精度高、鲁棒性强,但计算量太大,不适合实时SLAM
  • ORB:速度快、性能均衡,是工程界的首选
  • 特征匹配:暴力匹配简单但慢,FLANN是更好的选择
  • 误匹配剔除:Lowe比值法 + RANSAC 是黄金组合

说实话,特征点法前端看起来简单,但真正调起来坑不少。我记得有一次在室外场景,光照变化剧烈,ORB的匹配率掉到了30%以下。后来我调整了FAST的阈值,并且用了自适应阈值,才把匹配率提上来。

嗯,这些经验都是一次次踩坑换来的。希望你能少走些弯路。


专注资料整理