Ceres 详解(一) Problem类

2023-05-16

引言

Ceres 是由Google开发的开源C++通用非线性优化库(项目主页),与g2o并列为目前视觉SLAM中应用最广泛的优化算法库

(VINS-Mono中的大部分优化工作均基于Ceres完成)。Ceres中的有限边界最小二乘问题建模为以下形式:

Ceres的求解过程包括构: 建最小二乘和求解最小二乘问题 两部分,其中构建最小二乘问题的相关方法均包含在Ceres::Problem类中,

涉及的成员函数主要包括 Problem::AddResidualBlock() Problem::AddParameterBlock()

 

Problem::AddResidualBlock( )

AddResidualBlock() 顾名思义主要用于向 Problem 类传递残差模块的信息,函数原型如下,

传递的参数主要包括:代价函数模块、损失函数模块 参数模块

ResidualBlockId Problem::AddResidualBlock(CostFunction *cost_function, 
                                          LossFunction *loss_function,  
                                          const vector<double *> parameter_blocks)
										  
ResidualBlockId Problem::AddResidualBlock(CostFunction *cost_function, 
                                          LossFunction *loss_function, 
                                          double *x0, double *x1, ...)

代价函数:包含了参数模块的维度信息,内部使用仿函数定义误差函数的计算方式。AddResidualBlock() 函数会检测传入的

参数模块是否和代价函数模块中定义的维数一致,维度不一致时程序会强制退出。代价函数模块的详解参见Ceres详解(二) CostFunction。

损失函数:用于处理参数中含有野值的情况,避免错误量测对估计的影响,常用参数包括 HuberLossCauchyLoss

(完整的参数列表参见Ceres API文档);该参数可以取 NULL nullptr,此时损失函数为单位函数。

参数模块:待优化的参数,可一次性传入所有参数的 指针容器 vector<double*> 依次传入所有参数的指针double*。

 

Problem::AddParameterBlock( )

用户在调用 AddResidualBlock() 时其实已经隐式地向 Problem 传递了参数模块,但在一些情况下,需要用户显式地向 Problem 传入参数模块

通常出现在需要对优化参数进行重新参数化的情况,因为这个时候,优化的参数已经变了)。

Ceres提供了 Problem::AddParameterBlock() 函数用于用户显式传递参数模块:

void Problem::AddParameterBlock(double *values, int size)

void Problem::AddParameterBlock(double *values, int size, LocalParameterization *local_parameterization)

第一种 函数原型除了会增加一些额外的参数检查之外,功能上 和 隐式传递参数并没有太大区别。

第二种 函数原型则会额外传入 LocalParameterization 参数,用于重构优化参数的维数,这里我们着重讲解一下 LocalParameterization 类。

 

LocalParameterization

LocalParameterization 类的作用是解决非线性优化中的过参数化问题。所谓过参数化,即待优化参数的实际自由度小于参数本身的自由度。

例如在SLAM中,当采用四元数表示位姿时,由于四元数本身的约束(模长为1),实际的自由度为3而非4。此时,若直接传递四元数进行优化,

冗余的维数会带来计算资源的浪费,需要使用Ceres预先定义的 QuaternionParameterization 对优化参数进行重构:

problem.AddParameterBlock(quaternion, 4);// 直接传递4维参数

ceres::LocalParameterization* local_param = new ceres::QuaternionParameterization();
problem.AddParameterBlock(quaternion, 4, local_param)//重构参数,优化时实际使用的是3维的等效旋转矢量

自定义LocalParameterization

LocalParaneterization 本身是一个虚基类,详细定义如下;用户可以自行定义自己需要使用的子类,或使用Ceres预先定义好的子类

class LocalParameterization {
 public:
  virtual ~LocalParameterization() {}
  //
  virtual bool Plus(const double* x,
                    const double* delta,
                    double* x_plus_delta) const = 0;//参数正切空间上的更新函数
  virtual bool ComputeJacobian(const double* x, double* jacobian) const = 0; //雅克比矩阵
  virtual bool MultiplyByJacobian(const double* x,
                                  const int num_rows,
                                  const double* global_matrix,
                                  double* local_matrix) const;//一般不用
  virtual int GlobalSize() const = 0; // 参数的实际维数
  virtual int LocalSize() const = 0; // 正切空间上的参数维数
};

上述成员函数中,需要我们改写的主要为 GlobalSize()ComputeJacobian()GlobalSize()LocalSize()

这里我们以ceres预先定义好的 QuaternionParameterization 为例具体说明,类声明如下:

class CERES_EXPORT QuaternionParameterization : public LocalParameterization {
 public:
  virtual ~QuaternionParameterization() {}
  virtual bool Plus(const double* x,
                    const double* delta,
                    double* x_plus_delta) const;
  virtual bool ComputeJacobian(const double* x,
                               double* jacobian) const;
  virtual int GlobalSize() const { return 4; }
  virtual int LocalSize() const { return 3; }
};

1、可以看到,GlobalSize() 的返回值为4,即四元数本身的实际维数;由于在内部优化时,

      ceres采用的是旋转矢量,维数为3,因此 LocalSize() 的返回值为3。

