DBoW2算法
来源:互联网 发布:阿里云学生库存不足 编辑:程序博客网 时间:2024/05/29 10:03
DBoW2是一种高效的回环检测算法,DBow2算法的全称为Bags of binary words for fast place recognition in image sequence,使用的特征检测算法为Fast,描述子为BRIEF描述子,是一种离线方法。
算法流程
Bag of Words字典建立方法(最终得到的就是每一层的不同类的median,每一个叶子节点对应的就是一个词汇)建树流程
权重设置
权重设置用的是idf,意思是词汇在训练过程中出现的频率越高,区分度越低,因此权重越低
idf=logNni
每一个节点包含
struct Node{ //在所有节点中的标号 NodeId id; //该节点的权重,该权重为 //训练的过程中设置的,在得到了树之后, //所有的描述子过一遍树,得到每一个单词出现 //的次数,除以总的描述子数目 WorldValue weight; //描述符,为每一类的均值(对于brief描述子,则要对均值进行二值化) TDescriptor descriptor; //如果有叶节点,则有词汇的ID WordID word_id;}
上面的方法是分层聚类的,每一次聚类得到的多个节点,都有median v表示该类,可以用来判断新的词汇是否属于该类。最终建立的树包括W个叶节点,也就是W个视觉词汇,词汇也用median表示。
http://www.cnblogs.com/jian-li/p/5664559.html
视觉词典
DBoW2库采用树状结构存储词袋,搜索复杂度在log(N)。每个叶节点被赋予一个权重,默认为TF-IDF。
TF-IDF主要思想是:如果某个词或短语在一片文章中出现的频率TF高,并且在其他文章中很少出现,则认为此词或者短语具有很好的类别区分能力,适合用来分类.TF-IDF实际上是TF*IDF,TF代表词频(Term Frequency),表示词条在文档d中的出现频率.IDF代表逆向文件频率(Inverse Document Frequency)。如果包含词条t的文档越少,IDF越大,表明词条t具有很好的类别区分能力。
第k个叶节点的TF和IDF分别定义为
IDFk=lognumber of all imagesnumber of images reach k−th leaf node
TFk=lognumber of features locates in leaf node knumber of all features
视觉词典可以通过离线训练大量数据得到。训练中只计算和保存单词的IDF值,即单词在众多图像中的区分度。TF则是从实际图像中计算得到各个单词的频率。单词的TF越高,说明单词在这幅图像中出现的越多;单词的IDF越高,说明单词本身具有高区分度。二者结合起来,即可得到这幅图像的BoW描述。
template<class TDescriptor, class F>void TemplatedVocabulary<TDescriptor, F>::create( const std::vector<std::vector<TDescriptor> > &training_features, // 图像特征集合 int k, // 每层的类的个数 int L, // 树的层数 WeightingType weighting, //权重类型,默认为TF-IDF ScoringType scoring) // 得分的类型,默认为L1-norm { m_nodes.clear(); m_words.clear(); //节点数 = Sum_(i=0..L) (k^i) int expected_nodes = (int)((pow((double)m_k,(double)m_L + 1) - 1) / (m_k - 1)); m_nodes.reserve(expected_nodes); //将所有特征描述集合到一个vector std::vector<pDescriptor> features; getFeature(training_features, features); //生成根节点 m_nodes.push_back(Node(0)); //root //k-means++ (内有递归) HKmeansStep(0, features, 1); //建立一个只有叶节点的序列m_words createWords(); //为每一个叶节点生成权重,此处计算IDF部分,如果不用IDF,则为1 setNodeWeights(training_features) } /*k-means++过程*/ template<class TDescriptor, class F> void TemplatedVocabulary<TDescriptor, F>::HKmeansStep( NodeId parent_id, // 父节点ID const std::vector<pDescriptor> &descriptor, // 该父节点对应的描述集合 int current_level // 当前层数) { if(descriptors.empty()) return; //用来储存子节点的特征描述 std::vector<TDescriptor> clusters; //用来储存每一个子节点对应的特征描述在descriptor向量中的id std::vector<std::vector<unsigned int > groups; //groups[i] = {j1, j2, ...} // j1, j2 ... indices of descriptors associated to cluster 1 clusters.reserve(m_k); group.reserve(m_k); //如果特征描述个数小于m_k,直接分类 if((int)descriptors.size() <= m_k) { groups.resize(descriptors.size()); for(unsigned int i = 0; i < descriptors.size(); i++) { groups[i].push_back(i); clusters[i].push_back(*descriptors[i]); } } else { //k_means分类 bool first_time = true; bool goon = true; //用来检测迭代过程中前后两次分类结果是否一致,如果一致,分类结束 std::vector<int> last_association, current_association; //迭代过程 while(goon) { // 1. 分类 if(first_time) { //第一次分类,初始化分类 initiateClusters(descriptors, clusters); } else { //计算每一类的meanValue for(unsigned int c = 0; c < clusters.size(); c++) { std::vector<pDescriptor> cluster_descriptors; cluster_descriptors.reserve(groups[c].size()); //利用group,读取每一类对应的id std::vector<unsigned int>::const_iterator vit; for(vit = groups[c].begin(); vit != groups[c].end(); ++vit) { cluster_descriptors.push_back(descriptors[*vit]); } //计算meanValue F::meanValue(cluster_descriptors, clusters[c]); } } // 2. 利用1计算的中心重新分类 groups.clear(); groups.resize(clusters.size(), std::vector<unsigned int>()); current_association.resize(descriptors.size()); typename std::vector<pDescriptor>::const_iterator fit; //对每一个特征,计算它与k个中心特征的距离,标记距离最小的中心特征的id for(fit = descriptors.begin(); fit != descriptors.end(); ++fit) { double best_dist = F::distance(*(*fit)), clusters[0]); undigned int icluster = 0; for(unsigned int c = 1; c < clusters.size(); ++c) { double dist = F::distance(*(*fit), clusters[c]); if(dist < best_dist) { best_dist = dist; icluster = c; } } //记录分类信息 groups[icluster].push_back(fit - descriptors.begin()); current_association[fit - descriptors.begin()] = icluster; } //k-means++ ensures all the clusters has any feature associated with them //3 . 检测前后两次分类结果是否一致,如一致,分类结束 if(first_time) first_time = false; else { goon = false; for(unsigned int i = 0; i < current_association.size(); i++) { if(current_association[i] != last_association[i]) goon = true; break; } } if(goon) { last_association = current_association; } } //生成本层的节点,其特征描述为每一类的meanValue for(unsigned int i = 0; i < clusters.size(); ++i) { NodeId id = m_nodes.size(); m_nodes.push_back(Node(id)); m_nodes.back().descriptor = clusters[i]; m_nodes.back().parent = parent_id; m_nodes[parent_id].children.push_back(id); } // go on with the next level if(current_level < m_L) { // iterate again with the resulting clusters const std::vector<NodeId> &children_ids = m_nodes[parent_id].children; for(unsigned int i = 0; i < clusters.size(); ++i) { NodeId id = children_ids[i]; std::vector<pDescriptor> child_features; child_features.reserve(groups[i].size()); std::vector<unsigned int>::const_iterator vit; for(vit = groups[i].begin(); vit != groups[i].end(); ++vit) { child_features.push_back(descriptors[*vit]); } //进入下一层,继续分类 if(child_features.size() > 1) { HKmeansStep(id, child_features, current_level + 1); } } } }
- DBoW2算法
- DBoW2算法原理介绍
- DBoW2算法 精析
- DBoW2 回环检测/重定位 算法解析
- DBoW2 回环检测/重定位 算法解析
- DBoW2视觉词袋原理
- win10下配置DBoW2的问题
- DBoW2原理与代码分析(结合ORB_SLAM2)
- DBoW2在windows上的vs工程搭建方法
- 视觉slam闭环检测之-DBoW2 -视觉词袋构建
- 视觉slam闭环检测之-DBoW2 -视觉词袋构建
- 视觉slam闭环检测之-DBoW2 -视觉词袋构建
- 算法
- 算法
- 算法
- 算法
- 算法
- 算法
- 梯度检验与高级优化
- 算法基础复习-InsertionSort
- Android SDK上手指南:用户交互
- mtk 按键中断驱动
- Android 中 非对称(RSA)加密和对称(AES)加密
- DBoW2算法
- java存储机制(栈、堆、方法区详解)
- Docker+Git效率工作
- android camera拍摄文字识别
- linux杂记3
- RedHat 下如何安装gdb
- 求列表平衡点
- Android 中算法问题
- [转]imx6 uboot logo 更改