ceres_solver

本文介绍了Ceres Solver的基本使用,特别是它在SLAM问题中的应用,强调了非线性图的稀疏化。通过构建CostFunction、选择不同的微分模型,以及设置优化参数,Ceres Solver能够有效地处理Bundle Adjustment问题。文章提到了边缘化和稀疏化的概念,并鼓励读者查阅相关论文深入理解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1:google 官网 http://ceres-solver.org/

2:一篇中文博客讲的很好:http://m.blog.youkuaiyun.com/HUAJUN998/article


简单的总结一下ceres solver

google的ceres-slover 个人感觉和g2o差不多。

(1)最重要的就是构建CostFunction。根据选择的微分模型的不同有三种构建方式(自动微分,数值微分,手动微分)

          1:对于AutoDiffCostFunction类型的CostFunction,我们构造一个结构体,重写template operator(),注意类型为模板类型,重新定义了()函数,将结构体作为AutoDiffCostFunction的参数。

        

// structstruct CostFunctor { 
  template <typename T>   
  bool operator()(const T* const x, T* residual) const {    
  residual[0] = T(10.0) - x[0];     return true;   }};
// make CostFunction
CostFunction* cost_function = new AutoDiffCostFunction<CostFunctor, 1, 1>(new CostFunctor);
problem.AddResidualBlock(cost_function, NULL, &x);

      2:对于NumericDiffCostFunction类型的CostFunction,与AutoDiffCostFunction类似,只不过将结构体的接收类型不再是模板类型,用double类型代替了模板类型

      

// struct
struct NumericDiffCostFunctor {
  bool operator()(const double* const x, double* residual) const {
    residual[0] = 10.0 - x[0];
    return true;
  }
};
// make CostFunction
CostFunction* cost_function =
new NumericDiffCostFunction<NumericDiffCostFunctor, ceres::CENTRAL, 1, 1>(
  new NumericDiffCostFunctor);
problem.AddResidualBlock(cost_function, NULL, &x);
      3:  在有些情况下,不使用AutoDiffCostFunction,例如我们用近似的方式计算导数,而不是用AutoDiff的链式法则,我们需要自己的残差和Jacobin计算。这时我们定义一个CostFunction或者SizedCostFunction的子类。

class QuadraticCostFunction : public ceres::SizedCostFunction<1, 1> {
 public:
  virtual ~QuadraticCostFunction() {}
  virtual bool Evaluate(double const* const* parameters,
                        double* residuals,
                        double** jacobians) const {
    const double x = parameters[0][0];
    residuals[0] = 10 - x;

    // Compute the Jacobian if asked for.
    if (jacobians != NULL && jacobians[0] != NULL) {
      jacobians[0][0] = -1;
    }
    return true;
  }
};
基本都用自动微分(链式求导法则)。数值微分是有线性误差的,而且这也会导致收敛比较慢。手动求导容易出错(g2o用的就是手动求导,有没有感觉很麻烦)
(2)添加误差项Problem.AddResidualBlock(cost_fuction,NULL/loss_function,input_param1,input_param2,...)

中loss_function的目的是排除外点。即误差较大的项被剔除。除此之外,还有个函数和Problem.AddResidualBlock类似

void Problem::AddParameterBlock(double *values, int size, LocalParameterization*local_parameterization)
void Problem::AddParameterBlock(double *values, int size)
这个函数的目的是告诉Problem在目标函数中有哪些是变量。其实这个可以不添加。Google的官网有说明:

The user has the option of explicitly adding the parameter blocks using AddParameterBlock. This causes additional correctness checking; however, AddResidualBlock implicitly adds the parameter blocks if they are not present, so calling AddParameterBlock explicitly is not required.

但也不是完全没用,比如要固定一些变量,就需要设定Problem::SetParametersBlockConstant(&x),x为你要设定的固定变量。

这里还需要注意的是在构建cost_function时,例如

CostFunction* cost_function = new AutoDiffCostFunction<CostFunctor, 1, 1,1>(new CostFunctor); CostFunction* cost_function = new AutoDiffCostFunction<CostFunctor, 1, 1,1>(new CostFunctor); 
这里的第一个1代表误差项的个数,第二个1代表 input_param1的 维数。第三个1代表input_param2的维数。即cost_function 要和AddResidualBlock相对应


(3)求解器的构建

  Solver::Options options;
  options.minimizer_progress_to_stdout = true;
  Solver::Summary summary;
  Solve(options, &problem, &summary);
以上几步骤是必须的。以下部分是根据需要选择的部分(主要是BA时的一些选项)

DEFINE_string(trust_region_strategy, "levenberg_marquardt",
              "Options are: levenberg_marquardt, dogleg.");
DEFINE_string(dogleg, "traditional_dogleg", "Options are: traditional_dogleg,"
              "subspace_dogleg.");

DEFINE_bool(inner_iterations, false, "Use inner iterations to non-linearly "
            "refine each successful trust region step.");

DEFINE_string(blocks_for_inner_iterations, "automatic", "Options are: "
            "automatic, cameras, points, cameras,points, points,cameras");

DEFINE_string(linear_solver, "sparse_schur", "Options are: "
              "sparse_schur, dense_schur, iterative_schur, sparse_normal_cholesky, "
              "dense_qr, dense_normal_cholesky and cgnr.");
DEFINE_bool(explicit_schur_complement, false, "If using ITERATIVE_SCHUR "
            "then explicitly compute the Schur complement.");
DEFINE_string(preconditioner, "jacobi", "Options are: "
              "identity, jacobi, schur_jacobi, cluster_jacobi, "
              "cluster_tridiagonal.");
DEFINE_string(visibility_clustering, "canonical_views",
              "single_linkage, canonical_views");

DEFINE_string(sparse_linear_algebra_library, "suite_sparse",
              "Options are: suite_sparse and cx_sparse.");
DEFINE_string(dense_linear_algebra_library, "eigen",
              "Options are: eigen and lapack.");
DEFINE_string(ordering, "automatic", "Options are: automatic, user.");

DEFINE_bool(use_quaternions, false, "If true, uses quaternions to represent "
            "rotations. If false, angle axis is used.");
DEFINE_bool(use_local_parameterization, false, "For quaternions, use a local "
            "parameterization.");
DEFINE_bool(robustify, false, "Use a robust loss function.");

DEFINE_double(eta, 1e-2, "Default value for eta. Eta determines the "
             "accuracy of each linear solve of the truncated newton step. "
             "Changing this parameter can affect solve performance.");


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值