2、重载的 Plus 函数给出了四元数的更新方法,接受参数分别为优化前的四元数 x,用旋转矢量表示的增量delta

以及更新后的四元数 x_plus_delta。函数首先将增量由旋转矢量转换为四元数,随后采用标准四元数乘法对四元数进行更新

bool QuaternionParameterization::Plus(const double* x,
                                      const double* delta,
                                      double* x_plus_delta) const {
  // 将旋转矢量转换为四元数形式
  const double norm_delta =
      sqrt(delta[0] * delta[0] + delta[1] * delta[1] + delta[2] * delta[2]);
  if (norm_delta > 0.0) {
    const double sin_delta_by_delta = (sin(norm_delta) / norm_delta);
    double q_delta[4];
    q_delta[0] = cos(norm_delta);
    q_delta[1] = sin_delta_by_delta * delta[0];
    q_delta[2] = sin_delta_by_delta * delta[1];
    q_delta[3] = sin_delta_by_delta * delta[2];
    // 采用四元数乘法更新
    QuaternionProduct(q_delta, x, x_plus_delta);
  } else {
    for (int i = 0; i < 4; ++i) {
      x_plus_delta[i] = x[i];
    }
  }
  return true;
}

bool QuaternionParameterization::ComputeJacobian(const double* x,
                                                 double* jacobian) const {
  jacobian[0] = -x[1]; jacobian[1]  = -x[2]; jacobian[2]  = -x[3];  // NOLINT
  jacobian[3] =  x[0]; jacobian[4]  =  x[3]; jacobian[5]  = -x[2];  // NOLINT
  jacobian[6] = -x[3]; jacobian[7]  =  x[0]; jacobian[8]  =  x[1];  // NOLINT
  jacobian[9] =  x[2]; jacobian[10] = -x[1]; jacobian[11] =  x[0];  // NOLINT
  return true;
}

ceres预定义LocalParameterization

除了上面提到的 QuaternionParameterization 外,ceres 还提供下述预定义 LocalParameterization 子类:

  • EigenQuaternionParameterization:除四元数排序采用Eigen的实部最后外,与QuaternionParameterization完全一致;
  • IdentityParameterizationconstLocalSizeGlobalSize一致,相当于不传入LocalParameterization
  • SubsetParameterizationGlobalSize为2,LocalSize为1,用于第一维不需要优化的情况;
  • HomogeneousVectorParameterization:具有共面约束的空间点;
  • ProductParameterization:7维位姿变量一同优化,而前4维用四元数表示的情况(这里源文档只举了一个例子,具体用法有待深化);

其他成员函数

Probelm 还提供了其他关于 ResidualBlockParameterBlock 的函数,例如获取模块维数、判断是否存在模块、存在的模块数目等,

这里只列出几个比较重要的函数,完整的列表参见ceres API:

  1. // 设定对应的参数模块在优化过程中保持不变
    void Problem::SetParameterBlockConstant(double *values)
    // 设定对应的参数模块在优化过程中可变
    void Problem::SetParameterBlockVariable(double *values)
    // 设定优化下界
    void Problem::SetParameterLowerBound(double *values, int index, double lower_bound)
    // 设定优化上界
    void Problem::SetParameterUpperBound(double *values, int index, double upper_bound)
    // 该函数紧跟在参数赋值后,在给定的参数位置求解Problem,给出当前位置处的cost、梯度以及Jacobian矩阵;
    bool Problem::Evaluate(const Problem::EvaluateOptions &options, 
    					   double *cost, vector<double>* residuals, 
    					   vector<double> *gradient, CRSMatrix *jacobian)
    

     

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Ceres 详解(一) Problem类 的相关文章

