Ceres-Solver学习笔记(1)

来源:互联网 发布:mac 上的page键 编辑:程序博客网 时间:2024/06/15 03:01

Ceres-Solver是google出的解决非线性最小二乘问题的库,非线性最小二乘问题具有如下形式: 
这里写图片描述 
ρi(∥fi(xi1,…,xik)∥2)是我们所说的残差,fi(⋅)在Ceres中叫做CostFunction,ρi(⋅)叫做LossFunction,用来剔除异常值影响。

Ceres最简单的应用,其他博主的博客中已经有很好的说明, Ceres-Solver库入门

这里做一个小的总结:

  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 CostFunctionCostFunction* cost_function = new AutoDiffCostFunction<CostFunctor, 1, 1>(new CostFunctor);problem.AddResidualBlock(cost_function, NULL, &x);
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
  2. 对于NumericDiffCostFunction类型的CostFunction,与AutoDiffCostFunction类似,只不过将结构体的接收类型不再是模板类型,用double类型代替了模板类型。

    // structstruct NumericDiffCostFunctor {  bool operator()(const double* const x, double* residual) const {    residual[0] = 10.0 - x[0];    return true;  }};// make CostFunctionCostFunction* cost_function =new NumericDiffCostFunction<NumericDiffCostFunctor, ceres::CENTRAL, 1, 1>(  new NumericDiffCostFunctor);problem.AddResidualBlock(cost_function, NULL, &x);
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    谷歌推荐类型为AutoDiffCostFunction,C++模板的使用使得AutoDiff效率更高,而数值的差花费更多,容易出现数字错误,导致收敛速度变慢。

  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;  }};
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    SimpleCostFunction::Evaluate 提供一个 parameters 数组作为输入, 输出 residuals 数组作为残差 ,输出数组 jacobians来显示Jacobians. jacobians是一个可选项,Evaluate检查他是否为 non-null,如果非空,就用残差方程的导数来填充他,因为残差方程是线性的,所以jacobians是常数。(输出惨差和jacobians怎么用? 如何构建CostFunction?)

  4. 对于有多个残差的情况,我们可以构建多个AutoDiffCostFunction,例如 

    f1(x)f2(x)f3(x)f4(x)F(x)=x1+10x2=5(x3x4)=(x22x3)2=10(x1x4)2=[f1(x), f2(x), f3(x), f4(x)]

        // struct     /* struct F1 F2 F3 is omited */    struct F4 {      template <typename T>      bool operator()(const T* const x1, const T* const x4, T* residual) const {        residual[0] = T(sqrt(10.0)) * (x1[0] - x4[0]) * (x1[0] - x4[0]);        return true;      }    };    // make CostFunction    problem.AddResidualBlock(      new AutoDiffCostFunction<F1, 1, 1, 1>(new F1), NULL, &x1, &x2);    problem.AddResidualBlock(      new AutoDiffCostFunction<F2, 1, 1, 1>(new F2), NULL, &x3, &x4);    problem.AddResidualBlock(      new AutoDiffCostFunction<F3, 1, 1, 1>(new F3), NULL, &x2, &x3)    problem.AddResidualBlock(      new AutoDiffCostFunction<F4, 1, 1, 1>(new F4), NULL, &x1, &x4);
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
  5. AddResidualBlock函数是一个模板函数,模板参数为”CostFunction,LossFunction,param1,param2,…”,LossFunction可以为NULL,表示不使用LossFunction,param最多有10个。

接下来会对Ceres例程做一下学习。

原创粉丝点击