Ceres简单使用

用Ceres解决最小二乘问题步骤一般是这样

  1. 我们要先建立一个最小二乘问题;(代码中就是构建一个用Problem类构建一个problem对象)
  2. 接着我们需要建立代价函数costFunction。(如果是用AutoDiff自动求解,用法是这样的:AutoDiffCostFunction<仿函数类,残差的维度,剩下的一堆是优化变量的维度>);
    我们看到这里有一个“仿函数类”需要我们填。所以,这时我们需要在外面定义一个仿函数类:这个仿函数类主要是告诉Ceres怎么计算残差。
    注意:这里“剩下一堆是优化变量的维度”含义是,如果把m个变量写在一起变成向量的形式(成了一个变量),那就直接写向量的维度m;要是分开写的话就是m个1;
  3. 添加残差模块,用problem.AddResidualBlock(costFunc, 鲁邦核函数,优化变量们用指针传)
    (鲁棒核函数没有的话就是nullptr;引用也是指针)
  4. 设置求解器和输出报告
#include <iostream>
#include <ceres/ceres.h>
#include <opencv2/core/core.hpp>

/*这个工程优化 y=mx+c中的参数m和参数c*/

// 设计一个仿函数(函数对象)用于残差计算 cost function
class computeResidual
{
public:
    computeResidual(double x, double y) : _x(x), _y(y) {}

//    template <typename T>
//    bool operator()(const T *m, const T *c, T *residual) const
//    {
//        residual[0] = T(_y) - (m[0] * T(_x) + c[0]);
//        return true;
//    }

     template <typename T>
     bool operator()(const T *const paraMC, // 参数维度,2维
                     T *residual) const
     {
         residual[0] = T(_y) - (paraMC[0] * T(_x) + paraMC[1]);
         return true;
     }

    const double _x;
    const double _y;
};

int main(int argc, char **argv)
{
    // 参数
    double m = 0.0, c = 0.0;
    // 参数块
    double paraMC[2] = {m, c};

    cv::RNG rng;
    double sigma = 0.2;

    // 1、建立最小二乘问题
    ceres::Problem problem;
    for (int i = 0; i < 100; ++i)
    {
        // 按照m = 0.3, c = 0.1来对100个点进行赋值,并给予白噪声
        double y_with_noise = std::exp(0.3 * i / 100.0 + 0.1) + rng.gaussian(sigma * sigma);

        // 2、建立costFunction。如果是AutoDiff自动求解就如下 :
        // AutoDiffCostFunction<仿函数类,残差的维度,剩下的一堆是优化变量的维度>

//        ceres::CostFunction *cost_function =
//            new ceres::AutoDiffCostFunction<computeResidual, 1, 1, 1>(
//                new computeResidual(i / 100.0, y_with_noise));
//
//        // 3、添加残差模块,用problem.AddResidualBlock(costFunc, 鲁邦核函数,优化变量们用指针传)
//        problem.AddResidualBlock(cost_function, nullptr, &m, &c);

        /*********************************************************************************************/

         ceres::CostFunction *cost_function =
             new ceres::AutoDiffCostFunction<computeResidual, 1, 2>(
                 new computeResidual(i / 100.0, y_with_noise));

         problem.AddResidualBlock(cost_function, nullptr, paraMC);
    }

    // 4、设置求解器和输出报告
    ceres::Solver::Options options;               // 这其中有很多配置项可以填
    options.linear_solver_type = ceres::DENSE_QR; // 增量方程怎么求解
    options.minimizer_progress_to_stdout = true;  // 输出到cout
    options.max_num_iterations = 10;

    ceres::Solver::Summary summary;            // 优化信息
    ceres::Solve(options, &problem, &summary); // 开始优化

    std::cout << summary.BriefReport() << std::endl;

//    std::cout << "m=" << m << " "
//              << "c=" << c << std::endl;

    /*********************************************************************************************/

     std::cout << summary.BriefReport() << std::endl;
     std::cout << "m=" << paraMC[0] << "c=" << paraMC[1] << std::endl;

    return 0;
}

posted @ 2024-03-21 14:31  沈鹿青  阅读(190)  评论(0)    收藏  举报