视觉SLAM实践入门——(9)曲线拟合之g2o库

G2O库:图优化库基础使用,以曲线拟合(一元边问题)为例 记录了G2O库的基础使用方式,包括对节点、边类的继承与重写;优化器、图模型的构建。采用曲线拟合问题为例,进行学习。 阅读详情

图优化理论

g2o是一个基于图优化的库(图优化是一种将非线性优化和图论结合起来的理论)

图优化把优化问题表现成图。一个图由若干顶点以及连接这些顶点的边组成。

顶点表示优化变量,边表示误差项

下图是一个简单的图优化例子。三角形表示相机位姿节点,圆形表示路标点,它们构成图优化的顶点;实线表示相机运动模型,虚线表示观测模型,它们构成图优化的边

有了图,可以做 去掉孤立顶点或者优先优化边数较多的顶点 这样的优化

 

安装g2o

安装依赖

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

从hhtps://github.com/RainerKuemmerle/g2o获得库并安装

cd ./g2o
mkdir build
cd build
cmake ..
make
make install

 

使用g2o拟合曲线

为了使用g2o,首先将曲线拟合问题抽象成图优化(节点是优化变量,边是误差项)

整个问题只有一个顶点,因此边是一元边(只连接了一个节点)。边连接的节点数,反映了这个误差与多少个优化变量有关

 

 

使用g2o进行优化的步骤:

1、定义顶点和边的类型(添加一些需要的变量,重写一些初始化、计算的方法)

2、构建图

3、选择优化算法

4、使用g2o优化

 

注意事项

如果无法链接g2o库(提示为下面内容)

error while loading shared libraries: libg2o_core.so: cannot open shared object file: No such file or directory 

增加动态库路径配置文件

sudo vi /etc/ld.so.conf.d/g2o.conf 

添加一行

/usr/local/lib 

再输入

sudo ldconfig

 

#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 {	//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]);	//static_cast将_vertices[0]的类型强制转换为const CurveFittingVertex *
    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 << "estimated model: " << abc_estimate.transpose() << endl;

  return 0;
}

 

高翔视觉SLAM十四讲(第二版)各种软件、库安装的以及报错解决方法 前言 自己不小心把Ununtu系统搞崩了,只好重装Ununtu系统,写一篇博客记录一下高翔视觉SLAM十四讲(第二版)各种库安装的以及报错解决方法。本篇博客写于2022年4月7日,安装顺序按照在书中出现的顺序。下面每个库都会介绍在书中出现的地方,以及库的来源。下面安装的依赖项,如果书上有都是来源于书上,如果书上版本低了,则做出了相应的改动;如果书上没有则来自于其他博客。 系统版本 Ununtu18.04 下载高翔视觉SLAM十四讲第二版的源代码 有些小型的库存放在 slambook2/3rdp.. 阅读详情

相关推荐

从零开始一起学习SLAM | 理解图优化,一步步带你看懂g2o代码

首发于公众号:计算机视觉life 旗下知识星球「从零开始学习SLAM」 这可能是最清晰讲解g2o代码框架的文章 理解图优化,一步步带你看懂g2o框架 小白:师兄师兄,最近我在看SLAM的优化算法,有种方法叫“图优化”,以前学习算法的时候还有一个优化方法叫“凸优化”,这两个不是一个东西吧? 师兄:哈哈,这个问题有意思,虽然它们中文发音一样,但是意思差别大着呢!我们来看看英文表达吧,图优化的英文是...

计算机视觉life 6654

SLAM算法与工程实践——SLAM基本库的安装与使用(6):g2o优化库(1)g2o库的安装

g2o优化库(1)

YangtseJin的博客 1957

视觉SLAM非线性优化之Ceres solver 和 G2o

“ 如果你受苦了,感谢生活,那是它给你的一份感觉; 如果你受苦了,感谢上帝,说明你还活着。” ——伊索 3月就要结束了~ 最近在看视觉SLAM的一些东西...

