您当前的位置: 首页 > 
  • 1浏览

    0关注

    417博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

(01)ORB-SLAM2源码无死角解析-(31) ORB特征匹配→词袋BoW:BRIEF描述子转BoW向量

江南才尽,年少无知! 发布时间:2022-05-21 11:06:57 ,浏览量:1

讲解关于slam一系列文章汇总链接:史上最全slam从零开始,针对于本栏目讲解的(01)ORB-SLAM2源码无死角解析链接如下(本文内容来自计算机视觉life ORB-SLAM2 课程课件): (01)ORB-SLAM2源码无死角解析-(00)目录_最新无死角讲解:https://blog.csdn.net/weixin_43013761/article/details/123092196   文末正下方中心提供了本人 联系方式, 点击本人照片即可显示 W X → 官方认证 {\color{blue}{文末正下方中心}提供了本人 \color{red} 联系方式,\color{blue}点击本人照片即可显示WX→官方认证} 文末正下方中心提供了本人联系方式,点击本人照片即可显示WX→官方认证  

一、前言

通过上一篇博客,已经对 BoW 进行了理论讲解。其中有一个重要的图示: 在这里插入图片描述 假设上述为构建好的 BoW词袋,那么如何把一个特征点的 BRIEF 转行成 BoW向量呢? src/Frame.cc 文件,找到函数 void Frame::ComputeBoW()。可以看到如下代码:

		// 将特征点的描述子转换成词袋向量mBowVec以及特征向量mFeatVec
        mpORBvocabulary->transform(vCurrentDesc,	//当前的描述子vector
								   mBowVec,			//输出,词袋向量,记录的是单词的id及其对应权重TF-IDF值
								   mFeatVec,		//输出,记录node id及其对应的图像 feature对应的索引
								   4);				//4表示从叶节点向前数的层数

该函数的功能,就是把一幅图所有的描述子转换成 BoW向量,也就是把 vCurrentDesc 转换成 mBowVec 以及 mFeatVec。这里先介绍以下 mBowVec 与 mFeatVec 代表什么.

DBoW2::BowVector mBowVec: 其可以存储多个元素,每个元素包含了两个值: 叶子节点 id,其对应的权重 DBoW2::FeatureVector mFeatVec: 其可以存储多个元素,每个元素包含了两个值: 第一个值为叶子节点(word)所属节点 id(注意,并非父节点id),其与参数levelsup相关;第二个值为特征点,或者说 BRIEF 描述子的索引。

转换流程 其上图中紫色的箭头线,就是转换的流程,首先输入的 BRIEF描述子 与根节点的所有之节点的 BRIEF描述子 描述子进行比较,也就是与图像的 Level1 的节点进行比较。这里注意一个点: 除了叶子(word)节点,其于节点的 BRIEF描述子 都是为其子节点的平均值。通过汉明距离比较之后,找到 Level1 中与输入 BRIEF描述子 最近的节点 称为 node1。那么下一步就是与 best_node1节点所有子节点进行比较,从中再找到汉明距离最近的节点 best_node2,这样依次循环,直到寻找到最匹配的叶子节 best_word4 点为止,找到了叶子节点,就知道叶子节点的 id 与 其对应的权重,就能构建一个元素存储于 mBowVec 之中。

如果如上图所示,levelsup 参数为3,那么 mFeatVec 元素的第一个值,就是 best_node1节点的 id; 第二个值就是输入 BRIEF 描述子对应特征点在整张图像中的索引。因为 levelsup=3,所以从叶子节点往上数3级,级为其所属节点。对应于源码中变量 nid(后面有源码讲解) 。

 

二、源码转换过程

