热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

视觉SLAM十四讲读书编程笔记Chapter12回环检测

Chapter12回环检测词袋模型(BoW)字典字典的结构实践:创建字典相似度的计算理论部分实践:相似度计算相似性评分的处理关键帧的处理检测之后的验证词

Chapter12 回环检测

  • 词袋模型(BoW)
  • 字典
      • 字典的结构
      • 实践:创建字典
  • 相似度的计算
      • 理论部分
      • 实践:相似度计算
      • 相似性评分的处理
      • 关键帧的处理
      • 检测之后的验证


词袋模型(BoW)
  1. 确定BoW的单词,从而组成字典。
  2. 确定一副图像中出现了哪些在字典中定义的概念,从而把一副图像转换成了一个向量的描述。
  3. 比较上一步中描述的相似程度。

字典

字典的结构


  • 字典生成问题类似于一个聚类问题,聚类问题常用K-means方法:根据K-means,我们可以把已经提取的大量特征点聚类成一个含有k个单词的字典。
  • 字典的存储结构:
    使用一种k叉树来表达字典,假设我们有N个特征点,希望构建一个深度为d,每次分叉为k的树,那么做法如下:

  1. 在根节点,用K-means把所有样本聚成k类,这样得到了第一层。
  2. 对第一层的每个节点,把属于该节点的样本再聚成N类,得到下一层。
  3. 以此类推,最后得到叶子层。叶子层即所谓的Words
  4. 经过上述步骤,构建了一个k分支,深度为d的树,可以容纳kd个单词,在查找某个特定的单词时,只需将它与每个中间节点的聚类中心比较(一共d次),即可找到最后的单词,保证了对数级别的查找效率。

在这里插入图片描述

实践:创建字典


  1. 安装BoW库,下载地址:https://github.com/rmsalinas/DBow3
    它是一个cmake工程,编译并且安装它。
  2. 完整代码:
    feature_training.cpp