I-am-Unique 4009

ceres库 拟合曲线 (含高斯牛顿法)

Ceres是一个广泛使用的最小二乘问题求解库。 Ceres求解的最小二乘问题最一般的形式如下 min⁡x12∑iρi(∣∣fi(xi1,...,xin∣∣2) \min_{x}\frac{1}{2}\sum_{i}\rho_{i}(||f_{i}(x_{i1}, ... , x_{in}||^{2})xmin​21​i∑​ρi​(∣∣fi​(xi1​,...,xin​∣∣2) 其中fif_{i}fi​为代价函数,在ceres中为残差块,ρi\rho_{i}ρi​为核函数,如果不用的话,那么目标函数仍然是许多

蓝羽飞鸟的博客 1715

解决视觉SLAM十四讲ch7中 g2o库编译错误以及opencv报错问题

一、问题 最近在看高翔博士的视觉Slam十四讲,其中在跑书中第七节的例子的时候出现如下问题: 1.编译的时候pose_estimation_3d2d.cpp以及pose_estimation_3d3d.cpp文件编译不通过,如下图 2.opencv imshow函数显示不出来图片内容,且窗口标题乱码,如下图 二、解决方法 第一个问题是由于g2o库的版本不同导致的问题,如果你使用的版本和高博士的...

weixin_43319860的博客 3818

《视觉SLAM十四讲》中各库的安装

目录 目录 1. Eigen线性代数库的安装 2. Sophus李代数库的安装 3. OpenCV计算机视觉库的安装 4. PCL点云库的安装 5. Ceres非线性优化库的安装 6. G2O图优化库的安装 1. Eigen线性代数库的安装 Eigen库是一个C++线性代数开源库,官方主页http://eigen.tuxfamily.org/dox-devel/modules.h...

H&&Z的博客 6236

ceres库 曲线拟合

首先你需要定义一个模型函数,这个函数描述了曲线的形状,并且包含了需要拟合的参数。Ceres库是一个用于非线性最小二乘问题的C++库,它可以用来进行曲线拟合。:设置求解器的配置参数,如线性求解器类型、迭代次数、是否输出进度等。:接着定义一个残差函数,它计算模型函数和实际观测数据之间的差异。类来构建优化问题,将残差函数添加到问题中。:调用求解器来求解问题,并获取结果。下面是一个高斯曲线拟合的例子。

weixin_43632469的博客 633

视觉SLAM14讲:SLAM中g2o入门详解,直接法BA(课程第7讲作业)

视觉SLAM课程-第7讲作业:SLAM中g2o入门详解,直接法BA

qq_37746927的博客 3907

【SLAM】G2O优化库超详细解析

通用图优化。为何叫通用呢?G2O的核里带有各种各样的求解器,而它的顶点、边的类型则多种多样。通过自定义顶点和边,事实上,只要一个优化问题能够表达成图,那么就可以用G2O去求解它。常见的,比如bundle adjustment、ICP、数据拟合,都可以用G2O来做。所谓图优化,是把优化问题表现成图的一种方式,这里的图是图论意义上的图。一个图由若干个顶点,以及连着这些顶点的边组成。在这里,我们用顶点表示优化变量,而用边表示残差项。

Yngz_Miao的博客 1万+

从零开始一起学习SLAM | 掌握g2o顶点编程套路

点“计算机视觉life”关注,置顶更快接收消息! 小白:师兄,上一次将的g2o框架《从零开始一起学习SLAM | 理解图优化,一步步带你看懂g2o代码》真的很清晰,我现在再去看g2o的那些优化的部分,基本都能看懂了呢! 师兄:那太好啦,以后多练习练习,加深理解 小白:嗯,我开始编程时,发现g2o的顶点和边的定义也非常复杂,光看十四讲里面,就有好几种不同的定义,完全懵圈状态。。。师兄,能否帮我捋...

计算机视觉life 4049

Open3D(C++) 最小二乘拟合多项式曲线

最小二乘拟合多项式曲线的C++版本Open3D代码实现。

点云侠的博客 520

【视觉SLAM十四讲】各种库的安装及代码实践

在学习高博的《视觉SLAM十四讲》的过程中,遇到了各种问题。虽说在网上都能找到对应的解决方案,但没有一篇是详细列尽遇到的问题的文章。于是,打算自己写一篇记录学习过程中遇到的一系列问题。希望能为后续的学习提供一点帮助!(自己也是新手小白,还是有很多不懂的地方。

2302_80099075的博客 6054

视觉SLAM笔记(29) g2o

图优化、g2o 的编译与安装、拟合曲线

氢键H-H 1万+

【视觉SLAM14讲】【汇总】

第一讲东西少,就没记录【slam十四讲第二版】【课本例题代码向】【第二讲初识SLAM】【SLAM基础知识】【linux下C++编译】【cmake基础使用】【slam十四讲第二版】【课本例题代码向】【第三~四讲刚体运动、李群和李代数】【eigen3.3.4和pangolin安装,Sophus及fim的安装使用】【绘制轨迹】【计算轨迹误差】【slam十四讲第二版】【课本例题代码向】【第五讲~相机与图像】【OpenCV、图像去畸变、双目和RGB-D、遍历图像像素14种】【slam十四讲第二版】【课本例题代码向】【

qq_45954434的博客 1万+

保姆级教程:在mmdetection中手动计算并可视化P、R、F1值(附完整代码)

本文提供了一份详细的mmdetection教程,指导开发者如何手动计算并可视化精确率(P)、召回率(R)和F1值。通过完整的代码示例和清晰的步骤说明,帮助用户深入理解目标检测模型的性能评估方法,特别适合需要精细分析模型表现的计算机视觉研究人员和工程师。

weixin_29038303的博客 398

STM32H750实战:用TIM+DMA驱动ADC/DAC实现音频回环(附CubeMX配置避坑指南)

本文详细介绍了在STM32H750上构建高保真、低延迟音频链路的实战方法。通过配置TIM定时器作为硬件节拍器,精准触发ADC采集与DAC播放,并利用DMA实现数据的自动搬运,全程无需CPU干预。文章重点剖析了CubeMX配置中的关键步骤与常见“坑点”,如ADC的Conversion Data Management模式选择、DMA的FIFO与Burst模式配置,以及STM32H7系列必须开启ADC全局中断等,并提供了完整的代码实现与调试验证指南。

1057

【视觉惯性SLAM:六、图优化库(1):g2o的使用指南】

g2o 提供了一些基本顶点类,但也支持用户自定义顶点。自定义顶点需要继承 g2o::BaseVertex 并实现相应的虚函数。示例:自定义一个三维点顶点// 定义一个3维点的顶点public:// 初始化函数,设置顶点初始值// 初始化为 (0, 0, 0)// 更新顶点值// 更新顶点估计值// 可选:保存和加载顶点信息(序列化)

计算机领域博客,与时俱进的思想与技术。 1376

嵌入式学习之QT学习---14 QT跨平台运行之把QT程序交叉编译到ARM开发板

想要把qt工程放到开发板上运行,就需要用到交叉编译。由于qt是跨平台的,所以只需要换个编译器编译一下就可以。 以“定时器”的例子为例,在移植之前还需要进行一个准备工作,在windows下运行的时候,电脑屏幕很大,但是运行的窗口只有一点点大,开发板也有外接屏幕,如何让运行窗口自动适配开发板的外接屏幕呢?令其占满屏幕显示,而不是一小块。 第一步:需要设置一下,先给ui布局,如果不布局,控件就不会随着屏幕的大小的变化而变化。 第二步:利用代码来获取屏幕的大小,给widget.cpp文件下添加如下代码 #inclu

qq_42822743的博客 5456

g2o学习-《视觉slam十四讲》中的g2o

如果想学好视觉slam,看来g2o是无论如何都绕不开的一个槛。我也在学习这个库的使用,希望可以分享一点学习心得~ 感谢无人的回忆的转载的博客以及半闲居士做的系列博客。 目前的准备是讲《视觉slam十四讲》中所有用到g2o的部分都给弄明白,那么咱们开始吧~ 文章目录概论定义顶点和边的类型构建图并选择优化算法调用g2o进行优化,返回结果第6讲 拟合曲线:g2o_curve_fitting1. 定义顶...

菠菜明灯的博客 2508

GD32H7实战:5步搞定YOLO轻量化模型部署到MCU(附避坑指南)

本文详细介绍了如何将YOLO轻量化模型部署到GD32H7 MCU的完整实战流程。通过五个关键步骤,涵盖环境搭建、模型训练、格式转换到工程集成,并重点分享了使用GD32AI-ModelZoo工具链进行MCU部署的避坑指南,帮助开发者在资源受限的边缘设备上实现高效目标检测。

weixin_29070861的博客 445

LeRobot 入门教程(十四)Meta-World 机器人多任务与元强化学习操作仿真基准平台

Meta-World是一个开源机器人操作模拟基准平台,专注于多任务与元强化学习研究。该平台提供50项多样化任务(MT50套件),采用标准化评估协议测试算法泛化能力。LeRobot平台支持Meta-World任务评估,提供预处理数据集和训练工具。用户可通过命令行快速训练SmolVLA策略,并评估模型在简单、中等、困难等不同难度任务上的表现。文章还提供了兼容性问题和实用技巧建议,如使用完整MT50任务集测试泛化能力、采用one-hot任务条件化等。这些资源为研究人员开展机器人多任务学习提供了标准化实验环境。

2506_90492529的博客 1017

G2O 库

图优化

sinoai 2182

【3】 灰度变换(1)

第三章(1)【总三】

课题分离 659

视觉SLAM十四讲笔记:G2O库的安装

在学习高翔大神的视觉SLAM十四讲的安装G2O库的时候遇到了无法安装依赖的问题.当时费劲九牛二虎的力气(有夸大成分)解决之.当时没有记笔记或者写博客的习惯.匆匆了之继续奋斗在SLAM前线去了.后来电脑重新装了ubuntu系统.如今又遇到了G2O库的安装问题 .后悔当初,但为时已晚.为避免今后遇到类似的问题,遂记录下这次的解决方式.以便日后查阅.同时希望能给有相同问题的战友们一点帮助: G2O库是一...

qq_43159510的博客 4459

USB_TYPE-C 母座电路设计

本文详细介绍了USB Type-C接口(C2765186)的电路设计要点,重点解析了电源、识别和数据三部分的关键连接方案。电源部分需并联VBUS和GND引脚并加宽走线以承载3A电流;识别部分必须为CC1/CC2引脚配置5.1kΩ±1%精度的下拉电阻,这是触发PD充电的核心条件;数据部分通过短接正反插引脚实现盲插功能。文档还提供了完整的引脚对照表,并强调PCB布局需注意ESD防护、差分走线阻抗控制等要点,为Type-C接口设计提供了实用指导。

在读研究生,FPGA电路设计与功能开发。 579

【虚拟仿真】Unity3D中实现对大疆无人机遥控器手柄按键响应

最近项目中需要用到大疆无人机遥控器对程序中无人机进行控制,遥控器是下图这一款:博主发现接入手柄这块的可以参考的内容非常少,对于大疆遥控器的控制更是没有。博主经过一番研究,终于理通了这块的遥控器摇杆数据的控制。并且将解决思路分享出来,希望对大家有所帮助。

优快云博客专家,Unity3D高级软件工程师,《Unity 3D从入门到实战》作者。 2818
上一篇: 视觉SLAM实践入门——(8)使用Ceres库进行曲线拟合
下一篇: 视觉SLAM实践入门——(10)特征提取和匹配(修复源码中的段错误bug)
floatinglong
博客等级 码龄9年 90粉丝 143原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值