Manifold

class Manifold

在多传感器融合问题中,我们经常需要对处在流形上的量进行建模和参数化,例如使用四元数表示的旋转。流形空间在局部类似于欧式空间,更确切地说,在流形上的每一点都有一个与流形相切的线性空间。它的维度等于流形本身的内在维度,小于或等于流形所嵌入的局部空间。注意:ambient space没找到准确的翻译,这里翻译为局部空间 或者叫做 本地空间

例如,三维球面上一点的切空间是与球面在该点相切的二维平面(如李群与李代数)。切线空间之所以有趣,有两个原因:

  • 它们是欧几里得空间,因此适用于通常的向量空间运算,这使得数值运算变得简单。

  • 切线空间中的运动转化为沿流形的运动。垂直于切线空间的运动不会转化为流形上的运动。

然而,沿着与球面相切的二维平面移动并投影到球面上会使你远离起始点,但沿着同一点的法线移动并投影到球面上会使你回到起始点。除了数学上的有点之外,正确的对流行进行数值上的建模并关注其几何特征对实际使用也有很大帮助。

  • 在整个优化过程中,它自然而然地将变量约束在流形上,使用户无需再使用四元数归一化等技巧。

  • 它将优化问题的维度缩小到自然大小。例如,一个限制在一条线上的量是一个一维对象,而不管这条线所处的局部空间的维度是多少。

  • 在切线空间工作不仅能降低优化算法的计算复杂度,还能改善算法的数值表现。

其中

其中

有:

class Manifold {
 public:
  virtual ~Manifold();
  virtual int AmbientSize() const = 0;
  virtual int TangentSize() const = 0;
  virtual bool Plus(const double* x,
                    const double* delta,
                    double* x_plus_delta) const = 0;
  virtual bool PlusJacobian(const double* x, double* jacobian) const = 0;
  virtual bool RightMultiplyByPlusJacobian(const double* x,
                                           const int num_rows,
                                           const double* ambient_matrix,
                                           double* tangent_matrix) const;
  virtual bool Minus(const double* y,
                     const double* x,
                     double* y_minus_x) const = 0;
  virtual bool MinusJacobian(const double* x, double* jacobian) const = 0;
};
int Manifold::AmbientSize() const;

流形嵌入到的局部空间维度。比如在用四元数表示时其值为 4。对应老版本 Ceres 的 GlobalSize()。

int Manifold::TangentSize() const;

流形空间上的维度,或者说切空间中的维度。

bool Plus(const double *x, const double *delta, double *x_plus_delta) const;
bool PlusJacobian(const double *x, double *jacobian) const;
bool RightMultiplyByPlusJacobian(const double *x, 
                                 const int num_rows, 
                                 const double *ambient_matrix, 
                                 double *tangent_matrix) const;

This function is only used by the GradientProblemSolver, where the dimension of the parameter block can be large and it may be more efficient to compute this product directly rather than first evaluating the Jacobian into a matrix and then doing a matrix vector product.

由于这个函数并不常用,为了方便起见,Ceres 提供了一个默认实现。如果考虑性能,那么用户应该考虑自行实现一个。

bool Minus(const double *y, const double *x, double *y_minus_x) const;
bool MinusJacobian(const double *x, double *jacobian) const = 0;

Ceres 提供了大量的实际中经常用到的 Manifold 实例,对于 Lie GroupsSophus 是一个不错的选择。

class EuclideanManifold

默认情况下,参数都被认为是欧式空间上的,所以无需使用,提供 EuclideanManifold 的目的是为了测试,也是为了和其他流形上的实现一起实用,比如 ProductManifold,我们在后面会作出说明。

该类适用于动态和静态的局部空间维度。如果编译时已知道局部空间维度,则使用

EuclideanManifold<3> manifold;

如果在编译时不知道局部空间尺寸,则需要将模板参数设置为 ceres::DYNAMIC,并将实际尺寸作为构造函数参数提供:

EuclideanManifold<ceres::DYNAMIC> manifold(ambient_dim);

class SubsetManifold

SubsetManifold 将这种构造推广到通过指定坐标集来保持参数块的任何部分不变。

It is legal to hold all coordinates of a parameter block to constant using a SubsetManifold. It is the same as calling Problem::SetParameterBlockConstant() on that parameter block.

class ProductManifold

In cases, where a parameter block is the Cartesian product of a number of manifolds and you have the manifold of the individual parameter blocks available, ProductManifold can be used to construct a Manifold of the Cartesian product.

在刚性变换的情况下,假设有一个大小为 7 的参数块,其中前四个条目表示四元数的旋转,后三个条目表示平移,那么流形就可以这样构建:

ProductManifold<QuaternionManifold, EuclideanManifold<3>> se3;

Manifolds 能够被移动赋值到 ProductManifold:

SubsetManifold manifold1(5, {2});
SubsetManifold manifold2(3, {0, 1});
ProductManifold<SubsetManifold, SubsetManifold> manifold(manifold1,
                                                         manifold2);

在高级用例中,流形可以动态分配,并作为(智能)指针传递:

ProductManifold<std::unique_ptr<QuaternionManifold>, EuclideanManifold<3>> se3
{std::make_unique<QuaternionManifold>(), EuclideanManifold<3>{}};

模板参数也可以省略,因为它们是自动推导出来的,使初始化简单得多:

ProductManifold se3{QuaternionManifold{}, EuclideanManifold<3>{}};

class QuaternionManifold

If you are using Eigen quaternions, then you should use EigenQuaternionManifold instead because Eigen uses a different memory layout for its Quaternions.

四元数是用 4 个维度的单位向量表示的三维流形,即

正切空间是 3 维的,其加减操作可以定义为

\log(q)=\frac{\atan 2\left(\sqrt{1-q_0^2},q_0\right)}{\sqrt{1-q_0^2}}\left[q_1,q_2,q_3\right]

class EigenQuaternionManifold

class SphereManifold

这提供了一个球面上的流形,意味着矢量的法线保持不变。这种情况经常出现在 Structure for Motion 问题中。比如用它来表示三角剖分条件不佳的点。在这种情况下,使用过参数化是有利的,因为 homogeneous vectors 可以表示无穷远处的点。局部空间维度需要大于1。

该类适用于动态和静态的局部空间维度。如果编译时已知道局部空间维度,则使用

SphereManifold<3> manifold;

如果在编译时不知道局部空间尺寸,则需要将模板参数设置为 ceres::DYNAMIC,并将实际尺寸作为构造函数参数提供:

SphereManifold<ceres::DYNAMIC> manifold(ambient_dim);

class LineManifold

请注意,这是一条直线的流形,而不受限于直线上的一个点。当我们想对直线空间进行优化时,它就会派上用场。例如,给定三维空间中的 n 个不同点(测量值),我们希望找到一条使所有点的距离平方和最小的直线。

Last updated