g2o的一般过程

1.自己定义顶点类、边类或者用已经有的。
1.1定义顶点
例子
class CurveFittingVertex: public g2o::BaseVertex<3, Eigen::Vector3d>
{
public:
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
virtual void setToOriginImpl() // 重置
{
_estimate << 0,0,0;
}

virtual void oplusImpl( const double* update ) // 更新
{
_estimate += Eigen::Vector3d(update);
}
// 存盘和读盘:留空
virtual bool read( istream& in ) {}
virtual bool write( ostream& out ) const {}
};
自己能够操作的,修改类名为自己的类名。修改顶点的维度和类型,就是g2o:BaseVertex<>里的两个参数。
函数setToOriginImpl{}里设置_estimate的初值。你可以如例子中_estimate<<0,0,0,也可以_estimate=SE3Quat(),也可以留空。
oplusImpl是设定估计的更新值的函数,一般里面的变量都是更新值const double* update,至于这个update你可以设成update_什么的。然后函数里估计值会变成估计值和更新值的和或积,而更新值的类型必须修改成和顶点类型一致。也可以重写这个函数,在括号后输入override,而在{}定义一个新参数v,这个v可以和顶点类型不一致,v是由update得到或者由update和其他参数一起得到,然后是_estimate+=v,最后在设顶点估计值的时候,估计值要和v的类型一致。最重要的就是这个oplusImpl函数。
而存盘和读盘函数,可以选择留空,或者在{}里输入你想输入的数,比如return false;等
也可以设置参数。
1.2定义边
class CurveFittingEdge: public g2o::BaseUnaryEdge<1,double,CurveFittingVertex>
{
public:
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
CurveFittingEdge( double x ): BaseUnaryEdge(), _x(x) {}
// 计算曲线模型误差
void computeError()
{
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 bool read( istream& in ) {}
virtual bool write( ostream& out ) const {}
public:
double _x; // x 值, y 值为 _measurement
};
可操作的:边类名,边的顶点数,边数据类型,和边顶点类型。也就是g2o::BaseUnaryEdge<>中的内容。
CurveFittingEdge( double x ): BaseUnaryEdge(), _x(x) {}这个是类赋值,可以有,也可以没有,如果有,那么要定义参数_x,因为这里是把x赋值给_x.
最重要的就是计算误差函数computeError(),具体操作在{},主要是要给出_error的具体形式。
一般赋值_vertices[i]给顶点,比如v或者v1,v2等。这里v的类型就是之前我们定义的顶点类的指针。一般是这样定义的
const 顶点类* v=static_cast<const 顶点类*>(_vertices[0])
要么把v->estimate估计值传给新的值,要么直接用来计算误差值。误差值的是由测量值_measuremen减去预测值得到的,预测值是根据v->estimate得到的,具体怎么得按实际情况来。
还有linearizeOplus函数,这个函数是求雅克比矩阵,也可以没有这个函数。雅克比矩阵也就是误差函数对顶点的求导值。不是范数啊。
过程:先把_vertices[0],_vertices[1]等赋值给顶点,跟computeError函数里一模一样,也是
const 顶点类* 顶点名=static_cast<const 顶点类*>(_vertices[0]);
是跟computeError函数里重名的。
也会用到顶点的估计值来计算出雅克比矩阵的每一项的值。一般都是
_jacobianOplusXi(i,j)=;
2.定义图模型
typedef g2o::BlockSolver< g2o::BlockSolverTraits<3,1> > Block; // 每个误差项优化变量维度为3,误差值维度为1
Block::LinearSolverType* linearSolver = new g2o::LinearSolverDense<Block::PoseMatrixType>(); // 线性方程求解器
Block* solver_ptr = new Block( linearSolver ); // 矩阵块求解器
// 梯度下降方法,从GN, LM, DogLeg 中选
g2o::OptimizationAlgorithmLevenberg* solver = new g2o::OptimizationAlgorithmLevenberg( solver_ptr );
// g2o::OptimizationAlgorithmGaussNewton* solver = new g2o::OptimizationAlgorithmGaussNewton( solver_ptr );
// g2o::OptimizationAlgorithmDogleg* solver = new g2o::OptimizationAlgorithmDogleg( solver_ptr );
g2o::SparseOptimizer optimizer; // 图模型
optimizer.setAlgorithm( solver ); // 设置求解器
optimizer.setVerbose( true ); // 打开调试输出
上面的基本就是套路了。
自己操作的是定义自己的误差项的优化变量的维度,还有误差值的维度,就是g2o::BlockSolverTraits<> 里的两个值。
线性方程求解器如果是提取特征点之类的用Dense,稠密的,如果是要进行消元什么的,用Cholmod.
优化算法一般用的都是列文伯格,也可以用高斯牛顿等。
过程就是由线性方程求解器linearSolver得到矩阵块求解器solver_ptr,由矩阵块求解器得到梯度下降方法solver,图模型再设置算法为solver.

2.1图模型添加顶点
CurveFittingVertex* v = new CurveFittingVertex();
v->setEstimate( Eigen::Vector3d(0,0,0) );
v->setId(0);
optimizer.addVertex( v );
一般的模式就是先设置顶点,如果是多于一个顶点的话,以顶点数量为最大值做一个for循环,在for循环里,设置顶点,顶点估计值,顶点id,是否可以边缘化,也就是之后要不要进行消元,图模型添加边。形式如下
顶点类* v=new 顶点类();要有一个括号,如果有输入值的话,可以放在括号里。
v->setId(i);
v->setEstimate();//估计值如果有初值,就添加上,如果没有,就设成和顶点类型相同的,并且设为0.如果顶点中update被重写,那么估计值类型和顶点类型不一致
v->setMarginlized(true);//默认false,需要设置的时候都是true
optimizer.addVertex(v)
注意顶点和边都是指针,所以用->访问。
2.2图模型添加边
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 );
}
根据边的数量做一个for循环,先设置边。然后边要设置id,顶点,测量值,信息矩阵,图模型添加边。
形式如下,设边名称为edge的话
边类* edge=new 边类();
edge->setId(j);
edge->setVertex(0,v);
edge->setMeasurement();测量值是必须得有的,视具体情况而定。
edge->setInformation();设置信息矩阵,信息矩阵是协方差矩阵的逆,所以也可以称之为设置协方差矩阵。
edge->setParameterId();//一般没有这一项
optimizer->addEdge(edge);