下面来说说源码的转换流程,其实总的来说与上面的流程差不多,这里再详细的梳理一下: ( 1 ) : \color{blue}{(1)}: (1):根据权重的计算方式,运行不同的代码,主要存在四种计算权重的方式,分别为 TF_IDF,TF,IDF,BINARY。 ( 2 ) : \color{blue}{(2)}: (2):取出根节点的所有子节点,赋值给 nodes,计算输入BRIEF描述子与第一个子节点,即 nodes[0] 的汉明距离。再循环与其与子节点的距离,找到最距离最近的一个节点。然后再取出该节点的所有子节点,赋值给 nodes,重复前面的流程。 ( 3 ) : \color{blue}{(3)}: (3):在步骤(2)的循环过程中,会对当前汉明距离最近节点进行判断,如果其为倒数 levelsup 层级,则记录下该节点 id,对应于代码中的 nid。 ( 4 ) : \color{blue}{(4)}: (4):当跳出代码中的do while 循环,则表示已经找到最匹配的叶子节点。 ( 5 ) : \color{blue}{(5)}: (5):通过前面的步骤,已经获得了输入BRIEF描述子对应的子节点,以及所属节点的id,与之对应的权重,再进一步把这些信息添加到 mBowVec 与 mFeatVec 之中。对应于源码如下:

        // 如果Word 权重大于0,将其添加到BowVector 和 FeatureVector
        v.addWeight(id, w);
        fv.addFeature(nid, i_feature);

这里大家注意一点,就是再添加的时候,其会对节点id进行排序,每次会找到合适的位置插入。

 

三、源码注释

该源码位于在 src/Frame.cc 中被调用,调用源码如下:

/**
 * @brief 计算当前帧特征点对应的词袋Bow,主要是mBowVec 和 mFeatVec
 * 
 */
void Frame::ComputeBoW()
{
	
    // 判断是否以前已经计算过了,计算过了就跳过
    if(mBowVec.empty())
    {
		// 将描述子mDescriptors转换为DBOW要求的输入格式
        vector vCurrentDesc = Converter::toDescriptorVector(mDescriptors);
		// 将特征点的描述子转换成词袋向量mBowVec以及特征向量mFeatVec
        mpORBvocabulary->transform(vCurrentDesc,	//当前的描述子vector
								   mBowVec,			//输出,词袋向量,记录的是单词的id及其对应权重TF-IDF值
								   mFeatVec,		//输出,记录node id及其对应的图像 feature对应的索引
								   4);				//4表示从叶节点向前数的层数
    }
}

其上的 transform 实现于 src/Thirdpaty/DBoW2/DBoW2/TemplatedVocabulary.h 之中:


// --------------------------------------------------------------------------
/**
 * @brief 将描述子转化为Word id, Word weight,节点所属的父节点id(这里的父节点不是叶子的上一层,它距离叶子深度为levelsup)
 * 
 * @tparam TDescriptor            
 * @tparam F 
 * @param[in] feature                 特征描述子
 * @param[in & out] word_id           Word id
 * @param[in & out] weight            Word 权重
 * @param[in & out] nid               记录当前描述子转化为Word后所属的 node id,它距离叶子深度为levelsup
 * @param[in] levelsup                距离叶子的深度
 */
template
void TemplatedVocabulary::transform(const TDescriptor &feature, 
  WordId &word_id, WordValue &weight, NodeId *nid, int levelsup) const
{ 
  // propagate the feature down the tree
  vector nodes;
  typename vector::const_iterator nit;

  // level at which the node must be stored in nid, if given
  // m_L: depth levels, m_L = 6 in ORB-SLAM2
  // nid_level 当前特征点转化为的Word 所属的 node id,方便索引
  const int nid_level = m_L - levelsup;
  if(nid_level second /= nd;
    }
  
  }
  else // IDF || BINARY
  {
    unsigned int i_feature = 0;
    for(fit = features.begin(); fit  0) // not stopped
      {
        v.addIfNotExist(id, w);
        fv.addFeature(nid, i_feature);
      }
    }
  } // if m_weighting == ...
  
  if(must) v.normalize(norm);
}

 

四、结语

通过该片博客,了解了 BRIEF描述子 如果通过 词袋BoW 转换成 BoW向量。既然了解了 BoW向量 的来源,那么下面是探讨如何对其进行利用了。

    本文内容来自计算机视觉life ORB-SLAM2 课程课件

关注
打赏
1592542134
查看更多评论
立即登录/注册

微信扫码登录

0.0414s