首页 > 其他分享 >g2o函数

g2o函数

时间:2022-10-06 21:44:05浏览次数:48  
标签:abc 函数 double G2O g2o include sigma

g2o简介

g2o(General Graphical Optimization),是一个在SLAM领域广为使用的优化库。基于图优化理论。

图优化理论

把优化问题表现成图的一种方式。一个图由若干个顶点和连接着这些顶点的边组成。
用顶点表示优化变量,用边表示误差项。对于一个非线性最小二乘问题,我们可以为其构建一个图。

主要步骤

  • 定义顶点和边的类型
  • 构建图
  • 选择优化算法
  • 调用g2o进行优化,返回结果

使用g2o拟合曲线

#include<iostream>
#include<g2o/core/g2o_core_api.h>
#include<g2o/core/base_vertex.h>
#include<g2o/core/base_unary_edge.h>
#include<g2o/core/block_solver.h>
#include<g2o/core/optimization_algorithm_levenberg.h>
#include<g2o/core/optimization_algorithm_gauss_newton.h>
#include<g2o/core/optimization_algorithm_dogleg.h>
#include<g2o/solvers/dense/linear_solver_dense.h>
#include<Eigen/Core>
#include<opencv2/core/core.hpp>
#include<cmath>
#include<chrono>

using namespace std;

//曲线模型的顶点,模板参数:优化变量维度和数据类型
class CurveFittingVertex:public g2o::BaseVertex<3,Eigen::Vector3d>{
public:
    EIGEN_MAKE_ALIGNED_OPERATOR_NEW
    
    //重置
    virtual void setToOriginImpl()override{
        _estimate<<0,0,0;
    }
    
    //更新
    virtual void oplusImpl(const double *update)override{
        _estimate+=Eigen::Vector3d(update);
    }
    
    //存盘和读盘:留空
    virtual bool read(istream &in){}
    virtual bool write(ostream &out)const{}
};

//误差模型 模板参数:观测值维度,类型,连接顶点类型
class CurveFittingEdge:public g2o::BaseUnaryEdge<1,double,CurveFittingVertex>{
public :
    EIGEN_MAKE_ALIGNED_OPERATOR_NEW
    
    CurveFittingEdge(double x):BaseUnaryEdge(),_x(x){}
    
    //计算曲线模型误差
    virtual void computeError()override{
        const CurveFittingVertex *v=static_cast<const CurveFittingVertex *>(_vertices[0]);
        const Eigen::Vector3d abc=v->estimate();
        _error(0,0)=_measurement-std::exp(abc(0,0)*_x*_x+abc(1,0)*_x+abc(2,0));
    }
    //计算雅可比矩阵
    virtual void linearizeOplus()override{
        const CurveFittingVertex *v=static_cast<const CurveFittingVertex *>(_vertices[0]);
        const Eigen::Vector3d abc=v->estimate();
        double y=exp(abc[0]*_x*_x+abc[1]*_x+abc[2]);
        _jacobianOplusXi[0]=-_x*_x*y;
        _jacobianOplusXi[1]=-_x*y;
        _jacobianOplusXi[2]=-y;
    }
    
    virtual bool read(istream &in){}
    virtual bool write(ostream &out)const{}
public:
    double _x;//x值,y值为_measurement
};

int main(int argc,char **argv){
    double ar=1.0,br=2.0,cr=1.0;        //真实参数值
    double ae=2.0,be=-1.0,ce=5.0;       //估计参数值
    int N=100;
    double w_sigma=1.0;                 //噪声sigma
    double inv_sigma=1.0/w_sigma;
    cv::RNG rng;                        //OpenCV随机数生成
    
    vector<double> x_data,y_data;   //数据
    for(int i=0;i<N;i++){
        double x=i/100.0;
        x_data.push_back(x);
        y_data.push_back(exp(ar*x*x+br*x+cr)+rng.gaussian(w_sigma*w_sigma));
    }
    //构建图优化,先设定g2o
    typedef g2o::BlockSolver<g2o::BlockSolverTraits<3,1>>BlockSolverType;//每个误差项优化变量维度为3,误差值维度为1
    typedef g2o::LinearSolverDense<BlockSolverType::PoseMatrixType>LinearSolverType;//线性求解器类型


    //梯度下降方法,可以从GN、LM、DogLeg中选
    auto solver=new g2o::OptimizationAlgorithmGaussNewton(g2o::make_unique<BlockSolverType>(g2o::make_unique<LinearSolverType>()));
    g2o::SparseOptimizer optimizer;  //图模型
    optimizer.setAlgorithm(solver); //设置求解器
    optimizer.setVerbose(true);     //打开调试输出
    
    //往图中增加顶点
    CurveFittingVertex *v=new CurveFittingVertex();
    v->setEstimate(Eigen::Vector3d(ae,be,ce));
    v->setId(0);
    optimizer.addVertex(v);
    
    //往图中增加边
    for(int i=0;i<N;i++){
        CurveFittingEdge *edge=new CurveFittingEdge(x_data[i]);
        edge->setId(i);
        edge->setVertex(0,v);            //设置连接的顶点
        edge->setMeasurement(y_data[i]); //观测数值
        edge->setInformation(Eigen::Matrix<double,1,1>::Identity()*1/(w_sigma*w_sigma));//信息矩阵:协方差矩阵之逆
        optimizer.addEdge(edge);
    }
    //执行优化
    cout<<"start optimization"<<endl;
    chrono::steady_clock::time_point t1=chrono::steady_clock::now();
    optimizer.initializeOptimization();
    optimizer.optimize(10);//这个参数推测是迭代次数
    chrono::steady_clock::time_point t2=chrono::steady_clock::now();
    chrono::duration<double>time_used=chrono::duration_cast<chrono::duration<double>>(t2-t1);
    cout<<"solve time cost = "<<time_used.count()<<" seconds."<<endl;
    
    //输出优化值
    Eigen::Vector3d abc_estimate=v->estimate();
    cout<<"estimate model: "<<abc_estimate.transpose()<<endl;
    
    return 0;
}

