第十一章pose_graph_g2o_SE3

先贴一下cmakelists:

cmake_minimum_required( VERSION 2.8 )
project( pose_graph )

set( CMAKE_BUILD_TYPE "Release" )
set( CMAKE_CXX_FLAGS "-std=c++11 -O3" )

list( APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake_modules )

# Eigen
include_directories( "/usr/include/eigen3" )

# sophus 
#find_package( Sophus REQUIRED )
#include_directories( ${Sophus_INCLUDE_DIRS} )

# g2o 
find_package( G2O REQUIRED )
include_directories( ${G2O_INCLUDE_DIRS} )

find_package( Cholmod REQUIRED )
include_directories( ${CHOLMOD_INCLUDE_DIR} )

# gtsam 
#find_package( GTSAMCMakeTools )
#find_package( GTSAM REQUIRED )
#include_directories( ${GTSAM_INCLUDE_DIR} )


# Ceres 
find_package( Ceres REQUIRED )
include_directories( ${CERES_INCLUDE_DIRS} )

add_executable( pose_graph_g2o_SE3 pose_graph_g2o_SE3.cpp )
target_link_libraries( pose_graph_g2o_SE3
    g2o_core g2o_stuff g2o_types_slam3d ${CHOLMOD_LIBRARIES}
)

add_executable( pose_graph_g2o_lie pose_graph_g2o_lie_algebra.cpp )
target_link_libraries( pose_graph_g2o_lie
    g2o_core g2o_stuff 
    ${CHOLMOD_LIBRARIES}
    ${Sophus_LIBRARIES}
)

add_executable( pose_graph_gtsam pose_graph_gtsam.cpp )
target_link_libraries( pose_graph_gtsam
    ${CHOLMOD_LIBRARIES} gtsam
)

由于sophus和gtsam没有安装,所以cmakelists里面注释掉了。这俩主要是后面同样功能的sophus和gtsam方法用的。

程序:

#include <iostream>
#include <fstream>
#include <string>

#include <g2o/types/slam3d/types_slam3d.h>
#include <g2o/core/block_solver.h>
#include <g2o/core/optimization_algorithm_levenberg.h>
#include <g2o/core/optimization_algorithm_gauss_newton.h>
#include <g2o/solvers/dense/linear_solver_dense.h>
#include <g2o/solvers/cholmod/linear_solver_cholmod.h>
using namespace std;

/************************************************
 * 本程序演示如何用g2o solver进行位姿图优化
 * sphere.g2o是人工生成的一个Pose graph,我们来优化它。
 * 尽管可以直接通过load函数读取整个图,但我们还是自己来实现读取代码,以期获得更深刻的理解
 * 这里使用g2o/types/slam3d/中的SE3表示位姿,它实质上是四元数而非李代数.
 * **********************************************/

int main( int argc, char** argv )
{
    //判断命令行个数,这里就一个,就是待优化的位姿数据,也就是pose_graph_g2o_SE3 sphere.g2o文件
    if ( argc != 2 )
    {
        cout<<"Usage: pose_graph_g2o_SE3 sphere.g2o"<<endl;
        return 1;
    }
    //打开文件,同样有防呆,打开失败报警
    ifstream fin( argv[1] );
    if ( !fin )
    {
        cout<<"file "<<argv[1]<<" does not exist."<<endl;
        return 1;
    }

    //第一步:定义矩阵块求解器维度
    typedef g2o::BlockSolver<g2o::BlockSolverTraits<6,6>> Block;  // 6x6 BlockSolver
    //第二步:定义矩阵块求解器需要的线性方程求解器
    Block::LinearSolverType* linearSolver = new g2o::LinearSolverCholmod<Block::PoseMatrixType>(); // 线性方程求解器
    //第三步:用线性方程求解器构造块求解器
    Block* solver_ptr = new Block( linearSolver );      // 矩阵块求解器
    //第四步:用块求解器构造下降方法
    g2o::OptimizationAlgorithmLevenberg* solver = new g2o::OptimizationAlgorithmLevenberg( solver_ptr );
    //第五步:构造优化器,将下降方法传入设置。
    g2o::SparseOptimizer optimizer;     // 图模型
    optimizer.setAlgorithm( solver );   // 设置求解器

    int vertexCnt = 0, edgeCnt = 0; // 顶点和边的数量

    //总循环读取,用文件结尾标志控制。
    while ( !fin.eof() )
    {
        string name;
        fin>>name;
        //按行读取,判断行开头是顶点还是边,依次读入并设置ID,添加进优化器中。
        if ( name == "VERTEX_SE3:QUAT" )
        {
            // SE3 顶点
            g2o::VertexSE3* v = new g2o::VertexSE3();
            int index = 0;
            fin>>index;
            v->setId( index );
            v->read(fin);
            optimizer.addVertex(v);
            vertexCnt++;
            if ( index==0 )
                v->setFixed(true);
        }
        else if ( name=="EDGE_SE3:QUAT" )
        {
            // SE3-SE3 边
            g2o::EdgeSE3* e = new g2o::EdgeSE3();
            int idx1, idx2;     // 关联的两个顶点
            fin>>idx1>>idx2;
            e->setId( edgeCnt++ );
            e->setVertex( 0, optimizer.vertices()[idx1] );
            e->setVertex( 1, optimizer.vertices()[idx2] );
            e->read(fin);
            optimizer.addEdge(e);
        }
        //这句也是防呆吧,文件读取完关闭后,就直接break跳出了,问题来了,读到fin.eof()处,fin会自动关闭文件么?
        if ( !fin.is_open() ) break;
    }

    //输出信息:顶点个数、边个数
    cout<<"read total "<<vertexCnt<<" vertices, "<<edgeCnt<<" edges."<<endl;

    cout<<"prepare optimizing ..."<<endl;
    //输出详细优化信息
    optimizer.setVerbose(true);
    //开始优化
    optimizer.initializeOptimization();
    cout<<"calling optimizing ..."<<endl;
    //设置优化次数
    optimizer.optimize(30);

    cout<<"saving optimization results ..."<<endl;
    //将优化结果保存为.g2o文件
    optimizer.save("result.g2o");

    return 0;
}

版权声明:本文为robinhjwy原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。