Ceres-Solver 从入门到上手视觉SLAM位姿优化问题
Last updated on May 7, 2023 pm
概述
Ceres Solver is an open source C++ library for modeling and solving large, complicated optimization problems.
使用 Ceres Solver 求解非线性优化问题,主要包括以下几部分:
构建代价函数(cost function) 或 残差(residual)
构建损失函数(loss function)
- 构建优化问题(
ceres::Problem
):通过AddResidualBlock
添加代价函数(cost function)、损失函数(loss function) 和 待优化状态量- LossFunction: a scalar function that is used to reduce the influence of outliers on the solution of non-linear least squares problems.
配置求解器(
ceres::Solver::Options
)运行求解器(
ceres::Solve(options, &problem, &summary)
)
注意:
Ceres Solver 只接受最小二乘优化,也就是 \(\min r^T r\);若要对残差加权重,使用马氏距离,即 \(\min r^T P^{-1} r\),则要对 信息矩阵\(P^{-1}\) 做 Cholesky分解,即 \(LL^T=P^{−1}\),则 \(d = r^T (L L^T) r = (L^T r)^T (L^T r)\),令 \(r' = (L^T r)\),最终 \(\min r'^T r'\)。
入门
先以最小化下面的函数为例,介绍 Ceres Solver 的基本用法
\[ \frac{1}{2} (10 - x)^2 \]
Part 1: Cost Function
AutoDiffCostFunction
- 构造 代价函数结构体(例如:
struct CostFunctor
),在其结构体内对 模板括号()
重载,定义残差 在重载的
()
函数 形参 中,最后一个为残差,前面几个为待优化状态量1
2
3
4
5
6
7struct CostFunctor {
template<typename T>
bool operator()(const T *const x, T *residual) const {
residual[0] = 10.0 - x[0]; // r(x) = 10 - x
return true;
}
};创建代价函数的实例,对于模板参数的数字,第一个为残差的维度,后面几个为待优化状态量的维度
1
2ceres::CostFunction *cost_function;
cost_function = new ceres::AutoDiffCostFunction<CostFunctor, 1, 1>(new CostFunctor);
NumericDiffCostFunction
数值求导法 也是构造 代价函数结构体,但在重载 括号
()
时没有用模板1
2
3
4
5
6struct CostFunctorNum {
bool operator()(const double *const x, double *residual) const {
residual[0] = 10.0 - x[0]; // r(x) = 10 - x
return true;
}
};并且在实例化代价函数时也稍微有点区别,多了一个模板参数
ceres::CENTRAL
1
2
3ceres::CostFunction *cost_function;
cost_function =
new ceres::NumericDiffCostFunction<CostFunctorNum, ceres::CENTRAL, 1, 1>(new CostFunctorNum);
自定义 CostFunction
- 构建一个 继承自
ceres::SizedCostFunction<1,1>
的类,同样,对于模板参数的数字,第一个为残差的维度,后面几个为待优化状态量的维度 - 重载 虚函数
virtual bool Evaluate(double const* const* parameters, double *residuals, double **jacobians) const
,根据 待优化变量,实现 残差和雅克比矩阵的计算
1 |
|
Part 2: Loss Function
- http://ceres-solver.org/nnls_modeling.html#lossfunction
1 |
|
e.g.: CauchyLoss
\[ \rho(s) = \log(1+s) \]
1 |
|
Part 3: AddResidualBlock
- 声明
ceres::Problem problem;
- 通过
AddResidualBlock
将 代价函数(cost function)、损失函数(loss function) 和 待优化状态量 添加到problem
1 |
|
Part 4: Config & Solve
配置求解器,并计算,输出结果
1 |
|
Simple Example Code
1 |
|
应用: 基于李代数的视觉SLAM位姿优化
下面以 基于李代数的视觉SLAM位姿优化问题 为例,介绍 Ceres Solver 的使用。
(1)残差(预测值 - 观测值)
\[ r(\xi) = K \exp({\xi}^{\wedge}) P - u \]
(2)雅克比矩阵
\[ \begin{aligned} J &= \frac{\partial r(\xi)}{\partial \xi} \\ &= \begin{bmatrix} \frac{f_x}{Z'} & 0 & -\frac{X'f_x}{Z'^2} & -\frac{X'Y'f_x}{Z'^2} & f_x+\frac{X'^2f_x}{Z'^2} & -\frac{Y'f_x}{Z'} \\ 0 & \frac{f_y}{Z'} & -\frac{Y'f_y}{Z'^2} & -f_y-\frac{Y'^2f_y}{Z'^2} & \frac{X'Y'f_y}{Z'^2} & \frac{X'f_y}{Z'} \end{bmatrix} \in \mathbb{R}^{2 \times 6} \end{aligned} \]
- 雅克比矩阵的具体求导,可参考我的另一篇博客 视觉SLAM位姿优化时误差函数雅克比矩阵的计算
(3)核心代码
代价函数的构造:
1 |
|
构造优化问题,并求解相机位姿:
1 |
|