ORB_SLAM2:词袋模型 Bag of Words

一、理解BoW

假设有三句话

复制代码
我喜欢吃苹果
我喜欢吃香蕉
我喜欢看电影

我们建立一个词典

复制代码
Vocabulary:

Word 0:我
Word 1:喜欢
Word 2:吃
Word 3:苹果
Word 4:香蕉
Word 5:看
Word 6:电影

那么刚才的三句话就可以表示为:

复制代码
我    → Word 0
喜欢  → Word 1
吃    → Word 2
苹果  → Word 3

即   BoW1​=[1,1,1,1,0,0,0]

同理,剩下的两句可以表示为:

复制代码
BoW2​=[1,1,1,0,1,0,0]
BoW3​=[1,1,0,0,0,1,1]

于是,经过上面的处理,一句话就可以用一个向量表示。视觉BoW也是同样的思想,但是图像中并没有文字,但是有特征点和描述子。

假设一张图片提取了1000个 ORB特征点,

复制代码
Feature 1 → ORB descriptor
Feature 2 → ORB descriptor
Feature 3 → ORB descriptor
...
Feature 1000 → ORB descriptor

每个特征点的描述子都是256bit,这些描述子直接比较起来虽然可以,但是数量很多。所以 ORB-SLAM2 做了一件非常聪明的事情:把大量相似的 ORB 描述子归成一个"视觉单词"。

什么是"视觉单词"?

假设一张图有1000个ORB特征,经过Vocabulary:

复制代码
ORB Feature
   ↓
Visual Word

Feature 1  → Word 25
Feature 2  → Word 102
Feature 3  → Word 25
Feature 4  → Word 8
Feature 5  → Word 102
...

统计以后:

复制代码
Word 8    → 50个特征
Word 25   → 120个特征
Word 102  → 83个特征
Word 300  → 17个特征
...

于是整张图片就变成:

复制代码
BoW=[0,0,0,...,50,...,120,...,83,...]

这就是视觉 BoW。

所以ORB_SLAM2的BoW本质可以理解为:一张图片 --> ORB特征 --> 视觉单词 -->词频统计,也就是不再关心每一个具体的ORB特征是什么,而是关心这张图片出现了哪些视觉词,以及各自有多少。

二、ORB_SLAM2 中 ComputeBoW()

函数作用:把当前 Frame中的所有ORB 描述子,转换成视觉词袋表示。

cpp 复制代码
void Frame::ComputeBoW()
{
    if(mBowVec.empty())
    {
        vector<cv::Mat> vCurrentDesc = Converter::toDescriptorVector(mDescriptors);
        mpORBvocabulary->transform(vCurrentDesc,mBowVec,mFeatVec,4);
    }
}

变量含义

cpp 复制代码
transform(输入描述子, 输出BoW向量, 输出Feature向量, 深度);

mDescriptors 表示当前帧中所有特征点的描述子

mBowVec是什么?

mBowVec 通常是:BowVector mBowVec;它不是简单的:vector<float>,而是一个稀疏的:视觉词 ID → 权重

例如:

复制代码
Word 10  → 0.12
Word 53  → 0.08
Word 128 → 0.25
Word 456 → 0.15
Word 900 → 0.40

为什么不是统计次数而是权重?

假设:

复制代码
图像A:

Word 1 → 100次
Word 2 → 10次
Word 3 → 1次

简单统计:

复制代码
[100, 10, 1]

但是有些视觉词特别常见。例如:

复制代码
墙
边缘
角点
纹理

这些可能在很多图像里都出现。如果一个视觉词几乎每张图都出现,那么它对区分两张图的作用其实很小。这时候就会引入类似:TF-IDF的思想。

TF:Term Frequency。表示:这个视觉词在当前图像中出现得多不多?

IDF:Inverse Document Frequency。表示:这个视觉词在所有图像中常不常见?

于是:

复制代码
常见视觉词
↓
权重低

而:

复制代码
稀有视觉词
↓
权重高

所以最终:mBowVec 不是简单的出现次数,而是经过权重计算后的

复制代码
视觉词 → 权重

mBowVec与mFeatVec的区别

mBowVec表示:这张图像整体上有哪些视觉词? 它主要用于:**判断两张图像是否相似。**例如:

复制代码
Word 10  → 0.12
Word 53  → 0.08
Word 128 → 0.25
...

mFeatVec表示:**每个视觉词对应了哪些 ORB 特征?**例如:

复制代码
Word 10 → 特征 3、25、100
Word 53 → 特征 5、19、88
Word 128 → 特征 2、8、30、55

深度是什么?

mpORBvocabulary 指向ORBVocabulary,来自于Vocabulary/ORBvoc.txt。本质是哪个是一个巨大的ORB描述子字典,它不是简单的

cpp 复制代码
Word 0
Word 1
Word 2
...

而是一个树状结构,即Vocabulary Tree(词汇树)。

为什么需要树状结构?

假设 Vocabulary 有:100万个视觉单词。现在来了一个 ORB 描述子:D。最笨的方法:

