个人博客网站制作代码,做网站 商标分类,平面设计师磨刀石,苏州吴江区建设局网站前言
DBOW作为一种视觉回环技术被广泛应用在各类VSLAM框架中#xff0c;之前的经验主要集中在使用和抽象理解层面#xff0c;近期花了一些时间仔细阅读了相关论文和源码#xff0c;这里做一些记录。
两个关键概念
Vocabulary
通过预先训练得到的词汇库#xff0c;以树状…前言
DBOW作为一种视觉回环技术被广泛应用在各类VSLAM框架中之前的经验主要集中在使用和抽象理解层面近期花了一些时间仔细阅读了相关论文和源码这里做一些记录。
两个关键概念
Vocabulary
通过预先训练得到的词汇库以树状数据结构保存便于后续查询如下图黄色部分
训练过程通过数据集提取每张图片feature构成一个feature集将feature集进行按层级的kmeans聚类每一层都进行一次聚类得到centroid node作为节点最终获取到d层共w个words每一个word根据在数据集中的频次计算其weight并保存待后续使用。查询过程从根节点开始将待查询featuref与每层的node计算hamming distance选择最小值的node继续往下依次从上到下贯穿整棵树直到叶子节点就得到其对应的word。
Dataset
上图中的蓝色部分在实际使用中需要实时构建数据库用于后续查找回环。
构建数据库采集到的每张图片提取全部feature所有feature通过vocabulary查询获取对应word所有word构成这张图片对应的Bowvector同时根据word的weight与单张图片中该word出现比例可以计算得到value这些信息将会构成一张反向索引表所有包含某个word的图片索引和一张正向索引表每张图片保护的word索引及alue这两张表实际上就是数据库用于后面提取历史keyframe对应的图片的Bowvector。
回环检测过程
1、构建自己的vocabulary并保存这一步一般可以省略可以直接使用作者提供的一份vocabulary file如果效果不佳可以考虑自己构建。2、运行自己的VIO算法每一个keyframe对应的图片加入到dataset实时构建dataset代码如下
inline DBow::EntryId DBow::Database::AddEntry(const vectorfloat features)
{DBow::BowVector v;m_voc-Transform(features, v, false);return _AddEntry(v);
}EntryId Database::_AddEntry(BowVector v)
{VocParams::ScoringType norm;if(VocParams::MustNormalize(m_voc-Scoring(), norm)){// vectors are stored normalized if neededv.Normalize(norm);}EntryId eid m_nentries;// update inverted fileBowVector::const_iterator it;for(it v.begin(); it ! v.end(); it){// eids are in ascending order in the indexm_index[it-id].push_back(IFEntry(eid, it-value));}m_nentries;return eid;
}3、每一个新的keyframe对应的图片加入dataset查询回环具体过程是将图片提取全部feature并通过vocabulary转换得到Bowvector通过dataset查询相关的历史keyframe计算当前keyframe与历史keyframe对应Bowvector的loss计算算法有很多种类如下 switch(info.Parameters-Scoring){case VocParams::L1_NORM:doQueryL1(v, ret, max_results, info.Parameters-ScaleScore);break;case VocParams::L2_NORM:doQueryL2(v, ret, max_results, info.Parameters-ScaleScore);break;case VocParams::CHI_SQUARE:doQueryChiSquare(v, ret, max_results, info.Parameters-ScaleScore);break;case VocParams::KL:doQueryKL(v, ret, max_results, info.Parameters-ScaleScore);break;case VocParams::BHATTACHARYYA:doQueryBhattacharyya(v, ret, max_results, info.Parameters-ScaleScore);break;case VocParams::DOT_PRODUCT:doQueryDotProduct(v, ret, max_results, info.Parameters-ScaleScore);break;}得到score对score进行排序获取candidates如下
void Database::doQueryL1(const BowVector v, QueryResults ret, const int max_results, const bool scale_score) const
{BowVector::const_iterator it;IFRow::const_iterator rit;QueryResults::iterator qit;for(it v.begin(); it ! v.end(); it){WordId wid it-id;WordValue qvalue it-value;const IFRow row m_index[wid];for(rit row.begin(); rit ! row.end(); rit){EntryId eid rit-id;WordValue dvalue rit-value;// scoring-dependent valuedouble value fabs(qvalue - dvalue) - fabs(qvalue) - fabs(dvalue);// check if this entry is already in the returning vectorqit find(ret.begin(), ret.end(), eid);if(qit ret.end()){// insertret.push_back(Result(eid, value));}else{// updateqit-Score value; }} // for each inverted row } // for each word in features // resulting scores are now in [-2 best .. 0 worst]// sort vector in ascending order// (scores are inverted now --the lower the better--)sort(ret.begin(), ret.end());// cut vectorif((int)ret.size() max_results) ret.resize(max_results);// complete score// ||v - w||_{L1} 2 Sum(|v_i - w_i| - |v_i| - |w_i|) // for all i | v_i ! 0 and w_i ! 0 // (Nister, 2006)if(scale_score){for(qit ret.begin(); qit ! ret.end(); qit) qit-Score -qit-Score/2.0;}else{for(qit ret.begin(); qit ! ret.end(); qit) qit-Score 2.0 qit-Score;}
}