当前位置:网站首页>使用Ceres进行slam必须要弄清楚的几个类和函数
使用Ceres进行slam必须要弄清楚的几个类和函数
2022-07-06 18:23:00 【月照银海似蛟龙】
使用Ceres进行slam必须要弄清楚的几个类和函数
Ceres solver 是谷歌开发的一款用于非线性优化的库,在谷歌的开源激光雷达slam项目cartographer中被大量使用。
在之前的博客说了,图优化的本质就是一个非线性优化问题.所以ceres刚好适用图优化问题的解决.
在进行特征点匹配后进行迭代的优化最优变换位姿时也可以使用ceres.
ceres简介
Ceres可以解决边界约束鲁棒非线性最小二乘法优化问题。这个概念可以用以下表达式表示:
这一表达式在工程和科学领域有非常广泛的应用。比如统计学中的曲线拟合,或者在计算机视觉中依据图像进行三维模型的构建等等。
注意这个公式里面各模块有几个特殊的概念要熟知,涉及到具体的使用:
残差块(ResidualBlock):
这一部分被称为残差块(ResidualBlock).
代价函数(CostFunction):
这一部分被称为代价函数(CostFunction).
参数块(ParameterBlock):
代价函数依赖于一系列参数,这一系列参数(均为标量)称为参数块(ParameterBlock).当然参数块中也可以只含有一个变量
上下边界:
lj和uj是xj的上下边界.
损失函数(LossFunction):
pi是损失函数(LossFunction).按照损失函数的是一个标量函数,其作用是减少异常值(Outliers)对优化结果的影响。其效果类似于对函数的过滤。
ceres的使用流程
1.构建代价函数(cost function)
2.通过代价函数构建待求解的优化问题
3.配置求解器参数并求解问题
ceres必须要知道的类和函数
class LossFunction
class LossFunction 损失函数
最小二乘问题的输入数据可能包含异常值(错误测量得到的),使用损失函数减少这部分数据的影响。
比如说当一个移动相机的场景中,街道上有消防栓和汽车,当图像的处理算法把消防栓的尖和汽车的前灯匹配在了一起,那么如果不做任何处理,则会导致ceres为使这个错误的大的误差减小,而是优化结果偏离正确位置.
LossFunction可以让大的残差的权重降低,从而对 最终的优化结果没有太大的影响.
class LossFunction {
public:
virtual void Evaluate(double s, double out[3]) const = 0;
};
LossFunction的类,关键的函数就是 LossFunction::Evaluate()
一个非负的参数s,计算输出
Ceres包含了几种定义好的损失函数,都是没有缩放的.具体效果如下图所示:
图中红色的就是没有经过损失函数的,y=x*x.蓝色的是HuberLoss,值低于正常值,并且x越大,效果越明显.
正常的是:
HuberLoss是:
SoftLOneLoss是:
CauchyLoss是:
ArctanLoss是:
TolerantLoss是:
用定义好的损失函数使用也很简单.例如:
ceres::LossFunction *loss_function = new ceres::HuberLoss(0.1);
定义ceres 的 损失函数 0.1代表 残差大于0.1的点 ,则权重降低,具体效果看上面的公式. 小于0.1 则认为正常,不做特殊的处理
定义好后,在添加残差
LocalParameterization
LocalParameterization 本地参数
在许多优化问题中,尤其是传感器融合问题中,必须对存在于称为流形的空间中的量进行建模,例如由四元数表示的传感器的旋转/方向。
Ceres定义了一些特殊的参数,对于slam,用的更多的就是旋转的四元数
QuaternionParameterization
EigenQuaternionParameterization
定义两个主要的原因就是Eigen的存储四元数的方式和一般的不同,Eigen是x,y,z,w,实数部分的w放在最后,一般的则是:w,x,y,z.
使用
double para_q[4] = {
0, 0, 0, 1};
ceres::LocalParameterization *q_parameterization =
new ceres::EigenQuaternionParameterization();
problem.AddParameterBlock(para_q, 4, q_parameterization);
class problem
problem类就是代表者具有双边约束的最小二乘问题
为了创建一个最小二乘问题,需要使用
Problem::AddResidalBlock() 添加残差模块
Problem::AddParameterBlock() 添加参数模块
这两个方法
举个例子,一个问题包含三个参数模块,尺寸分别是3,4,5,两个残差模块尺寸分别是2和6
double x1[] = {
1.0, 2.0, 3.0 };
double x2[] = {
1.0, 2.0, 3.0, 5.0 };
double x3[] = {
1.0, 2.0, 3.0, 6.0, 7.0 };
Problem problem;
problem.AddResidualBlock(new MyUnaryCostFunction(...), x1);
problem.AddResidualBlock(new MyBinaryCostFunction(...), x2, x3);
方法Problem::AddResidualBlock(),和名字一样,功能就是添加参数模块到problem中,这个方法必须有参数CostFunction和可选参数LossFunction,这个方法就连接了CostFunction和参数模块.
CostFunction 具有它希望的参数块尺寸的信息.
这个函数检查这些是否与 parameter_blocks 中列出的参数块的大小相匹配 .如果检测到错误的匹配,程序会终止.
LossFunction 可以有,也可以没有
可以使用Problem::AddParameterBlock() 这个方法来添加参数模块,这个会添加一次参数尺寸的检测.将参数块显式添加到问题中。 还允许将 Manifold 对象与参数块相关联。
这个函数可以用带LocalParameterization的参数,也可以不带.
problem.AddParameterBlock(para_q, 4, q_parameterization);// 添加四元数的参数块
problem.AddParameterBlock(para_t, 3);//添加平移的参数块
声明的时候一般这样:
ceres::Problem::Options problem_options;
ceres::Problem problem(problem_options);
先声明一个ceres::Problem::Options,然后再用Options初始化problem
class CostFunction
代价函数CostFunction 负责计算残差向量和雅克比矩阵.
代价函数依赖参数块
其内部定义是这样的
class CostFunction {
public:
virtual bool Evaluate(double const* const* parameters,
double* residuals,
double** jacobians) = 0;
const vector<int32>& parameter_block_sizes();
int num_residuals() const;
protected:
vector<int32>* mutable_parameter_block_sizes();
void set_num_residuals(int num_residuals);
};
这部分不用太管,因为使用的时候用其它类定义的这个类的内部
定义 CostFunction 或 SizedCostFunction 可能容易出错,尤其是在计算导数时。 为此,Ceres 提供了自动微分。
class AutoDiffCostFunction
定义 CostFunction 或 SizedCostFunction 可能容易出错,尤其是在计算导数时。 为此,Ceres 提供了自动微分。
template <typename CostFunctor,
int kNumResiduals, // Number of residuals, or ceres::DYNAMIC.
int... Ns> // Size of each parameter block
class AutoDiffCostFunction : public SizedCostFunction<kNumResiduals, Ns> {
public:
AutoDiffCostFunction(CostFunctor* functor, ownership = TAKE_OWNERSHIP);
// Ignore the template parameter kNumResiduals and use
// num_residuals instead.
AutoDiffCostFunction(CostFunctor* functor,
int num_residuals,
ownership = TAKE_OWNERSHIP);
};
得到一个可以自动求导的代价函数,必须定义一个类或者结构体在里面重载运算符,在里面实现用参数模板计算代价函数,重载的运算符必须在最后一个参数里存入计算结果,并且返回true.
举个例子,要计算 一个 代价函数是 e= k - xTy.
x和y是二维的向量,k是一个不变的参数.
那么可以定义一个这样的类
class MyScalarCostFunctor {
MyScalarCostFunctor(double k): k_(k) {
}
template <typename T>
bool operator()(const T* const x , const T* const y, T* e) const {
e[0] = k_ - x[0] * y[0] - x[1] * y[1];
return true;
}
private:
double k_;
};
在重载运算符的定义里面.参数x和y在前面,如果有更多的输入参数,则继续可以排在y后面,输出也就是残差放在最后一个参数,
给定这个类的定义之后,它的自动微分代价函数可以定义如下:
CostFunction* cost_function
= new AutoDiffCostFunction<MyScalarCostFunctor, 1, 2, 2>(
new MyScalarCostFunctor(1.0)); ^ ^ ^
| | |
Dimension of residual ------+ | |
Dimension of x ----------------+ |
Dimension of y -------------------+
上面的1,2,2 就是注释的那样,计算1维的残差,2个2维的优化量
边栏推荐
- Get to know MySQL for the first time
- Appium automation test foundation uiautomatorviewer positioning tool
- 使用nodejs完成判断哪些项目打包+发版
- When grep looks for a process, it ignores the grep process itself
- JS ES5也可以创建常量?
- ROS learning (XX) robot slam function package -- installation and testing of rgbdslam
- MySQL最基本的SELECT(查询)语句
- JVM memory model
- HDU 4661 message passing (wood DP & amp; Combinatorics)
- ROS学习(24)plugin插件
猜你喜欢
2022/0524/bookstrap
dvajs的基础介绍及使用
Flir Blackfly S USB3 工业相机:白平衡设置方法
刨析《C语言》【进阶】付费知识【完结】
ROS learning (XX) robot slam function package -- installation and testing of rgbdslam
Correct use of BigDecimal
Centros 8 installation MySQL Error: The gpg Keys listed for the "MySQL 8.0 Community Server" repository are already ins
The GPG keys listed for the "MySQL 8.0 community server" repository are already ins
C语言关于链表的代码看不懂?一篇文章让你拿捏二级指针并深入理解函数参数列表中传参的多种形式
Modify the system time of Px4 flight control
随机推荐
Public key \ private SSH avoid password login
dvajs的基础介绍及使用
454 Baidu Mianjing 1
Blue Bridge Cup 2022 13th provincial competition real topic - block painting
2022 system integration project management engineer examination knowledge point: Mobile Internet
centos8安裝mysql報錯:The GPG keys listed for the “MySQL 8.0 Community Server“ repository are already ins
Ds-5/rvds4.0 variable initialization error
sql中批量删除数据---实体中的集合
Baidu flying general BMN timing action positioning framework | data preparation and training guide (Part 2)
Modify the system time of Px4 flight control
Blackfly S USB3工业相机:缓冲区处理
Command injection of cisp-pte
Gin introduction practice
Today's question -2022/7/4 modify string reference type variables in lambda body
Batch delete data in SQL - set in entity
npm install 编译时报“Cannot read properties of null (reading ‘pickAlgorithm‘)“
AcWing 344. Solution to the problem of sightseeing tour (Floyd finding the minimum ring of undirected graph)
Curl command
Shell script quickly counts the number of lines of project code
Golang foundation - data type