复制代码
D 和 Word 0 比较
D 和 Word 1 比较
D 和 Word 2 比较
...
D 和 Word 999999 比较

需要比较:1000000 次,这非常慢。所以 ORB-SLAM2 建立了一棵树。例如:

复制代码
                    Root
                     |
          ┌──────────┼──────────┐
          ↓          ↓          ↓
        Node1      Node2      Node3
        / | \      / | \      / | \
       ↓  ↓  ↓    ↓  ↓  ↓    ↓  ↓  ↓
      ...        ...         ...

通过树逐层寻找,这样就不用和所有单词比较。

复制代码
ORB descriptor
      ↓
第一层
      ↓
第二层
      ↓
第三层
      ↓
第四层
      ↓
...
      ↓
Visual Word

三、BoW 相似 ≠ 一定是同一个地方

比如:两个办公室都有墙、桌子、窗户、电脑,那么 BoW 可能比较相似。只能说明可能存在回环,不能直接证明这是在同一个地方。因此,ORB_SLAM2后边还需要进行特征匹配、几何验证、Sim3、回环检测。

四、具体步骤流程

cpp 复制代码
                 当前图像
                    │
                    ↓
              ORB特征提取
                    │
                    ↓
             ORB KeyPoints
                    │
                    ↓
             ORB Descriptors
                    │
                    ↓
          mDescriptors(N×32)
                    │
                    ↓
     Converter::toDescriptorVector()
                    │
                    ↓
         vector<cv::Mat>
                    │
                    ↓
      mpORBvocabulary->transform()
                    │
                    ↓
             Vocabulary Tree
                    │
                    ↓
        每个描述子寻找Visual Word
                    │
             ┌──────┴──────┐
             ↓             ↓
          mBowVec       mFeatVec
             │             │
             ↓             ↓
       图像整体表示      特征分组
             │             │
             ↓             ↓
       相似度计算       快速特征匹配
             │
             ↓
        回环候选检测
             │
             ↓
        几何一致性验证
             │
             ↓
          回环闭合

五、举例说明

假设当前图像有 10 个 ORB 描述子:

复制代码
D1
D2
D3
D4
D5
D6
D7
D8
D9
D10

经过 Vocabulary:

复制代码
D1  → Word 5
D2  → Word 5
D3  → Word 8
D4  → Word 12
D5  → Word 5
D6  → Word 20
D7  → Word 8
D8  → Word 12
D9  → Word 12
D10 → Word 20

统计:

复制代码
Word 5  → 3
Word 8  → 2
Word 12 → 3
Word 20 → 2

那么这张图就可以表示成:

复制代码
Word 5  : 3
Word 8  : 2
Word 12 : 3
Word 20 : 2

再经过权重归一化,这就是:mBowVec。

复制代码
Word 5  : 0.30
Word 8  : 0.20
Word 12 : 0.30
Word 20 : 0.20

两张图像怎么比较?

假设:图像 A

复制代码
Word 5  : 0.30
Word 8  : 0.20
Word 12 : 0.30
Word 20 : 0.20

图像 B

复制代码
Word 5  : 0.28
Word 8  : 0.22
Word 12 : 0.32
Word 20 : 0.18

两者非常接近。所以:Similarity(A,B)比较高。

而图像 C

复制代码
Word 100 : 0.3
Word 200 : 0.2
Word 300 : 0.3
Word 500 : 0.2

和 A 几乎没有共同视觉词。那么:Similarity(A,C)就比较低。

相关推荐
蓝悦无人机3 天前
《概率机器人》读书笔记-第六章-机器人感知模型:波束、似然场与地标
机器人·slam·测距仪·观测模型·波束模型·似然场模型·地标模型
feasibility.6 天前
世界模型WSM技术解读:SLAM内化为具身智能的状态记忆,纯RGB机器人导航反超RGB-D
人工智能·机器人·aigc·slam·导航·具身智能·世界模型
大江东去浪淘尽千古风流人物6 天前
【HexVIO】DSP卸载双目惯性VIO:Hexagon向量化前端与单帧融合调度深度解析
前端·状态模式·slam·dsp·vio·hexagon·移动端加速
Felaim11 天前
【SLAM】SLAM-Former论文与代码导读
transformer·slam·dense slam·代码导读
Felaim11 天前
【SLAM】SLAM数据集相机规格说明
数据集·vslam·slam·相机标定
Felaim11 天前
【SLAM】SLAM-Former
transformer·slam·dense slam·几何基础模型
Felaim12 天前
【SLAM】人形机器人 VLN 相机与传感器配置调研
slam·传感器·人形机器人·vln·相机选型
火星机器人life15 天前
深度学习如何重塑移动机器人SLAM?一篇综述讲透视觉里程计、闭环检测与语义建图
深度学习·视觉里程计·slam·语义建图
reikocao15 天前
IMU预积分讲人话:递推、协方差、零偏修正到底在算什么
slam·imu·预积分
CS_Zero17 天前
大模型时代的SLAM
人工智能·机器学习·slam