
词袋向量的计算原理可以理解为一个“构建视觉词典”和“用词典描述图像”的过程。它的核心思想是把图像中提取的“特征点”类比成文章中的“单词”通过统计这些“单词”在图像中出现的频率将一张复杂的图像转换成一个数值向量。这个计算过程主要分为两大步离线构建词典和在线计算向量。️ 第一步离线构建“视觉词典”在系统运行前需要先利用大量图片通过聚类算法构建一棵“词汇树”Vocabulary Tree作为所有图像的通用词典。提取特征从大量不同的场景图片中提取ORB特征点及其描述子Descriptors。构建词汇树K-means聚类将所有提取到的特征描述子通过K-means算法进行层层聚类。第一层将所有特征点聚成k类得到k个聚类中心这些中心就是树第一层的节点。下一层对第一层的每一个节点类再将其内部的特征点聚成k类生成下一层的节点。重复这个过程重复d层最终得到一棵深度为d、每个节点有k个分支的k-d树。定义“单词”这棵词汇树的叶子节点最底层的节点就被定义为一个个的“视觉单词”Visual Word。整个词典总共可以表示k^d个不同的视觉单词。d层每一层上有K个节点第d层上共k^d个节点也就是k^d个单词例如在ORB-SLAM3中词典的参数为k10d6因此可以表达多达10^6 1,000,000个不同的视觉单词。 第二步在线计算图像的“词袋向量”当系统运行时对于每一帧新图像关键帧都会进行以下操作来生成词袋向量提取特征提取当前图像的ORB特征点和描述子。寻找单词对于当前图像中的每一个特征点描述子从词汇树的根节点开始遍历词典/词汇树的每一层计算它与当前层所有k个节点的距离选择距离最近的节点进入下一层直到抵达一个叶子节点。这个叶子节点的索引就是该特征点对应的视觉单词IDWord ID。当前帧中m个特征点描述子每个描述子可以查词典得到一个world ID,一个n个world ID ,多个特征点描述子可能查到同一个world ID统计词频TF遍历完当前帧所有特征点后统计每个视觉单词ID在这张图像中出现的次数Term Frequency, TF。n个world ID ,计算每一个world ID 的次数计算权重TF-IDF为每个单词的频数乘以一个权重。这个权重由TF-IDF方案决定。TF (词频)即上一步统计的单词在当前图像中出现的频率。IDF (逆文档频率)在离线构建词典时就已算好。它衡量所有训练图片中的每一个一个单词在所有训练图片中出现的频繁程度。如果一个单词在越多的图片中出现说明它越普遍区分度越低其IDF值就越小。最终权重单词权重 TF × IDF。这个权重值就是TF-IDF最终一张图像会被表示为一个稀疏的向量mBowVec其中包含了这张图像里出现的所有单词ID及其对应的TF-IDF权重。mBowVec 中保存的是 world ID 和 其对应的TF-IDF权重⚡ 加速索引正向与逆向索引为了加速后续的匹配和检索ORB-SLAM3还会构建两种索引逆向索引Inverse Index以“单词”为 key记录包含该单词的所有图像的列表。在闭环检测时可以通过当前帧的单词快速找到所有与之有共同单词的历史关键帧。包含有某一个特征点的所有关键帧正向索引Direct Index以“图像”为 key记录该图像中每个词汇树节点下有哪些特征点。在特征匹配时可以只对两帧图像中属于同一节点的特征点进行匹配大大缩小了搜索范围。某一个关键帧中包含的所有特征点 总结词袋向量的计算本质上是将图像特征ORB描述子通过离线构建的词汇树Vocabulary Tree量化成离散的视觉单词Visual Word再统计这些单词的频率并用TF-IDF加权最终形成一个可用于高效相似度计算的稀疏向量。补充mBowVec的维度在概念上等同于整个视觉词典的大小但在实际存储时它是一个仅包含非零元素的稀疏向量。具体可以从以下几个方面来理解 概念维度等同于词典大小视觉词典Vocabulary是通过离线训练得到的它包含了数量庞大的“视觉单词”Visual Word。mBowVec在概念上是一个维度为N的向量这个N就是词典中单词的总数。在ORB-SLAM3中这个N的典型值是1,000,000即10^6。这个数字来源于词典构建时的参数一个深度为6层、每层有10个分支的词汇树k10, d6其叶子节点即单词总数就是10^6。️ 实际存储一个“稀疏”的映射表虽然概念上维度高达百万但一张图像只包含有限个特征点例如几百个因此它只会命中词典中极少数的单词。如果用一个长度为1,000,000的数组来存储其中绝大部分元素都是0会造成巨大的内存浪费。因此mBowVec的实际类型是DBoW2::BowVector它被定义为一个std::mapWordId, WordValue。WordId是命中单词的ID键。WordValue是该单词对应的TF-IDF 权重值值。这种设计意味着mBowVec的实际大小size()等于该图像中非零权重单词的数量通常只有几百。它只存储有意义的“单词-权重”对忽略所有零值是一种非常高效的存储方式。 总结概念上mBowVec的维度是词典的大小通常为1,000,000。实际上它作为一个std::map其元素个数等于图像中有效特征点对应的单词数量通常为几百个。