• 第五篇 openvslam建图与优化模块梳理


    建图模块

    mapping_module在初始化系统的时候进行实例化,在构建实例的时候会实例化local_map_cleaner和local_bundle_adjuster。系统启动的时候会在另外一个线程中启动该模块。

    // src/openvslam/system.cc:78
    mapper_ = new mapping_module(map_db_, camera_->setup_type_ == camera::setup_type_t::Monocular);
    
    // src/openvslam/system.cc:123
    mapping_thread_ = std::unique_ptr<std::thread>(new std::thread(&openvslam::mapping_module::run, mapper_));
    

    对新增的关键帧进行建图

    // src/openvslam/mapping_module.cc:128
    void mapping_module::mapping_with_new_keyframe()
    
    对新增的关键帧进行建图mapping_with_new_keyframe
        取出队列中最早放入的关键帧
        设置原始关键帧ID
        将新关键帧保存入数据库store_new_keyframe
            计算当前关键帧的BoW特征向量
            获取当前关键帧的lm
            如果当前关键帧可以观测到该lm,将lm添加入local_map_cleaner的fresh_landmarks中
            否则
                添加lm的观测
                更新lm几何信息
                计算lm的描述子
            更新图连接update_connections
                获取图关键帧所有lm
                统计出共视关键帧以及共视lm数量情况,筛选出共视lm大于15的关键帧weight_covisibility_pairs
                寻找出共视lm数量最多的关键帧当做最近的共视关键帧
                图中添加连接add_connection
                对weight_covisibility_pairs进行降序排列,更新ordered_covisibilities_和ordered_weights_
                更新生成树。最近的共视关键帧设置为父树,当前关键帧为子树
            存储关键帧
        去除冗余的lm(remove_redundant_landmarks)
            移除的逻辑
            1. observed_ratio小于观测门限,需要从局部地图buffer和数据库中移除;
            2. 如果lm被添加之后一段时间内,被观测到的其他帧观测到的次数<=2,则认为时无效帧,需要从局部地图buffer和数据库中移除;
            3. 如果lm被添加之后一段时间内被多次观测到,则认为该lm有效,只从局部地图buffer中移除;
        依据当前关键帧和共视关键帧重新三角化lm(create_new_landmarks)
            获取当前关键帧权重高的共视关键帧
            逐个计算当前关键帧与共视关键帧之间的本质矩阵
            利用本质矩阵计算出两关键帧lm的匹配情况
            三角化匹配的lm,三角化成功的点将添加入库
        检测处理重复的lm(update_new_keyframe)
            获取两层共视关键帧
            融合重复的lm(fuse_landmark_duplication)
                获取当前帧的lm
                逐个共视关键帧去重(replace_duplication)
                    如果lm没有被共视关键帧观测到
                    将lm重投影至该共视关键帧,提取共视关键帧投影区域附近的特征点,如果相似度很高且重投影误差很小,
                    使用共视关键帧的lm点取代当前的lm,如果共视关键帧没有对应的lm则把当前lm添加到共视关键帧
                获取所有共视关键帧的lm集合再次进行去重(replace_duplication)
                    这里和上面去重输入参数是不一样的,这里的关键帧是当前关键帧,lm是共视关键帧lm集合
            更新当前帧lm几何信息和图连接
        进行局部地图BA(local_bundle_adjuster)
        祛除冗余的关键帧remove_redundant_keyframes
            获取当前关键帧的共视关键帧
            逐个共视关键帧计算冗余观测count_redundant_observations
                获取当前共视关键帧的lm
                逐个lm统计其共视关键帧数量,如果不小于3个就认为lm是冗余的num_redundant_obs++
                lm深度有效就认为是有效的lm,num_valid_obs++
            如果num_redundant_obs / num_valid_obs > 0.9,则认为该共视关键帧是冗余的,移除掉
    将新的关键帧发送给全局优化模块队列
    

    观测门限清理

    在跟踪模块优化局部地图optimize_current_frame_with_local_map时,首先会统计出当前帧可以被观测到的lm,会调用lm->increase_num_observable(),位姿优化后统计inlier的lm,调用lm->increase_num_observed(),因此num_observed_记录的是跟踪过程中真正有效的lm,num_observable_记录的是局部地图中可以被当前帧观测到的lm,如果num_observed_ / num_observable_的值很小的话,说明该lm对位姿评估没有太大意义,可以从局部地图buffer和数据库中清除掉。

    // src/openvslam/tracking_module.cc:340
    bool tracking_module::optimize_current_frame_with_local_map()
    

    全局优化模块

    和建图模块一样, 全局优化模块global_optimization_module在初始化系统的时候进行实例化,在构建实例的时候会实例化graph_optimizer、loop_detector和loop_bundle_adjuster。系统启动的时候会在另外一个线程中启动该模块。

    // src/openvslam/system.cc:80
    global_optimizer_ = new global_optimization_module(map_db_, bow_db_, bow_vocab_, camera_->setup_type_ != camera::setup_type_t::Monocular);
    
    // src/openvslam/system.cc:124
    global_optimization_thread_ = std::unique_ptr<std::thread>(new std::thread(&openvslam::global_optimization_module::run, global_optimizer_));
    
    

    run
        取出队列中最早放入的关键帧
        设置标记保证在回环检测和校正期间关键帧不被擦除
        将关键帧传入回环检测模块
        检测回环候选detect_loop_candidates
            回环检测功能被禁用或者刚刚被校正过,则不需要检测回环候选,直接将关键帧添加到bow_db
            1. 通过查询BoW数据库来搜索循环候选者
                在查询之前,计算当前关键帧和每个共视关键帧之间的BoW相似性的最小分数
                获取回环候选acquire_loop_candidates
                    获取与当前关键帧相连的关键帧集合(通过graph_node)
                    统计当前关键帧和其他关键帧共享单词数量情况
                    将最大共享单词数量*0.8作为最小共享单词门限
                    计算共享单词数满足条件的候选关键帧于当前关键帧的bow得分
                    挑选出不大于最小分数候选关键帧对儿score_keyfrm_pairs
                    计算每个候选关键帧(score_keyfrm_pairs)邻域的得分并取总和best_total_score
                    大于best_total_score*0.75才为有效的候选帧
                没有回环候选帧将当前关键帧添加到BoW database
            2. 寻找连续关键帧集合find_continuously_detected_keyframe_sets
                逐个查看回环候选关键帧
                    获取相连的关键帧集合
                    检测与之前连续关键帧集合是否相连,如果相连,添加入当前连续关键帧集合
            3. 将连接数大于2的关键帧放入回环候选
            4. 保存当前连续关键帧集合以便下次使用
        如果当前关键没有找到回环候选,那么当前帧是可以被删除的
        验证回环并且从中选出一个validate_candidates
            使用线性和非线性的方式评估当前关键帧和候选关键帧的sim3,挑选出回环候选帧
        校正回环correct_loop
            获取当前关键帧的共视关键帧
            获取回环校正前的共视关键帧的Sim3s_nw
            计算回环校正后的共视关键帧的Sim3s_nw
            校正共视关键帧中的lm的位置信息
            校正共视关键帧的位姿信息
            处理回环融合带来的重复lm(replace_duplicated_landmarks)
                用回环候选关键中的lm替换当前帧中的lm
                使用match::fuse检测重复的关键点
            获取新的连接关系,进行图优化sim3
                优化的变量只有关键帧位姿,优化完成后使用优化的结果调整landmark
            添加回环边
            最后进行loop BA
    
    

    问题

    1. 搞清楚线性和非线性sim3;
  • 相关阅读:
    lua协程一则报错解决“attempt to yield across metamethod/C-call boundary”
    web server && web framework角色区分
    throttle在程序中的作用
    如何将SVN patch的修改做成old&new文件
    lua 环境揭秘
    lua module package.seeall选项
    lua module环境探秘
    lua OOP实现对象的链式调用
    项目管理(一)任务分配
    项目管理(三)展望
  • 原文地址:https://www.cnblogs.com/hardjet/p/11564400.html
Copyright © 2020-2023  润新知