ORB-SLAM optimizer

本文介绍视觉SLAM中局部BA的实现细节,包括如何选择并固定关键帧,以及通过投影误差和相似变换进行优化的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

很有针对性的相关参考链接:https://blog.csdn.net/hzwwpgmwy/article/details/79884070

学会去看模板参数

顶点一般就是位姿、路标点位置

边的话就是1、一般找投影2、找两帧间的相对变换sim3作为边

class  EdgeSE3ProjectXYZ: public  BaseBinaryEdge<2, Vector2d, VertexSBAPointXYZ, VertexSE3Expmap>//投影边的模板参数,第一个连的顶点是三维点VertexSBAPointXYZ(三维点),第二点是VertexSE3Expmap(位姿)

sim3的理解https://blog.csdn.net/ABC1225741797/article/details/108044343

 局部BA

https://blog.csdn.net/u010128736/article/details/53395936

局部BA:红圈内红框为优化量,pos1为约束量

优化共视图图内的关键帧的位姿、地图点,同时把能观测到这些地图点的关键帧作为约束量

约束项放入代价函数中,但值保持不变的操作在代价函数求取雅可比矩阵时有所体现,不会求代价函数关于pos1的雅可比矩阵

每个点在所有选出来的帧里面的投影误差

代码实现:

// Fixed Keyframes. Keyframes that see Local MapPoints but that are not Local Keyframes
    // 步骤4:得到能被局部MapPoints观测到,但不属于局部关键帧的关键帧,这些关键帧在局部BA优化时不优化
    list<KeyFrame*> lFixedCameras;
    for(list<MapPoint*>::iterator lit=lLocalMapPoints.begin(), lend=lLocalMapPoints.end(); lit!=lend; lit++)
    {
        map<KeyFrame*,size_t> observations = (*lit)->GetObservations();
        for(map<KeyFrame*,size_t>::iterator mit=observations.begin(), mend=observations.end(); mit!=mend; mit++)
        {
            KeyFrame* pKFi = mit->first;

            // pKFi->mnBALocalForKF!=pKF->mnId表示局部关键帧,
            // 其它的关键帧虽然能观测到,但不属于局部关键帧
            if(pKFi->mnBALocalForKF!=pKF->mnId && pKFi->mnBAFixedForKF!=pKF->mnId)
            {                
                pKFi->mnBAFixedForKF=pKF->mnId;// 防止重复添加
                if(!pKFi->isBad())
                    lFixedCameras.push_back(pKFi);
            }
        }

 

    // Set Fixed KeyFrame vertices
    // 步骤7:添加顶点:Pose of Fixed KeyFrame,注意这里调用了vSE3->setFixed(true)。
    for(list<KeyFrame*>::iterator lit=lFixedCameras.begin(), lend=lFixedCameras.end(); lit!=lend; lit++)
    {
        KeyFrame* pKFi = *lit;
        g2o::VertexSE3Expmap * vSE3 = new g2o::VertexSE3Expmap();
        vSE3->setEstimate(Converter::toSE3Quat(pKFi->GetPose()));
        vSE3->setId(pKFi->mnId);
        vSE3->setFixed(true);
        optimizer.addVertex(vSE3);
        if(pKFi->mnId>maxKFid)
            maxKFid=pKFi->mnId;
    }

代码中:optimizer:InfoMatrix是高斯型误差指数上p=error'*Q*error中的Q

essential-graph的优化 

 

量测量是两帧之间的相似变换sim3,也就是加入优化器中的e->setMeasurement,这个类模板内部会根据添加的顶点,定义的误差类型g2o::EdgeSim3* ,内部计算如上图中的公示(9)这个最小二乘的形式,进行优化

const g2o::Sim3 Sjw = vScw[nIDj];
            // 得到两个pose间的Sim3变换
const g2o::Sim3 Sji = Sjw * Swi;

g2o::EdgeSim3* e = new g2o::EdgeSim3();
e->setVertex(1, dynamic_cast<g2o::OptimizableGraph::Vertex*>(optimizer.vertex(nIDj)));
e->setVertex(0, dynamic_cast<g2o::OptimizableGraph::Vertex*>(optimizer.vertex(nIDi)));
            // 根据两个Pose顶点的位姿算出相对位姿作为边,那还存在误差?优化有用?因为闭环MapPoints调整新形成的边不优化?(wubo???)
e->setMeasurement(Sji);
e->information() = matLambda;
optimizer.addEdge(e);

 

### ORB-SLAMOptimizer.cc 文件的代码解析 OptimizerORB-SLAM 系统中的一个重要模块,负责优化相机姿态以及地图点的位置。它通过最小化重投影误差来实现这一目标。以下是 `Optimizer.cc` 的主要功能及其代码结构分析: #### 1. **全局束调整 (Global Bundle Adjustment)** 全局束调整用于优化所有帧的姿态和地图点位置。其核心函数为 `OptimizeGlobalBundleAdjustment()`。 ```cpp bool Optimizer::GlobalBundleAdjustment( g2o::SparseOptimizer &optimizer, unsigned long max_iterations) { optimizer.setVerbose(false); optimizer.initializeOptimization(); optimizer.computeInitialError(); // 设置最大迭代次数 optimizer.optimize(max_iterations); return true; } ``` 此部分实现了基于图优化框架 G2O 的全局 BA 过程[^1]。G2O 提供了一种灵活的方式来构建稀疏矩阵并执行非线性优化。上述代码片段展示了如何初始化优化器、设置参数,并调用优化方法。 --- #### 2. **局部束调整 (Local Bundle Adjustment)** 局部束调整仅针对当前关键帧附近的若干帧和它们观测到的地图点进行优化。这可以显著减少计算量,同时保持较高的精度。 ```cpp void Optimizer::LocalBundleAdjustment(KeyFrame *pKF, Map* pMap) { g2o::SparseOptimizer optimizer; // 添加顶点(Vertex) for(auto it = vSE3.begin(), itend=vSE3.end(); it!=itend; ++it){ VertexPose * VPose= new VertexPose(); VPose->setEstimate((*it).second); optimizer.addVertex(VPose); } // 添加边(Edge) for(const auto& obs : observations){ EdgeSE3ProjectXYZ* e = new EdgeSE3ProjectXYZ(); e->setMeasurement(obs.measurement); e->information() = Eigen::Matrix<double,2,2>::Identity(); // 将顶点与边连接起来 e->vertices()[0] = dynamic_cast<g2o::Vertex*>(optimizer.vertex(obs.frame_id)); e->vertices()[1] = dynamic_cast<g2o::Vertex*>(optimizer.vertex(obs.point_id)); optimizer.addEdge(e); } optimizer.setVerbose(false); optimizer.initializeOptimization(); optimizer.optimize(5); // 局部BA通常只需要少量迭代即可收敛 } ``` 该段代码描述了如何向 G2O 图模型中添加顶点(表示位姿或三维点)和边(约束关系)。随后调用了优化过程[^2]。 --- #### 3. **Pose Graph Optimization** 姿势图优化主要用于闭环检测后的全局一致性校正。它的作用是消除累积漂移。 ```cpp void Optimizer::OptimizePoseGraph(Map* pMap) { g2o::SparseOptimizer pose_graph_optimizer; // 构建节点 for(auto kf_it = keyframes.begin(); kf_it != keyframes.end(); ++kf_it){ KeyFrame* kf = (*kf_it).first; PoseGraphNode* node = new PoseGraphNode(kf->GetCameraPose()); pose_graph_optimizer.addNode(node); } // 构建边 for(auto loop_edge : loop_edges){ LoopEdge* edge = new LoopEdge(loop_edge.first, loop_edge.second, loop_edge.info_matrix); pose_graph_optimizer.addEdge(edge); } pose_graph_optimizer.setVerbose(true); pose_graph_optimizer.initializeOptimization(); pose_graph_optimizer.optimize(10); // 姿势图优化可能需要更多次迭代以达到稳定状态 } ``` 这段代码说明了如何利用 G2O 实现姿势图优化。其中涉及的关键概念包括关键帧之间的相对变换关系以及回环闭合带来的额外约束条件[^3]。 --- #### 4. **其他辅助函数** 除了以上提到的核心功能外,`Optimizer.cc` 还包含了多个辅助函数,例如: - 计算雅可比矩阵; - 初始化变量估计值; - 处理异常情况下的恢复机制等。 这些细节共同构成了一个高效稳定的 SLAM 系统优化引擎。 --- ### 总结 通过对 `Optimizer.cc` 的深入剖析可以看出,它是 ORB-SLAM 系列算法的重要组成部分之一,在提升系统鲁棒性和准确性方面发挥了不可替代的作用。无论是局部还是全局范围内的优化操作都依赖于强大的非线性求解工具——G2O 库的支持[^4]。 ```python # 示例 Python 调用伪代码 import subprocess def run_orb_slam(): command = "./Examples/RGB-D/rgbd_tum Vocabulary/ORBvoc.txt Examples/RGB-D/TUM1.yaml PATH_TO_SEQUENCE_FOLDER ASSOCIATIONS_FILE" result = subprocess.run(command.split()) return result.returncode == 0 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值