热门标签 | 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)替换当前关键帧以及共视关键帧和回环关键帧以及共视关键帧重复的地图点。

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

 



推荐阅读
  • 微软推出Windows Terminal Preview v0.10
    微软近期发布了Windows Terminal Preview v0.10,用户可以在微软商店或GitHub上获取这一更新。该版本在2月份发布的v0.9基础上,新增了鼠标输入和复制Pane等功能。 ... [详细]
  • malloc 是 C 语言中的一个标准库函数,全称为 memory allocation,即动态内存分配。它用于在程序运行时申请一块指定大小的连续内存区域,并返回该区域的起始地址。当无法预先确定内存的具体位置时,可以通过 malloc 动态分配内存。 ... [详细]
  • 本文详细介绍了Linux系统中用于管理IPC(Inter-Process Communication)资源的两个重要命令:ipcs和ipcrm。通过这些命令,用户可以查看和删除系统中的消息队列、共享内存和信号量。 ... [详细]
  • 本文详细介绍了如何在PHP中记录和管理行为日志,包括ThinkPHP框架中的日志记录方法、日志的用途、实现原理以及相关配置。 ... [详细]
  • 本文节选自《NLTK基础教程——用NLTK和Python库构建机器学习应用》一书的第1章第1.2节,作者Nitin Hardeniya。本文将带领读者快速了解Python的基础知识,为后续的机器学习应用打下坚实的基础。 ... [详细]
  • EST:西湖大学鞠峰组污水厂病原菌与土著反硝化细菌是多重抗生素耐药基因的活跃表达者...
    点击蓝字关注我们编译:祝新宇校稿:鞠峰、袁凌论文ID原名:PathogenicandIndigenousDenitrifyingBacte ... [详细]
  • 本文详细介绍了Java代码分层的基本概念和常见分层模式,特别是MVC模式。同时探讨了不同项目需求下的分层策略,帮助读者更好地理解和应用Java分层思想。 ... [详细]
  • 通过将常用的外部命令集成到VSCode中,可以提高开发效率。本文介绍如何在VSCode中配置和使用自定义的外部命令,从而简化命令执行过程。 ... [详细]
  • 浅析python实现布隆过滤器及Redis中的缓存穿透原理_python
    本文带你了解了位图的实现,布隆过滤器的原理及Python中的使用,以及布隆过滤器如何应对Redis中的缓存穿透,相信你对布隆过滤 ... [详细]
  • 网络爬虫的规范与限制
    本文探讨了网络爬虫引发的问题及其解决方案,重点介绍了Robots协议的作用和使用方法,旨在为网络爬虫的合理使用提供指导。 ... [详细]
  • 双指针法在链表问题中应用广泛,能够高效解决多种经典问题,如合并两个有序链表、合并多个有序链表、查找倒数第k个节点等。本文将详细介绍这些应用场景及其解决方案。 ... [详细]
  • 探讨Redis的最佳应用场景
    本文将深入探讨Redis在不同场景下的最佳应用,包括其优势和适用范围。 ... [详细]
  • Python 数据可视化实战指南
    本文详细介绍如何使用 Python 进行数据可视化,涵盖从环境搭建到具体实例的全过程。 ... [详细]
  • 本文详细介绍了如何解决DNS服务器配置转发无法解析的问题,包括编辑主配置文件和重启域名服务的具体步骤。 ... [详细]
  • 网站访问全流程解析
    本文详细介绍了从用户在浏览器中输入一个域名(如www.yy.com)到页面完全展示的整个过程,包括DNS解析、TCP连接、请求响应等多个步骤。 ... [详细]
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社区 版权所有