//2019.08.18
#include "DBoW3/DBoW3.h"
#include
#include
#include
#include
#include
#include using namespace cv;
using namespace std;int main(int argc,char **argv)
{//read the imagecout <<"reading images..." < images;for(int i&#61;0;i<10;i&#43;&#43;){string path &#61; "../data/" &#43; to_string(i&#43;1) &#43; ".png";images.push_back(imread(path));}//detect ORB featurescout <<"detecting ORB features..."< detector &#61; ORB::create();vector descriptors;for(Mat& image:images){vector keypoints;Mat descriptor;detector->detectAndCompute(image,Mat(),keypoints,descriptor);descriptors.push_back(descriptor);}//create vocabularycout<<"creating vocabulary..."<}

CMakeLists.txt

cmake_minimum_required( VERSION 2.8 )
project( loop_closure )set( CMAKE_BUILD_TYPE "Release" )
set( CMAKE_CXX_FLAGS "-std&#61;c&#43;&#43;11 -O3" )# opencv
find_package( OpenCV REQUIRED )
include_directories( ${OpenCV_INCLUDE_DIRS} )# dbow3
# dbow3 is a simple lib so I assume you installed it in default directory
set( DBoW3_INCLUDE_DIRS "/usr/local/include" )
set( DBoW3_LIBS "/usr/local/lib/libDBoW3.a" )add_executable( feature_training feature_training.cpp )
target_link_libraries( feature_training ${OpenCV_LIBS} ${DBoW3_LIBS} )

运行结果&#xff1a;
在这里插入图片描述

相似度的计算

理论部分

我们希望对单词的区分性或重要性加以评估&#xff0c;给它们不同的权值以起到更好的效果。在文本检索中&#xff0c;常用的一种做法称为TF-IDF(Term Frequency-Inverse Document Frequency)。
TF部分的思想是&#xff0c;某单词在一副图像中经常出现&#xff0c;它的区分度就高
IDF的思想是&#xff0c;某单词字典中出现的频率越低&#xff0c;则分类图像时区分度越高

在词袋模型中&#xff0c;在建立字典时可以考虑IDF部分。我们统计某个叶子节点wi中的特征数量相对于所有特征数量的比例作为IDF部分。假设所有的特征数量为n&#xff0c;wi中的特征数量为ni,那么该单词的IDF为&#xff1a;IDFi&#61;log(n/ni)
用来描述一个单词的特征点数量越少&#xff0c;说明这个单词越纯净&#xff0c;区分度也越好。

另一方面&#xff0c;TF部分则是指某个特征在单幅图像中出现的频率。假设图像A中单词wi出现了ni次&#xff0c;而一共出现的单词次数为n&#xff0c;那么TF为&#xff1a;TFi&#61;ni/n
在一幅图像中&#xff0c;某个单词出现的次数相比于它在所有图像中出现的次数占比越大&#xff0c;那么这个单词区分度越高。

某一个单词的权重定义为TF与IDF之积&#xff1a;
etai &#61; TFi×IDFi
考虑权重之后&#xff0c;对于某幅图像A&#xff0c;它的特征点可对应到许多个单词&#xff0c;组成它的Bag-of-Words:
A &#61; {(w1,etai),(w2,etai),…,(wN,etaN)} &#61; vA
由于相似的特征可能落到同一个类中&#xff0c;因此实际的**vA中会存在大量的零。这个向量vA**是一个稀疏的向量&#xff0c;它的非零部分指示了图像A中含有哪些单词&#xff0c;而这些部分的值为TF-IDF的值。

给定vA&#xff0c;vB&#xff0c;用L1范数计算它们的差异&#xff1a;

在这里插入图片描述

实践&#xff1a;相似度计算

loop_closure.cpp

//2019.08.18
#include "DBoW3/DBoW3.h"
#include
#include
#include
#include
#include
#include using namespace cv;
using namespace std;int main(int argc,char **argv)
{//read the images and databasecout <<"reading database"< images;for(int i&#61;0;i<10;i&#43;&#43;){string path &#61; "../data/" &#43; to_string(i&#43;1) &#43; ".png";images.push_back(imread(path));}//NOTE: in this case we are comparing images with a vocabulary generated by themselves, this may leed to overfitting.//detect ORB featurescout <<"detecting ORB features..."< detector &#61; ORB::create();vector descriptors;for(Mat& image:images){vector keypoints;Mat descriptor;detector->detectAndCompute(image,Mat(),keypoints,descriptor);descriptors.push_back(descriptor);}//we can compare the images directly or we can compare one image to a database//imagescout<<"comparing images with images"<}

CMakeLists.txt

cmake_minimum_required( VERSION 2.8 )
project( loop_closure )set( CMAKE_BUILD_TYPE "Release" )
set( CMAKE_CXX_FLAGS "-std&#61;c&#43;&#43;11 -O3" )# opencv
find_package( OpenCV REQUIRED )
include_directories( ${OpenCV_INCLUDE_DIRS} )# dbow3
# dbow3 is a simple lib so I assume you installed it in default directory
set( DBoW3_INCLUDE_DIRS "/usr/local/include" )
set( DBoW3_LIBS "/usr/local/lib/libDBoW3.a" )add_executable( loop_closure loop_closure.cpp )
target_link_libraries( loop_closure ${OpenCV_LIBS} ${DBoW3_LIBS} )

运行结果&#xff1a;
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

相似性评分的处理

绝对相似性评分鲁棒性不是很好&#xff0c;我们取一个先验相似度s(vt,vt-deltat),它表示某时刻关键帧图像与上一时刻的关键帧的相似性。然后&#xff0c;其他的分值都根据这个值进行归一化&#xff1a;
在这里插入图片描述

如果当前帧与之前的某关键帧的相似度超过当前帧与上一个关键帧相似度的3倍&#xff0c;就认为可能存在回环。

关键帧的处理

如果关键帧选得太近&#xff0c;那么将导致两个关键帧之间的相似性过高&#xff0c;相比之下不容易检测出历史数据中的回环。比如&#xff0c;检测结果经常是第n帧和第n-2帧&#xff0c;第n-3帧最为相似&#xff0c;这种结果似乎太平凡了&#xff0c;意义不大。从实践来说&#xff0c;用于回环检测的帧最好是稀疏一些&#xff0c;彼此之间不太相同&#xff0c;又能涵盖整个环境。
另一方面&#xff0c;如果成功检测到了回环&#xff0c;比如说出现在第1帧和第n帧。那么很可能第n&#43;1帧、第n&#43;2帧都会和第1帧之间构成回环。但是&#xff0c;确认第1帧和第n帧之间存在回环对轨迹优化是有帮助的&#xff0c;而再接下去的第n&#43;1帧、第n&#43;2帧都会和第1帧构成回环产生的帮助就没那么大了。所以&#xff0c;我们会把"相近"的回环聚成一类&#xff0c;使算法不要反复地检测同一类的回环。

检测之后的验证

词袋的回环检测算法完全依赖于外观而没有利用任何的几何信息&#xff0c;这导致外观相似的图像容易被当成回环。并且由于词袋不在乎单词顺序&#xff0c;只在意单词有无的表达方式&#xff0c;更容易引发感知偏差。所以&#xff0c;在回环检测之后&#xff0c;我们通常还会有一个验证步骤。
验证的方法有很多。其一是设立回环的缓存机制&#xff0c;认为单次检测到的回环并不足以构成良好的约束&#xff0c;而在一段时间中一直检测到的回环&#xff0c;才认为是正确的回环。这可以看成时间一致性检测
另一方法是在空间上的一致性检测&#xff0c;即对回环检测到的两个帧进行特征匹配&#xff0c;估计相机的运动。然后&#xff0c;再把运动放到之前的位姿图中&#xff0c;检查与之前的估计是否有很大的出入。总之&#xff0c;验证部分通常是必须的&#xff0c;但如何实现却是见仁见智的问题。


推荐阅读
  • 李逍遥寻找仙药的迷阵之旅
    本文讲述了少年李逍遥为了救治婶婶的病情,前往仙灵岛寻找仙药的故事。他需要穿越一个由M×N个方格组成的迷阵,有些方格内有怪物,有些方格是安全的。李逍遥需要避开有怪物的方格,并经过最少的方格,找到仙药。在寻找的过程中,他还会遇到神秘人物。本文提供了一个迷阵样例及李逍遥找到仙药的路线。 ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • 本文介绍了Codeforces Round #321 (Div. 2)比赛中的问题Kefa and Dishes,通过状压和spfa算法解决了这个问题。给定一个有向图,求在不超过m步的情况下,能获得的最大权值和。点不能重复走。文章详细介绍了问题的题意、解题思路和代码实现。 ... [详细]
  • STL迭代器的种类及其功能介绍
    本文介绍了标准模板库(STL)定义的五种迭代器的种类和功能。通过图表展示了这几种迭代器之间的关系,并详细描述了各个迭代器的功能和使用方法。其中,输入迭代器用于从容器中读取元素,输出迭代器用于向容器中写入元素,正向迭代器是输入迭代器和输出迭代器的组合。本文的目的是帮助读者更好地理解STL迭代器的使用方法和特点。 ... [详细]
  • 本文介绍了在开发Android新闻App时,搭建本地服务器的步骤。通过使用XAMPP软件,可以一键式搭建起开发环境,包括Apache、MySQL、PHP、PERL。在本地服务器上新建数据库和表,并设置相应的属性。最后,给出了创建new表的SQL语句。这个教程适合初学者参考。 ... [详细]
  • SpringBoot uri统一权限管理的实现方法及步骤详解
    本文详细介绍了SpringBoot中实现uri统一权限管理的方法,包括表结构定义、自动统计URI并自动删除脏数据、程序启动加载等步骤。通过该方法可以提高系统的安全性,实现对系统任意接口的权限拦截验证。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • IhaveconfiguredanactionforaremotenotificationwhenitarrivestomyiOsapp.Iwanttwodiff ... [详细]
  • 本文介绍了Redis的基础数据结构string的应用场景,并以面试的形式进行问答讲解,帮助读者更好地理解和应用Redis。同时,描述了一位面试者的心理状态和面试官的行为。 ... [详细]
  • 原文地址:https:www.cnblogs.combaoyipSpringBoot_YML.html1.在springboot中,有两种配置文件,一种 ... [详细]
  • 本文介绍了如何在给定的有序字符序列中插入新字符,并保持序列的有序性。通过示例代码演示了插入过程,以及插入后的字符序列。 ... [详细]
  • 本文介绍了为什么要使用多进程处理TCP服务端,多进程的好处包括可靠性高和处理大量数据时速度快。然而,多进程不能共享进程空间,因此有一些变量不能共享。文章还提供了使用多进程实现TCP服务端的代码,并对代码进行了详细注释。 ... [详细]
  • C++字符字符串处理及字符集编码方案
    本文介绍了C++中字符字符串处理的问题,并详细解释了字符集编码方案,包括UNICODE、Windows apps采用的UTF-16编码、ASCII、SBCS和DBCS编码方案。同时说明了ANSI C标准和Windows中的字符/字符串数据类型实现。文章还提到了在编译时需要定义UNICODE宏以支持unicode编码,否则将使用windows code page编译。最后,给出了相关的头文件和数据类型定义。 ... [详细]
  • Ihaveaworkfolderdirectory.我有一个工作文件夹目录。holderDir.glob(*)>holder[ProjectOne, ... [详细]
author-avatar
许晓慧
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有