g2o图优化简介与基本使用方法

2023-05-16

一、g2o简介

g2o(General Graphic Optimization)是一个基于图优化的库,将非线性优化与图论结合起来的理论,我们可以利用g2o求解任何可以表示为图优化的最小二乘问题。

图优化就是把优化问题表现成图的方式。图由顶点和边组成,其中顶点表示优化变量,边表示误差项,对任意一个非线性?> 最小二乘问题,我们都可以构建与之对应的图。
(注:这里的图是图论意义上的图,可以用概率论里面的定义,贝叶斯图或因子图。)

二、g2o安装

首先安装g2o的依赖

sudo apt install qt5-qmake qt5-default libqglviewer-dev-qt5 libsuitesparse-dev libcxsparse3 libcholmod3 

然后到github下clone此工程,然后编译安装,指令如下:

git clone https://github.com/RainerKuemmerle/g2o.git
cd g2o/
mkdir build
cd build
cmake ../
make

g2o的头文件在/usr/local/g2o下,库文件在/usr.local/lib下。

三、利用g2o拟合曲线

1. 拟合步骤

① 定义顶点和边的类型(优化变量与误差项)
② 构建图
③ 选择优化算法
④ 调用g2o进行优化,返回结果

2. 实验-拟合曲线

此示例程序还依赖opencv、Eigen、Ceres库,需要预先安装。

main.cpp文件

#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;

// 曲线模型的顶点(优化变量)(参数:维度、数据类型)
// 优化变量维数:3维    数据类型:Eigen::Vector3d
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);           // 更新优化变量(估计值)。增量方程计算出增量△x后,通过此函数对估计值进行调整
    }

    //读盘
    virtual bool read(istream &in) {}

    //存盘
    virtual bool write(ostream &out) const {}
};


// 曲线模型的边(误差项)(参数:观测值维度、类型、连接定点类型)
// 边的模型:BaseUnaryEdge   连接顶点个数:1    测量值数据类型:double  顶点类型:CurveFittingVertex
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]);        // _vertices[]存储顶点信息
        const Eigen::Vector3d abc = v->estimate();
        _error(0, 0) = _measurement - std::exp(abc(0, 0) * _x * _x + abc(1,0) * _x + abc(2, 0));        // _error存储computeError()函数计算的误差
    }

    // 计算雅克比矩阵
    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() {
    //定义数据参数
    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;                            //随机数产生器

    //生成100个带高斯噪声的数据
    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));
    }

    // 构建图优化
    typedef g2o::BlockSolver<g2o::BlockSolverTraits<3, 1>> BlockSolverType;    // 配置BlockSolver,每个误差项优化变量维度为3,误差值维度为1
    typedef g2o::LinearSolverDense<BlockSolverType::PoseMatrixType> LinearSolverType;    // 创建BlockSolver,并用定义的线性求解器初始化

    // 设置梯度下降的方法,创建总求解器solver
    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);                     //定义边的编号(决定在H矩阵中的位置)
        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);    //执行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() << " s." << endl;

    Eigen::Vector3d abc_estimate = v->estimate();   //获取当前值
    cout << "estimated model: " << abc_estimate.transpose() << endl;

    return 0;
}

CMakeLists.txt文件

cmake_minimum_required(VERSION 3.20)
project(g2oCurveFitting)
set(CMAKE_CXX_STANDARD 14)

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

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

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

# g2o库
list( APPEND CMAKE_MODULE_PATH /home/huffie/slam/3rdparty/g2o/cmake_modules ) #刚才clone的项目文件夹
set(G2O_ROOT /usr/local/include/g2o)
find_package(G2O REQUIRED)
include_directories(${G2O_INCLUDE_DIRS})

add_executable(g2oCurveFitting main.cpp)

target_link_libraries(g2oCurveFitting ${OpenCV_LIBS})
target_link_libraries(g2oCurveFitting  g2o_stuff   g2o_core )
target_link_libraries(g2oCurveFitting ${CERES_LIBRARIES})
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

