美文网首页
ceres solver 05 例子:曲线拟合

ceres solver 05 例子:曲线拟合

作者: book_02 | 来源:发表于2019-12-06 21:11 被阅读0次

    给出有噪声的曲线数据,用Ceres Solver拟合出曲线方程

    1. 曲线方程

    假定曲线方程
    y = e^{mx + c}
    我们取m=0.3, c=0.1y = e^{0.3x + 0.1},然后根据这个方程取67个点,然后给这67个点加上标准差为0.2的高斯噪声。

    2. Ceres 求解过程

    2.1 定义代价函数

    y = e^{mx + c}录入到代价函数中去,不过这时有了数据项x和y

    struct ExponentialResidual {
      ExponentialResidual(double x, double y)
          : x_(x), y_(y) {}
    
      template <typename T> bool operator()(const T* const m,
                                            const T* const c,
                                            T* residual) const {
        residual[0] = y_ - exp(m[0] * x_ + c[0]);
        return true;
      }
    
     private:
      const double x_;
      const double y_;
    };
    

    2.2 构建问题,添加残差项

      double m = 0.0;
      double c = 0.0;
    
      Problem problem;
      for (int i = 0; i < kNumObservations; ++i) {
        problem.AddResidualBlock(
            new AutoDiffCostFunction<ExponentialResidual, 1, 1, 1>(
                new ExponentialResidual(data[2 * i], data[2 * i + 1])),
            NULL,
            &m, &c);
      }
    

    data数组里存的是上面我们生成的带有噪声的曲线上点的数据

    2.3 定义求解器的选项参数,并求解

      Solver::Options options;
      options.max_num_iterations = 25;
      options.linear_solver_type = ceres::DENSE_QR;
      options.minimizer_progress_to_stdout = true;
    
      Solver::Summary summary;
      Solve(options, &problem, &summary);
    

    3. 完整代码

    #include "ceres/ceres.h"
    #include "glog/logging.h"
    
    using ceres::AutoDiffCostFunction;
    using ceres::CostFunction;
    using ceres::Problem;
    using ceres::Solver;
    using ceres::Solve;
    
    // Data generated using the following octave code.
    //   randn('seed', 23497);
    //   m = 0.3;
    //   c = 0.1;
    //   x=[0:0.075:5];
    //   y = exp(m * x + c);
    //   noise = randn(size(x)) * 0.2;
    //   y_observed = y + noise;
    //   data = [x', y_observed'];
    
    const int kNumObservations = 67;
    const double data[] = {
      0.000000e+00, 1.133898e+00,
      7.500000e-02, 1.334902e+00,
      1.500000e-01, 1.213546e+00,
      2.250000e-01, 1.252016e+00,
      3.000000e-01, 1.392265e+00,
      3.750000e-01, 1.314458e+00,
      4.500000e-01, 1.472541e+00,
      5.250000e-01, 1.536218e+00,
      6.000000e-01, 1.355679e+00,
      6.750000e-01, 1.463566e+00,
      7.500000e-01, 1.490201e+00,
      8.250000e-01, 1.658699e+00,
      9.000000e-01, 1.067574e+00,
      9.750000e-01, 1.464629e+00,
      1.050000e+00, 1.402653e+00,
      1.125000e+00, 1.713141e+00,
      1.200000e+00, 1.527021e+00,
      1.275000e+00, 1.702632e+00,
      1.350000e+00, 1.423899e+00,
      1.425000e+00, 1.543078e+00,
      1.500000e+00, 1.664015e+00,
      1.575000e+00, 1.732484e+00,
      1.650000e+00, 1.543296e+00,
      1.725000e+00, 1.959523e+00,
      1.800000e+00, 1.685132e+00,
      1.875000e+00, 1.951791e+00,
      1.950000e+00, 2.095346e+00,
      2.025000e+00, 2.361460e+00,
      2.100000e+00, 2.169119e+00,
      2.175000e+00, 2.061745e+00,
      2.250000e+00, 2.178641e+00,
      2.325000e+00, 2.104346e+00,
      2.400000e+00, 2.584470e+00,
      2.475000e+00, 1.914158e+00,
      2.550000e+00, 2.368375e+00,
      2.625000e+00, 2.686125e+00,
    
      2.700000e+00, 2.712395e+00,
      2.775000e+00, 2.499511e+00,
      2.850000e+00, 2.558897e+00,
      2.925000e+00, 2.309154e+00,
      3.000000e+00, 2.869503e+00,
      3.075000e+00, 3.116645e+00,
      3.150000e+00, 3.094907e+00,
      3.225000e+00, 2.471759e+00,
      3.300000e+00, 3.017131e+00,
      3.375000e+00, 3.232381e+00,
      3.450000e+00, 2.944596e+00,
      3.525000e+00, 3.385343e+00,
      3.600000e+00, 3.199826e+00,
      3.675000e+00, 3.423039e+00,
      3.750000e+00, 3.621552e+00,
      3.825000e+00, 3.559255e+00,
      3.900000e+00, 3.530713e+00,
      3.975000e+00, 3.561766e+00,
      4.050000e+00, 3.544574e+00,
      4.125000e+00, 3.867945e+00,
      4.200000e+00, 4.049776e+00,
      4.275000e+00, 3.885601e+00,
      4.350000e+00, 4.110505e+00,
      4.425000e+00, 4.345320e+00,
      4.500000e+00, 4.161241e+00,
      4.575000e+00, 4.363407e+00,
      4.650000e+00, 4.161576e+00,
      4.725000e+00, 4.619728e+00,
      4.800000e+00, 4.737410e+00,
      4.875000e+00, 4.727863e+00,
      4.950000e+00, 4.669206e+00,
    };
    
    struct ExponentialResidual {
      ExponentialResidual(double x, double y)
          : x_(x), y_(y) {}
    
      template <typename T> bool operator()(const T* const m,
                                            const T* const c,
                                            T* residual) const {
        residual[0] = y_ - exp(m[0] * x_ + c[0]);
        return true;
      }
    
     private:
      const double x_;
      const double y_;
    };
    
    int main(int argc, char** argv) {
      google::InitGoogleLogging(argv[0]);
    
      double m = 0.0;
      double c = 0.0;
    
      Problem problem;
      for (int i = 0; i < kNumObservations; ++i) {
        problem.AddResidualBlock(
            new AutoDiffCostFunction<ExponentialResidual, 1, 1, 1>(
                new ExponentialResidual(data[2 * i], data[2 * i + 1])),
            NULL,
            &m, &c);
      }
    
      Solver::Options options;
      options.max_num_iterations = 25;
      options.linear_solver_type = ceres::DENSE_QR;
      options.minimizer_progress_to_stdout = true;
    
      Solver::Summary summary;
      Solve(options, &problem, &summary);
      std::cout << summary.BriefReport() << "\n";
      std::cout << "Initial m: " << 0.0 << " c: " << 0.0 << "\n";
      std::cout << "Final   m: " << m << " c: " << c << "\n";
      return 0;
    }
    
    

    运行结果如下:

      iter      cost      cost_change  |gradient|   |step|    tr_ratio  tr_radius  ls_iter  iter_time  total_time
       0  1.211734e+02    0.00e+00    3.61e+02   0.00e+00   0.00e+00  1.00e+04       0    5.34e-04    2.56e-03
       1  1.211734e+02   -2.21e+03    0.00e+00   7.52e-01  -1.87e+01  5.00e+03       1    4.29e-05    3.25e-03
       2  1.211734e+02   -2.21e+03    0.00e+00   7.51e-01  -1.86e+01  1.25e+03       1    1.10e-05    3.28e-03
       3  1.211734e+02   -2.19e+03    0.00e+00   7.48e-01  -1.85e+01  1.56e+02       1    1.41e-05    3.31e-03
    
       4  1.211734e+02   -2.02e+03    0.00e+00   7.22e-01  -1.70e+01  9.77e+00       1    1.00e-05    3.34e-03
       5  1.211734e+02   -7.34e+02    0.00e+00   5.78e-01  -6.32e+00  3.05e-01       1    1.00e-05    3.36e-03
       6  3.306595e+01    8.81e+01    4.10e+02   3.18e-01   1.37e+00  9.16e-01       1    2.79e-05    3.41e-03
       7  6.426770e+00    2.66e+01    1.81e+02   1.29e-01   1.10e+00  2.75e+00       1    2.10e-05    3.45e-03
       8  3.344546e+00    3.08e+00    5.51e+01   3.05e-02   1.03e+00  8.24e+00       1    2.10e-05    3.48e-03
    
       9  1.987485e+00    1.36e+00    2.33e+01   8.87e-02   9.94e-01  2.47e+01       1    2.10e-05    3.52e-03
      10  1.211585e+00    7.76e-01    8.22e+00   1.05e-01   9.89e-01  7.42e+01       1    2.10e-05    3.56e-03
      11  1.063265e+00    1.48e-01    1.44e+00   6.06e-02   9.97e-01  2.22e+02       1    2.60e-05    3.61e-03
      12  1.056795e+00    6.47e-03    1.18e-01   1.47e-02   1.00e+00  6.67e+02       1    2.10e-05    3.64e-03
      13  1.056751e+00    4.39e-05    3.79e-03   1.28e-03   1.00e+00  2.00e+03       1    2.10e-05    3.68e-03
    
    Ceres Solver Report: Iterations: 13, Initial cost: 1.211734e+02, Final cost: 1.056751e+00, Termination: CONVERGENCE
    Initial m: 0 c: 0
    Final   m: 0.291861 c: 0.131439
    
    曲线拟合结果

    最后求出来m=0.291861, c=0.131439,与我们设定的m=0.3, c=0.1相近

    4. 总结

    总结使用步骤如下:

    1. 定义代价函数。根据目标函数定义代价代价函数
    2. 构建问题。添加残差项。这里要根据有噪声的数据点,不断地添加残差项。
    3. 求解问题。定义求解器的选项参数和求解器的结果报告

    5. 参考

    http://ceres-solver.org/nnls_tutorial.html#curve-fitting

    相关文章

      网友评论

          本文标题:ceres solver 05 例子:曲线拟合

          本文链接:https://www.haomeiwen.com/subject/ckfygctx.html