首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

SLAM从0到1——图优化g2o:从看懂代码到动手编写(长文)

精选作品,第一时间送达

「本文介绍了对g2o代码框架解读,以及如何自主设计顶点和边(代码)」

g2o(General Graphic Optimization)是一个通用图优化算法库。由于目前主流的SLAM研究基本都是基于优化的,因此十分有必要掌握g2o方法。

关于g2o的基本理论并不高深,在SLAM中应用g2o的难点主要是在代码实现上(作为入门小白,代码经常看的一脸懵)。

特别需要记住的是:

图优化中的点是相机位姿,也就是优化变量(状态变量)

图优化中的边是指位姿之间的变换关系,通常表示误差项

下图为官方文档中经典的g2o框架:

对这个结构框图做一个简单介绍(注意图中三种箭头的含义(右上角注解)):

(1)整个g2o框架可以分为上下两部分,两部分中间的连接点:SparseOpyimizer 就是整个g2o的核心部分。

(2)往上看,SparseOpyimizer其实是一个Optimizable Graph,从而也是一个超图(HyperGraph)。

(3)超图有很多顶点和边。顶点继承自 Base Vertex,也即OptimizableGraph::Vertex;而边可以继承自 BaseUnaryEdge(单边), BaseBinaryEdge(双边)或BaseMultiEdge(多边),它们都叫做OptimizableGraph::Edge。

(4)往下看,SparseOptimizer包含一个优化算法部分OptimizationAlgorithm,它是通过OptimizationWithHessian 来实现的。其中迭代策略可以从Gauss-Newton(高斯牛顿法,简称GN)、 Levernberg-Marquardt(简称LM法),、Powell's dogleg 三者中间选择一个(常用的是GN和LM)。

(5)对优化算法部分进行求解的是求解器solver,它实际由BlockSolver组成。BlockSolver由两部分组成:一个是SparseBlockMatrix,它由于求解稀疏矩阵(雅克比和海塞);另一个部分是LinearSolver,它用来求解线性方程得到待求增量,因此这一部分是非常重要的,它可以从PCG/CSparse/Choldmod选择求解方法。

我们再来看一下框架的搭建步骤,以高博在SLAM十四讲中使用g2o求解曲线参数为例(注意注释):

如程序中所示,编写一个图优化的程序需要从底层到顶层逐渐搭建,参照g2o官方框架图(上方),步骤可以分为6步

创建一个线性求解器LinearSolver。

创建BlockSolver,并用上面定义的线性求解器初始化。

创建总求解器solver,并从GN/LM/DogLeg 中选一个作为迭代策略,再用上述块求解器BlockSolver初始化。

创建图优化的核心:稀疏优化器(SparseOptimizer)。

定义图的顶点和边,并添加到SparseOptimizer中。

设置优化参数,开始执行优化。

各个步骤:

(1)创建一个线性求解器LinearSolver

这一步中我们可以选择不同的求解方式来求解线性方程,g2o中提供的求解方式主要有:

LinearSolverCholmod :使用sparse cholesky分解法,继承自LinearSolverCCS。

LinearSolverCSparse:使用CSparse法,继承自LinearSolverCCS。

LinearSolverPCG :使用preconditioned conjugate gradient 法,继承自LinearSolver。

LinearSolverDense :使用dense cholesky分解法,继承自LinearSolver。

LinearSolverEigen:依赖项只有eigen,使用eigen中sparse Cholesky 求解,因此编译好后可以方便的在其他地方使用,性能和CSparse差不多,继承自LinearSolver。

可以对照上面程序的代码去看求解方式在哪里设置。

(2)创建BlockSolver,并用定义的线性求解器初始化

BlockSolver有两种定义方式:

此外g2o还预定义了以下几种常用类型:

BlockSolver_6_3 :表示pose 是6维,观测点是3维,用于BA。

BlockSolver_7_3:在BlockSolver_6_3 的基础上多了一个scale。

BlockSolver_3_2:表示pose 是3维,观测点是2维。

(3)创建总求解器solver

注意看程序中只使用了一行代码进行创建:右侧是初始化;左侧含有我们选择的迭代策略,在这一部分,我们有三迭代策略可以选择:

g2o::OptimizationAlgorithmGaussNewton

g2o::OptimizationAlgorithmLevenberg

g2o::OptimizationAlgorithmDogleg