g2o图优化简介与基本使用方法 的相关文章

  • ROS2的基础概念

    前言 记录ROS2学习的各项核心概念 xff0c 便于后续复习 一 工作空间workshop 1 什么是工作空间 在ROS机器人开发中 xff0c 工作空间是一个存放项目开发相关文件的文件夹 xff0c 各种编写的代码 参数 脚本等文件 x
  • ubuntu多个系统之间文件局域网共享

    前言 xff1a 博主需要在多台主机上进行数据传输 xff0c 由于数据量比较大所以 xff0c 使用移动介质进行传输极为不方便 xff0c 并且也不没有更多的资源在两台主机都进行备份 下面的方式 xff0c 是博主在测试大量的网络上的帖子
  • idea如何清理缓存

    今天运行项目突然报错 检查半天 发现代码没问题 但就是报错 好气啊 最后解决办法就是把以前的缓存清理掉 问题解决 idea清理缓存的方法 File gt Invalidate Caches Restart
  • VNC登录失败:Authentication Failure

    遇到问题 xff1a 解决 xff1a 返回MobaXter xff0c 登录服务器 重置密码 回到VNC Viwer xff0c 重新连接
  • Haar特征

    一 Haar特征 特征是计算机视觉领域一种常用的特征描述算子 xff0c 特征 xff0c 描述图像的特征 xff0c 多用于人脸检测 行人检测 xff0c 等目标检测 xff0c Haar like特征模板内只有白色和黑色两种矩形 xff
  • 在线免费生成IntelliJ IDEA 15.0注册码

    http idea iteblog com key PHP
  • UCOSⅢ简介

    UCOS 简介 简述一 裸机系统与多任务系统二 UCOS 的重要特性三 UCOS 的组成 简述 UCOS xff08 UCOS的第三代内核 xff09 是一个可裁剪 可固化 可剥夺的多任务系统 xff0c 具有高度可移植性 xff0c 没有
  • 树莓派无屏幕无网线远程桌面连接配置方法

    要进行远程连接 xff0c 首先需要让树莓派连上网 xff0c 一种方法是使用网线 xff0c 另一种方法是使用WiFi 本文介绍后者 1树莓派WiFi的配置 没有网线的情况下 xff0c 要远程访问则只能通过WiFi 而由于没有屏幕 xf
  • 【C#可视化工具开发】(Visual Studio2017)利用echarts——1.界面设计

    C 可视化工具开发 近期在做一个可视化工具 xff0c 有关于指标对标相关内容 xff0c 用自己几乎没学到的Visual Studio 2017疯狂开发 xff08 碰壁 xff09 xff0c 由于总体的可视化工具还没做完 xff0c
  • 使用精灵标注助手生成json文件

    使用精灵助手教程 本文主要介绍如何使用精灵标注助手生成json文件 下载精灵标注助手 下载链接 xff1a http www jinglingbiaozhu com 选择windows版本进行下载 安装方式很简单 xff0c 就是一直nex
  • 关于Nginx配置文件在推流取流时的对应模块作用

    关于Nginx配置文件在推流取流时的对应模块作用 前言 xff1a 前提知识1 xff09 xff1a 取流地址只是我们从用于管理路面监控视频的DVR NVR的IP地址 xff0c 这里只需要知道该地址即可 重点是讲述推流和拉流nginx
  • go语言实战-----30-----token机制微信公众号签名验证的方法、XML解析,CDATA解析、交换协议、接收消息协议、被动回复消息协议、正则表达式

    一 token机制微信公众号签名验证的方法 1 token机制 token机制就是使用一个token 通常是一个字符串 xff0c 长度没有特别限制 xff0c 一般是10字节或者16字节 xff0c 然后按照一定的算法生成签名 xff0c
  • python下划线的5种类型

    python中5中下划线 学习的原文章1链接 学习的原文章2 双前导下划线解释 链接 1 单前导下划线 以单个下划线开头的变量或方法仅供内部使用 xff0c 有私有声明的作用 xff0c 但这并不是python语法的强制规定 xff0c 而
  • JAVA课后习题(一)——我是歌手

    大家好 xff01 我是小黄 xff0c 很高兴又跟大家见面啦 xff01 今天更新的是 xff1a JAVA程序设计课后习题 我是歌手往期检索 xff1a 程序设计学习笔记 目录 创建时间 xff1a 2020年10月23日 软件版本 x
  • 解决git时出现error: src refspec master does not match any问题

    问题复现 xff1a 今天在使用gitee创建仓库后上传写好的代码时报错 在远程关联仓库后无法正常推送 键入下图代码时报错error src refspec master does not match any xxx 解决方法 xff1a
  • 如何购买云服务器----以华为云服务器为例

    进入华为云官网 https activity huaweicloud com 登入自己注册的账户 进入控制台 点击界面里我的资源 弹性云服务器ECS 点击右上角 购买弹性云服务器 按照自己的需求选择 xff0c 重点注意 xff1a 计费方
  • Java编写MapReduce的步骤

    Mapper 自定义类继承Mapper类重写自定义类中的map方法 xff0c 在该方法中将K1和V1转为K2和V2将生成的K2和V2写入上下文中 二 Reduce 自定义类继承Reduce类重写Reducer中的reduce方法 xff0
  • PX4入门及开发指南

    PX4入门及开发指南 用户手册开发者手册 用户手册 https docs px4 cc master zh index html 开发者手册 https dev px4 cc master zh index html
  • 树莓派编译工作空间卡死

    树莓派编译程序时遇到卡死 1 树莓派安装的Ubuntu mate 16 04 系统默认设置的swap交换空间不够 xff0c 而编译某些文件的时候需要较大的交换空间 xff0c 树莓派的交换空间被用满所以树莓派看起来好像是死机了的样子 xf
  • 超好用但是很多人不知道的的串口(网络)调试助手推荐

    小众但是超好用的串口 xff08 网络 xff09 调试助手 前言O ComToll xff08 串口 xff09 格西烽火串口网络调试助手伏特加串口 xff08 网络 xff09 调试助手windows自带的串口调试助手总结 前言 这里的

