Ceres求解最小二乘问题

待优化的函数是:
y = a x 2 + b x + c y=ax^2+bx+c y=ax2+bx+c
采用自动求导与解析求导两种方式进行求解

自动求导:

#include <iostream>
#include <ceres/ceres.h>
#include <opencv2/core/core.hpp>
#include <vector>
using namespace std;

struct Curve_Factor
{
        Curve_Factor(double x, double y) : _x(x), _y(y) {}
        template <typename T>
        //操作符()是一个模板方法,返回值为bool型,接受参数依次为待优化变量和残差变量
        bool operator()(const T *const abc, T *residual) const
        {
                residual[0] = T(_y) - (abc[0] * T(_x) * T(_x) + abc[1] * T(_x) + abc[2]);
                return true;
        }
        const double _x, _y;
};

int main(int, char **)
{
        double a = 1.0, b = 10.0, c = 1.5;
        int N = 1000;
        double w_sigma = 1.0;
        cv::RNG rng;
        double abc[3] = {0, 0, 0};
        vector<double> x_data, y_data;

        for (int i = 0; i < N; i++)
        {
                double x = i / 100.0;
                x_data.push_back(x);
                y_data.push_back(a * x * x + b * x + c + rng.gaussian(w_sigma));
        }
        //构造最小二乘问题
        ceres::Problem problem;
        for (int i = 0; i < N; i++)
        {
                problem.AddResidualBlock(
                    new ceres::AutoDiffCostFunction<Curve_Factor, 1, 3>(new Curve_Factor(x_data[i], y_data[i])),
                    nullptr,
                    abc);
        };
        //配置求解器
        ceres::Solver::Options options;
        options.linear_solver_type = ceres::DENSE_QR;
        options.minimizer_progress_to_stdout = true;
        ceres::Solver::Summary summary;
        ceres::Solve(options, &problem, &summary);
        cout << summary.BriefReport() << endl;
        for (auto a : abc)
                cout << a << " " << endl;
}

解析求导

#include "ceres/ceres.h"
#include "opencv2/core/core.hpp"
using namespace std;

class CeresFactor : public ceres::SizedCostFunction<1, 3>
{
public:
        CeresFactor(const double x, const double y) : x_(x), y_(y) {}
        virtual ~CeresFactor() {}
        virtual bool Evaluate(double const *const *parameters, double *residuals, double **jacobians) const
        {
                const double a = parameters[0][0];
                const double b = parameters[0][1];
                const double c = parameters[0][2];
                residuals[0] = (a*x_*x_ + b*x_ + c) - y_;
                
                if (!jacobians)
                        return true;
                double *jacobian = jacobians[0];
                if (!jacobian)
                        return true;

                jacobian[0] = x_*x_;
                jacobian[1] = x_;
                jacobian[2] = 1;
                return true;
        }

private:
        const double x_;
        const double y_;
};

int main(int argc, char** argv)
{
        double a = 1.0, b = 10.0, c = 1.5; //真实参数值
        int N = 1000;
        double w_sigma = 1;
        cv::RNG rng;
        double abc[3] = {0, 0, 0};
        vector<double> x_data, y_data;
        for(int i = 0; i < N; i++)
        {
                double x = i / 100.0;
                double y = a*x*x + b*x + c + rng.gaussian(w_sigma);
                x_data.push_back(x);
                y_data.push_back(y);
        }
        ceres::Problem problem;
        for(int i = 0; i < N; i++)
        {
                ceres::CostFunction* cost_function = new CeresFactor(x_data[i], y_data[i]);
                problem.AddResidualBlock(cost_function, NULL, abc);
        }
        ceres::Solver::Options options;
        options.minimizer_progress_to_stdout = true;
        ceres::Solver::Summary summary;
        ceres::Solve(options, &problem, &summary);
        cout << abc[0] << "  " << abc[1] << "  " << abc[2] << endl;
        return 0;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值