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

openvslam(33)文件结构全局优化模块(globaloptimizationmodule):回环检测、posegraph优化、globalBA优化

博客地址https:blog.csdn.netu011341856articledetails109491058 这篇博客主要介绍OpenVSLAM的全局优化模块(global_o

博客地址

https://blog.csdn.net/u011341856/article/details/109491058

 

这篇博客主要介绍OpenVSLAM的全局优化模块(global_optimization_module),该模块是单独运行在一个线程中的。

它主要执行的工作是:SLAM的回环检测,以及回环成功之后的回环矫正,还包括紧随着回环检测成功之后的pose graph优化和全局的BA优化。

 


1.全局优化模块入口

 类的定义

 

 

 测试样例

 

说是全局优化模块,其实也就是一个普通的类。对于类,第一步肯定就是实例化构造对象,全局优化模块的实例化过程是在system.cc代码中的system的构造函数处,对应的代码的如下:

global_optimizer_ = new global_optimization_module(map_db_, bow_db_, bow_vocab_,
camera_->setup_type_ != camera::setup_type_t::Monocular);

可见全局优化模块和其它模块共用的数据包括

map_db_(地图的数据库)、

bow_db_(词袋数据库)、

bow_vocab_(词袋模型),

最后一个参数来控制优化时是否优化尺度(scale),

对于单目由于存在尺度漂移,所以需要优化尺度。

至此,全局优化模块构造完成。

另外由于它需要在一个独立的线程中运行,所以还需要新建一个线程,将该对象中的代码运行在这个线程中。

新建线程的代码在system.cc文件中的system::startup()函数中,对应的代码如下:

global_optimization_thread_ = std::unique_ptr(new std::thread(&openvslam::global_optimization_module::run, global_optimizer_));

 注意std::thread运行对象中函数的用法!


2.全局优化模块线程在干啥?

经过简单地配置,全局优化线程就欢脱的跑起来了,现在就让我们来看看它都具体干了啥?首先祭出一张流程图:

 

 

 

全局优化线程是一个死循环,只要程序正常运行,它将不停地在做同样的重复性工作,好无聊啊!

(1)首先,先检查一下SLAM的状态,确保没有收到SLAM要暂停、停止或者重启的命令!

这里命令的发出主要是通过显示模块中在pangolin的窗口上的那几个按钮!

(2)从关键帧队列中(keyfrms_queue_),取出最前面的一帧关键帧。如果关键帧队列中啥东西都没有,那怎么办呢?哎,这一趟循环了个屁,重新循环吧!心累

keyfrms_queue_这个成员变量主要用来存储关键帧,用于回环检测。其中关键帧数据主要是来自建图模块(mapping_module)的输入,只要建图模块成功的生成了一个关键帧,那么就将关键帧放入这个队列。

(3)将队列中取出来的这一个关键帧,与地图数据集中的所有关键帧进行比较,找到和自己的相似的关键帧,将其作为备选的回环关键帧。

如果找到了(闭环了),那就继续往下执行,全局优化

没有找到的话(没有闭环),又是一个无用的循环,那就回到开始,重新下一次循环吧!

这一步对应的函数是loop_detector::detect_loop_candidates(),这是一个重要的函数,下面的内容单独讲解这个函数。

(4)检测到了一些和自己相似的回环候选帧之后,需要验证这些候选关键帧是不是确实是一个真正的回环。

如果经过验证这些候选回环关键帧中没有真正的回环帧,那么这次循环就结束了,重新循环!

这一步对应的函数loop_detector::validate_candidates(),它也是一个重要的函数,后面会专门介绍。

(5)经过验证之后,确实是一个成功的回环,那么就需要执行回环矫正!

这一步对应的函数global_optimization_module::correct_loop(),这个函数后面介绍!

以上步骤中,一共出现了三个很重要的函数:



  • loop_detector::detect_loop_candidates()

  • loop_detector::validate_candidates()

  • global_optimization_module::correct_loop()

 

接下来我们一个一个去学习


2.1 检测回环候选帧

 

首先来看第一个函数loop_detector::detect_loop_candidates(),它主要是用来进行回环候选帧的检测,经过它的检测之后,可以获得很多的回环候选帧,这些候选帧中也许有真正的回环帧,也许没有!让我们来看看它都做了啥?首先祭出它的流程图:

 

 

 

让我向你具体介绍它都做了啥吧!

(1)首先,检测是否开启回环检测功能,另外如果距离上一次回环检测成功还没有超过10个关键帧,那就先不要进行回环检测,不然的话太频繁了,也不符合实际情况!如果不满足这两个条件,那就退出这个函数!

你可以想象一下,刚做完回环检测,你又回到原地的情况应该还是比较少见的吧!

 

(2)根据共视关系计算回环检测的最小评分。可以想象一下,如果拿着当前帧到地图数据库中去找和我比较相似的,那怎么判断拿个和我算比较相似,那个算比较不相似呢?如果设置的阈值过高可能错过了回环,如果阈值过低可能会检测到很多候选帧。于是作者这里的策略是把当前帧的共视关键帧取出来,以此作为判断依据,将共视关键帧中和自己bow评分最低的那个得分最为评判回环候选帧的阈值。

这一步操作对应的函数是loop_detector::compute_min_score_in_covisibilities()。这一点你是可以想象的,既然是回环帧,那至少和我们看起来还是比较相似的,至于取用共视关键帧中的最低评分,我估计作者是做了大量的实验之后,得出来的一个经验做法!
(3)根据上一步计算出来的评分,去地图数据库进行查找,那些只要和当前帧相似评分大于这个最低阈值的关键帧,都将作为回环候选帧取出来。

(4)如果没有得到任何的回环候选帧,那么结束当前函数。

(5)将每一个回环候选帧以及这个候选帧对应的所有共视关键帧打包组成一个集合(类似于下图虚线框起来的那样),以备后用。注意,这里其实有一个连续性检测条件,也就是算法认为,如果确实是一个真正的回环,那么应该是可以连续被检测到的,不可能上次检测到,这一次检测不到了。

这个理解起来还是比较难的,我通过一张向你解释一下这个过程吧!

 

 

 

上图中的三角形和圆形都是关键帧,为了以示区分我把它画成关键帧加共视关键帧组合的形式(图中虚线框起来的那样)。红色的三角形是当前的关键帧,它经过回环候选帧检测之后,获得了上图所示的四个虚线框组成的组合。连续性检测认为,如果下一次再进行回环候选帧检测,检测出来的组合和上一次检测出来的组合没有交集,那么它们就都不是可能的候选回环帧。例如,上图是本次的回环候选帧检测结果,下一次检测得到的回环候选帧组合与当前检测结果没有相交(所谓的相交,就是虚线框中这样的组合之间是否有公共的关键帧),则这两次结果里都不存在回环候选帧。
你品,你细品! 

 

(6)如果打包的关键帧集合连续被观测到三次,也就是说当前观测组成的回环帧集合,下一次又被检测到,总共被检测到三次,那么这个回环候选关键帧很可能是真正的回环帧,将其记录下来。

注意,如果连续性检测某一次失败了,那么之前累计的连续性结果也都归零,重新开始新的连续性检测。

通过以上算法之后,可能会获得很多回环候选帧,下一步就需要进行验证到底是不是真的回环!

 


2.2 验证回环候选帧

经过检测现在已经获得了很多回环候选帧,loop_detector::validate_candidates()函数主要就是用来对回环候选帧中的关键帧做检验,找到其中真正的回环帧。它的原理主要是做几何校验,验证其是否满足投影关系。

废话不多说,首先祭出流程图:

 

 

(1)首先,对候选关键帧与当前关键帧进行Sim3变换的几何校验。找到满足投影关系的回环候选关键帧。这一步对应的函数是:loop_detector::select_loop_candidate_via_Sim3()它的主要算法过程如下:



  • 通过bow加速搜索,获得候选关键帧与当前关键帧的匹配特征点;

  • 如果匹配的特征点少于20个,则说明当前候选关键帧不是一个好的候选关键帧,结束当前循环,进行下一次循环;

  • 根据搜索出来的匹配特征点对,求解当前关键帧到候选关键帧的Sim3变换,内点数量小于20,则认为不是一个好的候选帧;

  • 通过计算出来的Sim3变换,将两个关键帧对应的地图点相互向对方关键帧投影,获得更多的匹配关系;

  • 对获得的匹配关系进行优化,获得更加准确的结果;

  • 如果最终得到的内点数量大于20个,则认为当前候选关键帧是一个真正的回环帧,否则进行下一次循环,对下一个候选帧执行上述步骤。

 

(2)对上一步找到的回环帧,取出它的所有共视关键帧,以及共视关键帧赌赢的地图点。
(3)将上一步获得的地图点,全部向当前关键帧进行投影,获得更多的匹配关系,然后再重新计算一次Sim3变换,如果最终的匹配点对数量大于40个,则又进一步印证了当前检测出来的回环帧确实是一个回环帧。

经过上面的回环帧验证之后,我们获得的回环帧,也确实是一个真正的、可靠的回环帧了,下面该要执行的就是通过这个回环帧去消除掉累计误差了!

 

2.3 进行回环矫正
回环矫正对应的函数是:global_optimization_module::correct_loop()。它其中有一些细节还是比较难的,你可能需要关注一下它是怎么处理那些重复的关键帧,以及重复的地图点,怎么构建一个pose graph优化!

废话不多说,继续祭出我亲手画的流程图:

 

 

 

 

(1)首先,将我们辛辛苦苦取得的回环帧取出来,它可是咱们的宝贝啊,千呼万唤才弄出来的。
(2)如果目前系统中还正有一个回环全局优化在执行,就关闭它。毕竟又出现了新的回环帧之后,前面的累计误差可以消除,在此之前的别的回环优化都是浪费。
(3)确保mapp_module模块已经暂停。
(4)更新一下当前关键帧的连接关系,包括共视关系、权重等等。
(5)将当前关键帧以及它的共视关键帧,通过之前就算出来的Sim3变换进行位姿修正,并且也要将地图点也修正到它本该在的地方。
(6)替换当前关键帧以及共视关键帧和回环关键帧以及共视关键帧重复的地图点。

 你可以想象一下,既然是回环成功了,那肯定说明相机回到了以前出现过的地方,那么它们必然看到一样的地图点,但是由于存在累计误差,同样的地图点却出现了不同的坐标,所以是不是应该需要删除这些重复的地图点呢?如果当前帧和回环帧有共同的地图点,用回环帧中的地图点替换当前帧的地图点。而对于

 



推荐阅读
  • 本文详细探讨了HTML表单中GET和POST请求的区别,包括它们的工作原理、数据传输方式、安全性及适用场景。同时,通过实例展示了如何在Servlet中处理这两种请求。 ... [详细]
  • 解决SVN图标显示异常问题的综合指南
    本文详细探讨了SVN图标无法正常显示的问题,并提供了多种有效的解决方案,涵盖不同环境下的具体操作步骤。通过本文,您将了解如何排查和修复这些常见的SVN图标显示故障。 ... [详细]
  • 深入解析Redis内存对象模型
    本文详细介绍了Redis内存对象模型的关键知识点,包括内存统计、内存分配、数据存储细节及优化策略。通过实际案例和专业分析,帮助读者全面理解Redis内存管理机制。 ... [详细]
  • 本文探讨了如何在iOS开发环境中,特别是在Xcode 6.1中,设置和应用自定义文本样式。我们将详细介绍实现方法,并提供一些实用的技巧。 ... [详细]
  • Python第三方库安装的多种途径及注意事项
    本文详细介绍了Python第三方库的几种常见安装方法,包括使用pip命令、集成开发环境(如Anaconda)以及手动文件安装,并提供了每种方法的具体操作步骤和适用场景。 ... [详细]
  • 反向投影技术主要用于在大型输入图像中定位特定的小型模板图像。通过直方图对比,它能够识别出最匹配的区域或点,从而确定模板图像在输入图像中的位置。 ... [详细]
  • 本文详细介绍了 iBatis.NET 中的 Iterate 元素,它用于遍历集合并重复生成每个项目的主体内容。通过该元素,可以实现类似于 foreach 的功能,尽管 iBatis.NET 并未直接提供 foreach 标签。 ... [详细]
  • 本文详细介绍Python编程的基础知识,涵盖从安装环境到编写简单程序的核心内容,并深入探讨网络编程的基本概念和实践。提供多种资源下载方式,帮助读者快速上手。 ... [详细]
  • 本文详细介绍了C语言的起源、发展及其标准化过程,涵盖了从早期的BCPL和B语言到现代C语言的演变,并探讨了其在操作系统和跨平台编程中的重要地位。 ... [详细]
  • 获取Jedis和Commons Pool JAR包的两种方法及详细步骤
    本文介绍如何通过网盘链接或官方网站获取Jedis和Commons Pool的JAR包,并提供详细的图文教程。同时,还附有导入JAR包到项目的相关建议。 ... [详细]
  • 云计算的优势与应用场景
    本文详细探讨了云计算为企业和个人带来的多种优势,包括成本节约、安全性提升、灵活性增强等。同时介绍了云计算的五大核心特点,并结合实际案例进行分析。 ... [详细]
  • 本文详细介绍了如何通过RPM包在Linux系统(如CentOS)上安装MySQL 5.6。涵盖了检查现有安装、下载和安装RPM包、配置MySQL以及设置远程访问和开机自启动等步骤。 ... [详细]
  • 本文探讨了使用C#在SQL Server和Access数据库中批量插入多条数据的性能差异。通过具体代码示例,详细分析了两种数据库的执行效率,并提供了优化建议。 ... [详细]
  • 方法:1 配置数据库basediros.path.abspath(os.path.dirname(__file__))  #获取当前文件的绝对路径appFlask(__name__ ... [详细]
  • 解决Anaconda安装TensorFlow时遇到的TensorBoard版本问题
    本文介绍了在使用Anaconda安装TensorFlow时遇到的“Could not find a version that satisfies the requirement tensorboard”错误,并提供详细的解决方案,包括创建虚拟环境和配置PyCharm项目。 ... [详细]
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社区 版权所有