2.3图模型求解
optimizer.initializeOptimization();
optimizer.optimize(100);
直接就这两句就可以了。
optimize()括号内的数值可以修改。

时间: 2024-10-27 05:02:14

g2o的一般过程的相关文章

一起做RGB-D SLAM(8) (关于调试与补充内容)

“一起做”系列完结后,我收到不少同学给我的反馈.他们提了一些在程序编译/运行过程中的问题.我把它们汇总起来,组成了这个“补充篇”.你也可以看成是一个Q&A. Q: OpenCV的版本?A: 我用的是2.4.9.可以使用2.4系列,不会有太大差别.而3.0系列则在接口上有一些明显的改动,可能需要修改源码. Q: 第二讲的点云如何查看?A: 使用pcl_viewer.当点云显示时,先用r键复位视角,再用鼠标调整. Q: 如何调试代码?A: 可以在源程序里用cout, cerr输出,善用linux的管

视觉SLAM漫淡(二):图优化理论与g2o的使用

视觉SLAM漫谈(二):图优化理论与g2o的使用 1    前言以及回顾 各位朋友,自从上一篇<视觉SLAM漫谈>写成以来已经有一段时间了.我收到几位热心读者的邮件.有的希望我介绍一下当前视觉SLAM程序的实用程度,更多的人希望了解一下前文提到的g2o优化库.因此我另写一篇小文章来专门介绍这个新玩意. 在开始本篇文章正文以前,我们先来回顾一下图优化SLAM问题的提法.至于SLAM更基础的内容,例如SLAM是什么东西等等,请参见上一篇文章.我们直接进入较深层次的讨论.首先,关于我们要做的事情,你

g2o求解BA 第10章

1.g2o_bal_class.h1.1 projection.hg2o还是用图模型和边,顶点就是相机和路标,边就是观测,就是像素坐标.只不过这里的相机是由旋转(3个参数,轴角形式,就是theta*nx,theta*ny,theta*ny),位移(3个参数),f,k1,k2.就是之前BA模型的实现.但是这里归一化平面坐标取得是负值,而且最后没有加cx,cy.具体实现在projection.h中的CamProjectionWithDistortion函数实现的,而其中世界坐标转成相机坐标是由rot

关于SLAM的那些事——通用图优化(G2O)环境搭配(windows8.1 vs2013)

好久不见啊各位亲,最近刚中期答辩完,得以有时间好好更新下博客啦. 自从上一个单目AR系统做完后,就仔细思考了一下我到底在做什么,接下来要做什么.之前博客上写的是3d重建,后来视野开阔了之后发现无论我做3d重建,SLAM,AR,重要的都是姿态更新.一个精准的稳定的姿态更新,决定着系统的好坏.贝叶斯滤波器(EKF扩展卡尔曼滤波,PF粒子滤波)和通用图优化(G2O)是使得姿态更加精准稳定的两种方法.近些年来G2O在视觉SLAM领域逐渐成为了主流的后端优化方法. 具体的视觉SLAM流程和G2O的相关知识

g2o的使用

相关文献 1.论文 Grisetti, Giorgio, et al. "A tutorial on graph-based SLAM." IEEE Intelligent Transportation Systems Magazine 2.4 (2010): 31-43. pdf 2.论文 Kümmerle, Rainer, et al. "g2o: A general framework for graph optimization." Robotics and

ORB_SLAM2在Android上的移植过程

作者:Frank 转载请注明出处 一直没时间写博客,最近抽时间写了些关于在ORB_SLAM2在Android上的移植过程,也算是点经验吧. 写完后一个手贱点了个链接,瞬间1/3工作量没了,深夜弄完也是醉了... 正文开始 这篇博客讲述如何在Android平台上移植ORB_SLAM2,讲述过程包括基本的Android环境的搭建和NDK环境的配置,Android下移植的基本概念,ORB的具体移植步骤等. Android平台搭建和NDK环境配置 系统:windows7 32bit IDE:Eclips

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

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

关于RGBDSLAMV2学习、安装、调试过程

Step1:https://github.com/felixendres/rgbdslam_v2/wiki/Instructions-for-Compiling-Rgbdslam-(V2)-on-a-Fresh-Ubuntu-16.04-Install-(Ros-Kinetic)-in-Virtualbox 照着这个instructions安装好 rgbdslamv2,并且在安装的过程中,后续要用的依赖也已经安装好了 Step2:https://www.twblogs.net/a/5c542fd

G2O框架

(一)简介: g2o简称General Graphic Optimization,是一个用来优化非线性误差函数的c++框架 (二)g2o基本框架 1: SparseOptimizer SparseOptimizer是整个图的核心,我们注意右上角的 is-a 实心箭头,这个SparseOptimizer它是一个Optimizable Graph,从而也是一个超图(HyperGraph) 其中超图(HyperGraph)包括多个边与顶点;SparseOptimizer包括一个优化算法 2: 定点与边