DBOW作为一种视觉回环技术被广泛应用在各类VSLAM框架中,之前的经验主要集中在使用和抽象理解层面,近期花了一些时间仔细阅读了相关论文和源码,这里做一些记录。
通过预先训练得到的词汇库,以树状数据结构保存,便于后续查询,如下图黄色部分:

上图中的蓝色部分,在实际使用中,需要实时构建数据库,用于后续查找回环。
inline DBow::EntryId DBow::Database::AddEntry(const vector<float>& 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 needed
v.Normalize(norm);
}
EntryId eid = m_nentries;
// update inverted file
BowVector::const_iterator it;
for(it = v.begin(); it != v.end(); it++){
// eids are in ascending order in the index
m_index[it->id].push_back(IFEntry(eid, it->value));
}
m_nentries++;
return eid;
}
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 value
double value = fabs(qvalue - dvalue) - fabs(qvalue) - fabs(dvalue);
// check if this entry is already in the returning vector
qit = find(ret.begin(), ret.end(), eid);
if(qit == ret.end()){
// insert
ret.push_back(Result(eid, value));
}else{
// update
qit->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 vector
if((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;
}
}