代码中q是待优化的单位四元数;在2.1版本及以前,cere支持调用ceres提供的LocalParameterization
方法和QuaternionParameterization
即可。
/ 上略 /
// Build the problem.
double q[4];
ceres::Problem problem;
/****************************************/
/* 省略调用AddResidualBlock() q是参数之一*/
/****************************************/
ceres::LocalParameterization* quaternion_parameterization = new ceres::QuaternionParameterization;
problem.SetParameterization(q, quaternion_parameterization);
/ 下略 //
2.2版本开始,LocalParameterization
方法不可用,需要用Manifold
替代:
/ 上略 /
// Build the problem.
double q[4];
ceres::Problem problem;
/****************************************/
/* 省略调用AddResidualBlock() q是参数之一*/
/****************************************/
ceres::Manifold* quaternion_manifold = new ceres::QuaternionManifold;
problem.SetManifold(q, quaternion_manifold);
/ 下略 //
LocalParameterization
和Manifold
是什么?在最优化问题求解时,迭代的每一步都要更新所有的参数。绝大多数参数的更新都比较简单,直接加上或者减去更新量
d
v
dv
dv即可,例如从一堆二维数据点拟合直线时的直线参数更新;而四元数(单位四元数)作为姿态参数的一种表达形式,其更新不能简单的加减:因为两个单位四元数的和一般不能保持是单位四元数。所以,四元数的更新应该用乘法完成。LocalParameterization
或Manifold
就是做这个的,当你添加了一个四元数作为待优化参数后,还应该告诉解算器,这个参数需要特殊处理,其“加”“减”不能直接进行,四元数所在的Manifold
上的“加减”按照下面的原则:
⊞ ( x , Δ ) = exp ( Δ ) ⊗ x ⊟ ( y , x ) = log ( y ⊗ x − 1 ) \begin{split}\begin{align*} \boxplus(x, \Delta) &= \exp\left(\Delta\right) \otimes x \\ \boxminus(y,x) &= \log\left(y \otimes x^{-1}\right) \end{align*}\end{split} ⊞(x,Δ)⊟(y,x)=exp(Δ)⊗x=log(y⊗x−1)
其中, ⊗ \otimes ⊗是四元数乘法; ⊞ \boxplus ⊞是“加法”, ⊟ \boxminus ⊟是“减法”;对 Δ ∈ R 3 \Delta\in \mathbb{R}^3 Δ∈R3,
exp
(
Δ
)
=
[
cos
(
∥
Δ
∥
)
sin
(
∣
Δ
∥
)
∥
Δ
∥
Δ
]
\begin{split}\exp(\Delta) = \left[ \begin{matrix} \cos\left(\|\Delta\|\right)\\ \frac{\displaystyle \sin\left(|\Delta\|\right)}{\displaystyle \|\Delta\|} \Delta \end{matrix} \right]\end{split}
exp(Δ)=[cos(∥Δ∥)∥Δ∥sin(∣Δ∥)Δ]
以及,对于单位四元数
q
q
q,
log
(
q
)
=
atan2
(
1
−
q
0
2
,
q
0
)
1
−
q
0
2
[
q
1
,
q
2
,
q
3
]
\log(q) = \frac{\operatorname{atan2}\left(\sqrt{1-q_0^2},q_0\right)}{\sqrt{1-q_0^2}} \left [\begin{matrix}q_1,& q_2,& q_3\end{matrix}\right]
log(q)=1−q02atan2(1−q02,q0)[q1,q2,q3]