zoukankan      html  css  js  c++  java
  • 视觉十四讲:第六讲_ceres非线性优化

    使用Ceres求解非线性优化问题,一共分为三个部分:
    1、 第一部分:构建cost fuction,即代价函数,也就是寻优的目标式。这个部分需要使用仿函数(functor)这一技巧来实现,做法是定义一个cost function的结构体,在结构体内重载()运算符。
    2、 第二部分:通过代价函数构建待求解的优化问题。
    3、 第三部分:配置求解器参数并求解问题,这个步骤就是设置方程怎么求解、求解过程是否输出等,然后调用一下Solve方法

    #include <iostream>
    #include <opencv2/core/core.hpp>
    #include <ceres/ceres.h>
    #include <chrono>
    
    using namespace std;
    
    // 代价函数的计算模型
    struct CURVE_FITTING_COST {
      CURVE_FITTING_COST(double x, double y) : _x(x), _y(y) {}
    
      // 残差的计算
      template<typename T>
      bool operator()(
        const T *const abc, // 模型参数,待优化的参数,有3维
        T *residual) const {
        residual[0] = T(_y) - ceres::exp(abc[0] * T(_x) * T(_x) + abc[1] * T(_x) + abc[2]); // y-exp(ax^2+bx+c)  //残差,也就是代价函数的输出
        return true;
      }
    
      const double _x, _y;    // x,y数据
    };
    
    int main(int argc, char **argv) {
      double ar = 1.0, br = 2.0, cr = 1.0;         // 真实参数值
      double ae = 2.0, be = -1.0, ce = 5.0;        // 估计参数值
      int N = 100;                                 // 数据点
      double w_sigma = 1.0;                        // 噪声Sigma值
      double inv_sigma = 1.0 / w_sigma;
      cv::RNG rng;                                 // OpenCV随机数产生器
    
      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(exp(ar * x * x + br * x + cr) + rng.gaussian(w_sigma * w_sigma));
      }
    
      double abc[3] = {ae, be, ce};
    
      // 构建最小二乘问题
      ceres::Problem problem;
      for (int i = 0; i < N; i++) {
        problem.AddResidualBlock(     // 向问题中添加误差项
          // 使用自动求导,将定义的代价函数结构体传入。模板参数:误差类型,输出维度即残差的维度,输入维度即优化参数的维度,维数要与前面struct中一致
          new ceres::AutoDiffCostFunction<CURVE_FITTING_COST, 1, 3>(
            new CURVE_FITTING_COST(x_data[i], y_data[i])
          ),
          nullptr,            // 核函数,这里不使用,为空
          abc                 // 待估计参数
        );
      }
    
      // 配置求解器
      ceres::Solver::Options options;     // 这里有很多配置项可以填
      options.linear_solver_type = ceres::DENSE_NORMAL_CHOLESKY;  // 增量方程如何求解
      //options.linear_solver_type = ceres::DENSE_QR;
      options.minimizer_progress_to_stdout = true;   // 输出到cout
    
      ceres::Solver::Summary summary;                // 优化信息
      chrono::steady_clock::time_point t1 = chrono::steady_clock::now();
      ceres::Solve(options, &problem, &summary);  // 开始优化,求解
      chrono::steady_clock::time_point t2 = chrono::steady_clock::now();
      chrono::duration<double> time_used = chrono::duration_cast<chrono::duration<double>>(t2 - t1);
      cout << "solve time cost = " << time_used.count() << " seconds. " << endl;
    
      // 输出结果
      cout << summary.BriefReport() << endl;   //输出优化的简要信息
      cout << "estimated a,b,c = ";
      for (auto a:abc) cout << a << " ";
      cout << endl;
    
      return 0;
    }
    

    cmakelists.txt:

    cmake_minimum_required(VERSION 2.8)
    project(gaussnewton)
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
    find_package(OpenCV REQUIRED)
    include_directories(${OpenCV_INCLUDE_DIRS})
    find_package(Ceres REQUIRED)
    include_directories(${CERES_INCLUDE_DIRS})
    include_directories("/usr/include/eigen3")
    set(SOURCE_FILES main.cpp)
    add_executable(gaussnewton ${SOURCE_FILES})
    target_link_libraries(gaussnewton ${OpenCV_LIBS})
    target_link_libraries(gaussnewton ${CERES_LIBRARIES})
    
  • 相关阅读:
    软件测试(来自于网络)
    selenium常用命令
    新员工入门
    常用测试点
    测试leader职责
    软件测试 —— 用例设计4(读书分享)
    Tomcat 基础二
    Github Pull Request的提出与采纳
    Unix套接字接口
    健壮的I/O(RIO)
  • 原文地址:https://www.cnblogs.com/penuel/p/12958010.html
Copyright © 2011-2022 走看看