随机推荐

  • STM32上可用的的SM 2 3 4国密算法

    可在STM32上使用的国密算法 SM 2 3 4 SM2SM3SM4 下面直接给出代码 xff0c 有问题可评论 xff0c 自己改动的 xff0c 测试不到的地方可能有bug xff0c 欢迎指正 SM2 由于SM2算法牵扯到一些较为复杂
  • Stm32下环境传感器-Stlm75-hts221-spg30(Hal)

    Stm32下环境传感器 Stlm75 hts221 spg30 xff08 Hal xff09 简介IIC驱动接口Stlm75hts221Spg30 简介 Stlm75与Hts221都是ST的传感器 xff0c 有官方例程 xff0c 我只
  • vscode makefile编译方法实例

    c出来 o 使用 o出来 bin NB二人组走天下 xff0c 目标 xff1a 依赖 xff0c 下一行tab 加命令 感觉时比较块上手的教程 xff0c 手写AI c语言中文网的makefile c语言中文网的就是按部就班 xff0c
  • 树莓派(三):将你的树莓派进行镜像备份

    0 前言 就像备份电脑一样 xff0c 你一定不想树莓派出错后重新配置树莓派 xff0c 将你的树莓派进行备份 1 建立img镜像文件 随便找一个地方 xff0c 新建一个文本文档 xff0c 命名为 你喜欢的名字 img 这时候就会生成一
  • 接口的理解、接口匿名实现类的创建

    接口的概述 xff1a 一方面 xff0c 有时必须从几个类中派生出一个子类 xff0c 继承它们所有的属性和方法 但是 xff0c Java不支持多重继承 xff0c 有了接口 xff0c 就可以得到多重继承的效果 另一方面 xff0c
  • 关于大疆经纬M100进行二次开发视觉跟踪和视觉SLAM的求助

    本人第一次接触大疆的二次开发 xff0c 现在的需求是使用M100进行二次开发能够实现视觉跟踪目标 xff0c 并能够实现视觉SLAM xff0c 但是我没有接触过二次开发 xff0c 希望各位有过经验的大佬能够不吝留言给我说一下具体实现的
  • 定义一个接口CanFly,描述会飞的方法public void fly();

    1 使用类与接口的知识完成如下要求 xff1a xff08 1 xff09 定义一个接口CanFly xff0c 描述会飞的方法public void fly xff08 2 xff09 分别定义类飞机和鸟 xff0c 实现CanFly接口
  • 在Keil4中新建51单片机工程模板详细步骤

    本文主要介绍51单片机学习和开发中的第一步 新建工程模板 对于刚开始学单片机的同学 xff0c 首先要在电脑上装好MDK4软件和CH340驱动 xff0c 然后也要有一个单片机烧录软件 xff08 一般买回来的单片机附带的资料里都会有这三个
  • Java笔试常用库函数

    字符串转数组 String s span class token operator 61 span span class token string 34 13 34 span span class token punctuation spa
  • Pytorch极简入门教程(十六)——DenseNet提取特征

    Pytorch之DenseNet提取特征 导入必要的模块 span class token keyword import span torch span class token keyword from span torch span cl
  • 1. 创建一个功能包(package)

    一 ros所有的进程都需要在工作空间下进行 首先 xff0c 在 home文件夹 任何目录都可以 下创建一个工作空间 xff1a source span class token operator span opt span class to
  • 谷粒学院知识点总结

    文章目录 前言一 项目功能点1 后台管理系统功能2 前台系统功能3 总结项目技术点 二 项目问题三 项目描述1 总体介绍2 项目功能模块 amp 主要深入的模块3 项目涉及技术 前言 谷粒学院知识点总结 xff0c 准备实习面试 一 项目功
  • Win11家庭版U盘Pe安装

    目录 1 准备材料 2 安装 3 开机 4 需要安装的软件 5 封装 6 发现问题 未解决 1 准备材料 1 win11下载 MSDN 迅雷地址链接 2 驱动总裁 U盘魔术师 地址链接 2 安装 1 做好启动盘后 开机进pe 3 开机 准备
  • Android应用与硬件建立连接

    文章目录 1 建立连接的原理2 信件 和 邮递员 3 对方可能未收到如何处理4 接收 回信 5 多次数据交互6 小结 1 建立连接的原理 在实现软件与硬件交互的时候 xff0c 首先需要了解该硬件的构造 xff0c 运行流程等相关操作 xf
  • 使用Layui时间组件(laydate)

    在一般的程序或者软件业务的操作上 xff0c 通常涉及时间的记录 xff0c 需要记录业务时间 xff0c 或者根据时间来筛 选业务 选择时间 xff0c 可以直接输入 xff0c 也可以弹出日期进行选择 在layui中提供了 xff0c
  • 规范vs代码

    开发工具与关键技术 xff1a VS 作者 xff1a 吴业华 撰写时间 xff1a 2019年7月7号 在我们编程过程中 代码的规范性涉及很大很大 xff0c 有时候即使你的代码打对了 但是依然报错 这份功劳差不多大概都是代码的不规范所收
  • ESP8266_APP连接试验

    ESP8266 APP连接试验 概述硬件部分8266固件烧录Arduino IDE 8266版型下载安装MQTT库ESP8266程序设计 APP部分创建项目UI设计主程序设计 概述 本次试验使用的是ESP8266 NodeMCU 硬件部分
  • ROS安装时rosdep init与rosdep update问题解决方法(2022.04.08亲测)

    2022 4 8更新 xff1a 运行下面的指令即可 span class token function sudo span span class token function apt get span span class token f
  • 【已解决】mmcv/_ext.cpython-37m-x86_64-linux-gnu.so: undefined symbol: _ZN6caffe28TypeMeta21_typeMetaData

    问题描述 使用MMDetection复现论文 xff0c 出现如下Bug xff1a ImportError home quaiping anaconda3 lib python3 7 site packages mmcv ext cpyt
  • g2o图优化简介与基本使用方法

    一 g2o简介 g2o xff08 General Graphic Optimization xff09 是一个基于图优化的库 xff0c 将非线性优化与图论结合起来的理论 xff0c 我们可以利用g2o求解任何可以表示为图优化的最小二乘问