ORB-SLAM3 mFeatVec
mFeatVec(Feature Vector,特征向量)的计算原理,简单来说就是:为当前帧图像中的每个特征点,找到它在视觉词汇树中对应的中间节点(叶子节点world ID 上溯4层的节点ID),并将该特征点的索引(ORB特征点在当前帧图像中的索引),存入这个节点ID 下的一个列表里。
它的核心作用就像一份“花名册”,为后续的特征匹配提供了一份按地点(节点)归类的索引,从而避免了全局的暴力搜索。
🧠 核心思想:在“街区”里找人
为了理解mFeatVec的原理,我们可以做一个类比:
mBowVec(词袋向量):相当于“全局摘要”。它只告诉你有某个单词(比如“窗户”),但不说这个单词具体出现在图像的哪个位置。它用于快速比较两张图的整体相似度。mFeatVec(特征向量):相当于“街区地图”。它把图像特征点按“街区”(词汇树的中间节点)分类。当你在这个街区里找某个特征点时,就不用满城搜索,只需要查看这个街区的居民列表即可。
mFeatVec的这种“街区”设计,是加速特征匹配的关键。
⚙️ 计算流程:两步构建索引
mFeatVec的计算和mBowVec是同步的,都在ComputeBoW()函数中完成。
特征点“落户”:对于当前帧图像中提取的每个ORB特征点,它的描述子会从词汇树的根节点出发,每层都选择与它最相似的子节点,一路向下,直到抵达一个叶子节点(即一个具体的“视觉单词” world ID)。
登记到“街区”:在特征点向下搜索的过程中,
ComputeBoW()函数除了记录最终的单词world ID,还会记录下这个特征点经过的、距离叶子节点固定层数(比如4层)的那个中间节点ID。这个中间节点ID,就是它归属的“街区”。代码层面,
DBoW2::FeatureVector::addFeature(NodeId id, unsigned int i_feature)函数实现了这一登记过程:它会将特征点(在当前帧图像中)的索引i_feature添加到对应中间节点IDid的列表中。(NodeId id是中间节点ID,i_feature是ORB特征点在当前帧图像中的索引)
🚀 核心应用:如何用mFeatVec加速匹配?
这是mFeatVec最关键的价值所在。在特征匹配函数SearchByBoW中,它被这样使用:
同步遍历:同时遍历两个关键帧的
mFeatVec(例如,记为f1it和f2it),找出它们拥有相同中间节点ID的部分。(两个关键帧的mFeatVec包含 相同的某个中间节点 ID)限制匹配范围:
如果两帧都包含节点
N,那么匹配算法只会比较f1it中N节点下的特征点列表和f2it中N节点下的特征点列表。(相同的某个中间节点 ID下,暴力匹配两帧的ORB特征点,因为它们之间有很大的相似性)这相当于把原本需要在成百上千个点之间进行的“全局搜索”,缩小到了只在一个“街区”(对应节点)内的少量点之间进行比对,极大地提升了匹配速度。(不是两帧之间的所有特征点都暴力匹配,降低了匹配次数)
💎 总结
mFeatVec本质是一个按词汇树节点ID索引的、记录特征点ID的列表(std::map<NodeId, std::vector<unsigned int>>)。它通过将特征点按“视觉相近程度”预先分组,为后续的帧间特征匹配提供了“街区级”的快速索引,是ORB-SLAM3能够实现实时数据关联的关键数据结构。