随机推荐

  • 无人机位置信息计算无人机的瞬时速度的matlab仿真

    目录 1 算法描述 2 仿真效果预览 3 MATLAB核心程序 4 完整MATLAB 1 算法描述 无人机最早在20世纪20年代出现 xff0c 1914年第一次世界大战正进行得如火如荼 xff0c 英国的卡德尔和皮切尔两位将军 xff0c
  • 基于simulink的无人机姿态飞行控制仿真

    目录 1 算法描述 2 仿真效果预览 3 MATLAB核心程序 4 完整MATLAB 1 算法描述 无人机是无人驾驶飞机的简称 xff08 Unmanned Aerial Vehicle xff09 xff0c 是利用无线电遥控设备和自备的
  • 基于ADRC自抗扰控制器的simulink仿真,ESO和TD等模块使用S函数开发

    目录 1 算法仿真效果 2 MATLAB核心程序 3 算法涉及理论知识概要 4 完整MATLAB 1 算法仿真效果 matlab2022a仿真结果如下 xff1a 2 MATLAB核心程序 function sys x0 str ts 61
  • m基于模糊控制与遗传优化的自适应ADRC双闭环控制策略matlab仿真

    目录 1 算法仿真效果 2 MATLAB核心程序 3 算法涉及理论知识概要 4 完整MATLAB 1 算法仿真效果 matlab2013b仿真结果如下 xff1a 遗传优化的优化迭代过程仿真图 xff1a 这个是我们采用的优化算法的有过过程
  • VINS-mono在Ubuntu20.04上从零开始安装运行和环境配置(尝试)

    最近尝试在Ubuntu 20 04上安装运行港科大的VINS mono算法 详细记录一下安装过程以及遇到的问题 先记录一下结果 ROS opencv Eigen Ceres以及VINS mono都编译并安装成功了 但是用euroc数据集跑V
  • 数据结构-C++实现

    之前的2周一直在学数据结构 xff0c 头都大了 我是之前对数据结构一点认识都没有 xff0c 我是直接看书怼的 xff0c 我看的是 大话数据结构 xff0c 前面的讲解还不错 xff0c 到了树 图后 xff0c 就有点看不懂了 xff
  • 几款好看的css表格

    表格一 xff1a 代码 xff1a html代码段 xff1a 是用vs写的 表头 lt th gt 那是从数据库读取的数据段 lt td gt 那是我为测试效果加的代码 xff0c 大家可以自行更改 lt h1 gt 待处理订单 lt
  • 非线性优化 (曲线拟合) 问题:高斯牛顿、g2o 方法总结

    其实还有一个Ceres库可以进行优化 xff0c 但是之前的博客已经具体分析了 xff0c 所以这里就对其余两个进行了介绍 xff0c 相关的内容是SLAM14讲里面的知识 一 理论部分 我们先用一个简单的例子来说明如何求解最小二乘问题 x
  • VINS-Fusion : EUROC、TUM、KITTI测试成功 + 程序进程详细梳理

    完成以下任务的前提是系统安装了必备的库 xff0c 比如cere Eigen3 3等 提前下载好了数据集EUROC xff0c KITTI等 一 相关论文 T Qin J Pan S Cao and S Shen A General Opt
  • ROS 简单理解

    https download csdn net download qq 30022867 11120759 utm medium 61 distribute pc relevant download none task download b
  • ROS系列:七、熟练使用rviz

    7 熟练使用rviz xff08 1 xff09 rviz整体界面 rviz是ROS自带的图形化工具 xff0c 可以很方便的让用户通过图形界面开发调试ROS 操作界面也十分简洁 xff0c 如图29 xff0c 界面主要分为上侧菜单区 左
  • ROS系列:八、图像消息和OpenCV图像之间进行转换-cv_bridge

    cv bridge是在ROS图像消息和OpenCV图像之间进行转换的一个功能包 一 xff09 在ROS图像和OpenCV图像之间转换 xff08 C 43 43 xff09 xff11 xff0e Concepts xff08 概念 xf
  • ROS系列:九、rosbag使用

    文章目录 解析rosbag中的 bag文件 xff0c 得到 jpg图片数据和 pcd点云数据 https blog csdn net weixin 40000540 article details 83859694 1 rosbag写入文
  • 三、松灵课堂 | SCOUT的仿真使用

    仿真环境的介绍 Gazebo Gazebo是一款3D动态模拟器 xff0c 能够在复杂的室内和室外环境中准确有效地模拟机器人群 与游戏引擎提供高保真度的视觉模拟类似 xff0c Gazebo提供高保真度的物理模拟 xff0c 其提供一整套传
  • 1PPS:秒脉冲 相关概念理解

    时钟模块上的GPS接收机负责接收GPS天线传输的射频信号 xff0c 然后进行变频解调等信号处理 xff0c 向基站提供1pps信号 xff0c 进行同步 GPS使用原子钟 xff08 原子钟 xff0c 是一种计时装置 xff0c 精度可
  • opencv GStreamer-CRITICAL

    使用openvino中的opencv跑之前的代码 碰到个问题 span class token punctuation span myProg span class token operator span span class token
  • 激光雷达 LOAM 论文 解析

    注意 xff1a 本人实验室买的是Velodyne VLP 16激光雷和 LOAM 论文中作者用的不一样 xff0c 在介绍论文之前先介绍一下激光雷达的工作原路 xff0c 这样更容易理解激光雷达的工作过程 xff0c 其实物图如下图1所示
  • VINS 细节系列 - 坐标转换关系

    前言 在学习VINS Mono过程中 xff0c 对初始化代码中的坐标转换关系做出了一些推导 xff0c 特意写了博客记录一下 xff0c 主要记录大体的变量转换关系 相机和IMU的外参 若需要VINS标定旋转外参 xff0c 则进入以下代
  • VINS 细节系列 - 光束法平差法(BA)Ceres 求解

    一 理论部分 学习过VINS的小伙伴应该知道 xff0c 在SFM xff08 structure from motion xff09 的计算中 光束法平差法 BA xff08 Bundle Adjustment xff09 的重要性 xf
  • Ceres 详解(一) Problem类

    引言 Ceres 是由Google开发的开源C 43 43 通用非线性优化库 xff08 项目主页 xff09 xff0c 与g2o并列为目前视觉SLAM中应用最广泛的优化算法库 xff08 VINS Mono中的大部分优化工作均基于Cer