CMakeLists.txt
注意G2O_CORE_LIBRARY的写法,否则可能会出现XXX未定义的引用

cmake_minimum_required(VERSION 2.8)
project(ch6_3)

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

list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
list(APPEND CMAKE_MODULE_PATH /home/yufan/MyLibs/g2o-master/cmake_modules)
set(G2O_ROOT/usr/local/include/g2o)
set(G2O_LIBS/usr/local/include/g2o)

include_directories("/usr/include/eigen3")

#OpenCV
find_package(OpenCV REQUIRED)
include_directories(${OpenCV_INCLUDE_DIRS})

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

add_executable(g2oCurveFitting g2oCurveFitting.cpp)
target_link_libraries(g2oCurveFitting ${G2O_STUFF_LIBRARY} ${G2O_CORE_LIBRARY} ${OpenCV_LIBS})

标签:abc,函数,double,G2O,g2o,include,sigma
From: https://www.cnblogs.com/code-fun/p/16756436.html

相关文章

  • 网络字节序与主机字节序的转换函数实践
    1、网络字节序:是TCP/IP中一种固定好的数据表示格式,它与具体的CPU,操作系统,传输方式无关,从而可以保证数据在不同主机之间传输时能够兼容。2、主机字节序:即大端(BigEndian)......
  • 1.9 高级语法_函数
    #函数中已经输出结果,调用函数即可deffun(x):#函数体print(x/10)fun(10)fun(20)#函数中未输出结果,调用函数,再输出结果defcalc(a,b):returna+b......
  • 【C语言】初始函数
    ......
  • ES6新特征高阶函数
    <!DOCTYPEhtml><htmllang="en"><head> <metacharset="UTF-8"> <metahttp-equiv="X-UA-Compatible"content="IE=edge"> <metaname="viewport"content="......
  • 详解 printf() 函数
    声明(叠甲):鄙人水平有限,本文章仅供参考。1.引子#include<stdio.h>intmain(){printf("helloworld\n");return0;}上面这一段代码大家应该都十分的......
  • sorted函数中的key
    sorted函数有三个参数:iterable、key、reverse。其中,iterable为一个可迭代的对象,reverse表示是否对排序结果进行反转,而key稍微复杂一点,主要是用来对需要比较的元素进行处理......
  • 概率生成函数 (PGF)
    1.概述取值处概率的生成函数。\(F(1)=1,F'(1)=E\)2.分析设\(F(i)\)为\(i\)时刻结束概率的生成函数,\(G(i)\)为\(i\)时刻未结束概率的生成函数,那么有:\[f_i+g_i=g......
  • 算法学习笔记(数学):数论分块 + 容斥原理 + 莫比乌斯函数
    算法学习笔记(数学):数论分块+容斥原理+莫比乌斯函数这篇文章主要是要讲一道题目(链接在这里)以及梳理一下数论分块,莫比乌斯函数,容斥原理这些知识。先介绍下知识点吧qwq......
  • 8.函数上
    函数函数的原型和调用在使用函数前必须定义或者声明函数doublecircle(doubler);intmain(){ doublelength=circle(10);printf("length=%f\n",length......
  • C语言:三角函数的参数为弧度,通常的角度值需要转化为弧度
    #include<stdio.h>#include<math.h>//三角函数的参数为弧度,是角度必须转化为弧度//3.14=180,1度=3.14/180,转化方法:(3.14/180)*角度值main(){floata,b,c;......