(4)创建图优化的核心:稀疏优化器

根据程序中的代码示例,创建稀疏优化器:

设置求解方法:

设置优化过程输出信息:

(5)定义图的顶点和边,并添加到SparseOptimizer中

看下面的具体讲解。

(6)设置优化参数,开始执行优化

设置SparseOptimizer的初始化、迭代次数、保存结果等。

初始化:

设置迭代次数:

下面专门讲讲第5步:定义图的顶点和边。这一部分是比较重要且比较难的部分,但是如果要入门g2o,这又是必不可少的一部分。

点 Vertex

在g2o中定义Vertex有一个通用的类模板:BaseVertex。在结构框图中可以看到它的位置就是HyperGraph继承的根源。

同时在图中我们注意到BaseVertex具有两个参数D/T,这两个参数非常重要,我们来看一下:

D 是int 类型,表示vertex的最小维度,例如3D空间中旋转是3维的,则 D = 3

T 是待估计vertex的数据类型,例如用四元数表达三维旋转,则 T 就是Quaternion 类型

特别注意的是这个D不是顶点(状态变量)的维度,而是其在流形空间(manifold)的最小表示。

如何自己定义Vertex

在我们动手定义自己的Vertex之前,可以先看下g2o本身已经定义了一些常用的顶点类型:

但是!如果在使用中发现没有我们可以直接使用的Vertex,那就需要自己来定义了。一般来说定义Vertex需要重写这几个函数(注意注释):

请注意里面的oplusImpl函数,是非常重要的函数,主要用于优化过程中增量△x 的计算。根据增量方程计算出增量后,通过这个函数对估计值进行调整,因此该函数的内容要重视。

根据上面四个函数可以得到定义顶点的基本格式:

如果还不太明白,那么继续看下面的实例:

另外值得注意的是,优化变量更新并不是所有时候都可以像上面两个一样直接 += 就可以,这要看优化变量使用的类型(是否对加法封闭)。

向图中添加顶点

接着上面定义完的顶点,我们把它添加到图中:

三个步骤对应三行代码,注释已经解释了作用。

2. 边 Edge

图优化中的边:BaseUnaryEdge,BaseBinaryEdge,BaseMultiEdge 分别表示一元边,两元边,多元边。

顾名思义,一元边可以理解为一条边只连接一个顶点,两元边理解为一条边连接两个顶点(常见),多元边理解为一条边可以连接多个(3个以上)顶点。

以最常见的二元边为例分析一下他们的参数:D, E, VertexXi, VertexXj:

D 是 int 型,表示测量值的维度 (dimension)

E 表示测量值的数据类型

VertexXi,VertexXj 分别表示不同顶点的类型

上面这行代码表示二元边,参数1是说测量值是2维的;参数2对应测量值的类型是Vector2D,参数3和4表示两个顶点也就是优化变量分别是三维点 VertexSBAPointXYZ,和李群位姿VertexSE3Expmap。

如何定义一个边

除了上面那行定义语句,还要复写一些重要的成员函数:

除了上面四个函数,还有几个重要的成员变量以及函数:

有了上面那些重要的成员变量和成员函数,就可以用来定义一条边了:

让我们继续看curveftting这个实例,这里定义的边是简单的一元边:

上面的例子都比较简单,下面这个是3D-2D点的PnP 问题,也就是最小化重投影误差问题,这个问题非常常见,使用最常见的二元边,弄懂了这个跟边相关的代码就能懂了:

这个程序中比较难以理解的地方是:

cam_map 函数功能是把相机坐标系下三维点(输入)用内参转换为图像坐标(输出)。

map函数是把世界坐标系下三维点变换到相机坐标系。

v1->estimate().map(v2->estimate())意思是用V1估计的pose把V2代表的三维点,变换到相机坐标系下。

向图中添加边

和添加点有一点类似,下面是添加一元边:

在SLAM中我们经常要使用的二元边(前后两个位姿),那么此时:

至此,就介绍完了g2o中的一些框架和实现,需要提醒的是在SLAM中我们常常用到的是二元边以及对应的点,他们都较为复杂,应当多次学习复习实践。

下载1:OpenCV-Contrib扩展模块中文版教程

下载2:Python视觉实战项目31讲

下载3:OpenCV实战项目20讲

交流群

上述内容若有侵犯版权,请联系后台。

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20210202A02Q4S00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券