Ceres Solver使用说明

2023-05-16

官方文档:http://www.ceres-solver.org/nnls_tutorial.html#robust-curve-fitting
参考文章:一文助你Ceres 入门——Ceres Solver新手向全攻略
使用Ceres求解非线性优化问题,一共分为三个部分:
1、 第一部分:构建cost fuction(代价函数)。这个部分需要使用仿函数(就是使一个类的使用看上去像一个函数,就是重载了个括号运算符,所以对象调用operator()函数像个函数,理解就行这不重要)技巧来实现。这步定义一个cost function的结构体,在结构体内重载()运算符
2、 第二部分:通过代价函数构建待求解的优化问题。
3、 第三部分:配置求解器参数并求解问题,这个步骤就是设置方程怎么求解、求解过程是否输出等,然后调用一下Solve方法。

Ceres库中提供的核函数主要有:TrivialLoss 、HuberLoss、 SoftLOneLoss 、 CauchyLoss。
要使用CauchyLoss,只需要将nullptr换成new ceres::CauchyLoss(0.5)就行(0.5为参数)

#include <iostream>
#include <opencv2/core/core.hpp>
#include <ceres/ceres.h>//最小二成非线性优化
#include <chrono>//计时
#include <fstream>//文件流
 
using namespace std;
 
// [1] 代价函数的计算模型
// 1.定义一个Functor(拟函数/函数对象)类,其中定义的是CostFunction. 需要重载函数调用运算符,
//  从而可以像使用函数一样使用该类对象.(与普通函数相比,能够在类中存储状态,更加灵活)
struct CURVE_FITTING_COST//曲线拟合代价函数
{
    CURVE_FITTING_COST ( double x, double y ) : _x ( x ), _y ( y ) {}//直接赋值   _x = x;     _y  = y;
    /*
     函数 y=exp(a*x^2 +b*x+c) + w//w为噪声
    参差  y-exp(a*x^2 +b*x+c)
     */
    // 残差的计算
    template <typename T>//必须使用模板类型   通用参数类型
    bool operator() (            // 必须要编写一个重载() 运算
      //所有的输入参数和输出参数都要使用T类型
        const T* const abc,     // 模型参数,有3维
        T* residual ) const      // 残差
    { // T ( _y )  T ( _x ) 强制类型转换
        residual[0] = T ( _y ) - ceres::exp ( abc[0] * T ( _x )  * T ( _x ) + abc[1] * T ( _x ) + abc[2] ); 
	    // y-exp(a * x^2+b * x + c)
        return true;//必须返回ture
    }
     private:   //自添加
  // 观测值
    const double _x, _y;    //常量 double类型  x,y数据
};
 
int main ( int argc, char** argv )
{
    double a=1.0, b=2.0, c=1.0;   // 真实参数值
    int N=100;                             // 数据点数量
    double w_sigma=1.0;             // 噪声Sigma值  高斯分布方差
    cv::RNG rng;                         // OpenCV随机数产生器
    double abc[3] = {0,0,0};        // abc参数的估计值(初始值为0)
 
    vector<double> x_data, y_data;      // 数据 容器
 
    stringstream ss;//字符串流
    
    cout<<"生成数据 generating data: "<<endl;
    for ( int i=0; i<N; i++ )
    {
        double x = i/100.0;//自变量
        x_data.push_back ( x );
        y_data.push_back (
            exp ( a * x * x + b * x  + c ) + rng.gaussian ( w_sigma )//加上高斯噪声
        );
        cout<<x_data[i]<<"\t"<<y_data[i]<<endl;
	ss << x_data[i] << " " << y_data[i] << endl;//定向到 字符串流
    }
    
    //将生成的点坐标保存到points.txt
    ofstream file("points.txt"); 
    file << ss.str();
    
    // 构建最小二乘问题
    //声明一个残差方程,CostFunction通过模板类AutoDiffCostFunction来进行构造,
    //第一个模板参数为残差对象,也就是最开始写的那个那个带有重载()运算符的结构体,第二个模板参数为残差个数,第三个模板参数为未知数个数,最后参数是结构体对象。
    ceres::Problem problem;
    for ( int i=0; i<N; i++ )
    {
        problem.AddResidualBlock (     // 向问题中添加误差项
        // 使用自动求导,模板参数:误差类型,输出维度,输入维度,维数要与前面struct中一致
        // AutoDiff 自动求导                         指定  误差项维度1   参数3维    
            new ceres::AutoDiffCostFunction<CURVE_FITTING_COST, 1, 3> (  // 模型参数,有3维
                new CURVE_FITTING_COST ( x_data[i],  y_data[i] )//带入误差方差
            ),
            nullptr,            // 核函数,这里不使用,为空
            abc                  // 待估计参数 这里为 数组 输入的为 地址   如果是常量 需要 &x  取地址
        );
    }
 
    // 配置求解器
    // 这个类有许多字段,每个字段都提供了一些枚举值供用户选择。所以需要时只要查一查文档就知道怎么设置了。
    ceres::Solver::Options options;     // 这里有很多配置项可以填
    options.linear_solver_type = ceres::DENSE_QR;  // QR分解  增量方程如何求解
    options.minimizer_progress_to_stdout = true;   // 优化过程信息 输出到 标志输出
  /** 参数选择
    options.gradient_tolerance = 1e-16;
    options.function_tolerance = 1e-16;
    ...
    梯度阈值 gradient_tolerance.
    相邻两次迭代之间目标函数之差 function_tolerance.
    梯度下降策略 trust_region_strategy 可选levenberg_marquardt,dogleg.
    线性增量方程 HΔx=g 求解方法 linear_solver 可选sparse_schur,dense_schur,sparse_normal_cholesky,
		    视觉SLAM中主要采用稀疏Schur Elimination/ Marginalization的方法(也就是消元法),
		    将地图点的增量边缘化,先求出相机位姿的增量,可以极大地较少计算量,避免H矩阵直接求逆
   稀疏线性代数库 sparse_linear_algebra_library 可选suite_sparse,cx_sparse(ceres编译时需额外编译),
				  cx_sparse相对suite_sparse,更精简速度较慢,但是不依赖BLAS和LAPACK.这个通常选择suite_sparse即可.
  稠密线性代数库  dense_linear_algebra_library 可选eigen,lapack.
  边缘化次序 ParameterBlockOrdering 设置那些优化变量在求解增量方程时优先被边缘化,一般会将较多的地图点先边缘化,
			  不设置ceres会自动决定边缘化次序,这在SLAM里面常用于指定Sliding Window的范围.	
  多线程 这里的设置根据运行平台会有较大不同,对计算速度的影响也是最多的.
		  分为计算雅克比时的线程数num_threads,以及求解线性增量方程时的线程数num_linear_solver_threads.			  
  迭代次数 max_num_iterations,有时迭代多次均不能收敛,可能是初值不理想或者陷入了平坦的区域等等原因,
		      需要设定一个最大迭代次数.			  			  
   */
    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;
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Ceres Solver使用说明 的相关文章

  • ceres-solver和g2o性能比较

    前言 ceres solver 和 g2o 是slam领域常见的优化器 xff0c 其中ceres solver被vins mono使用 xff0c 而g2o被orb slam3使用 xff0c 因此到底哪个优化器更适合于在slam算法开发
  • FreeRTOS的vTaskDelete使用说明

    FreeRTOS的vTaskDelete使用说明 函数说明 参数 xff1a xTaskToDelete 要删除的任务的任务句柄 返回值 无 说明 删除一个用函数xTaskCreate 或者xTaskCreateStatic 创建的任务 x
  • easyplayerpro 使用说明_EasyPlayerPro(Windows)流媒体播放器开发之跨语言调用

    下面我们来讲解一下关于EasyPlayerPro接口的调用 xff0c 主要分为C 43 43 和C 两种语言 xff0c C 43 43 也可以基于VC和QT进行开发 xff0c C 43 43 以VC MFC框架为例进行讲解 xff0c
  • Ceres 自动求导解析-从原理到实践

    Ceres 自动求导解析 从原理到实践 文章目录 Ceres 自动求导解析 从原理到实践1 0 前言2 0 Ceres求导简介3 0 Ceres 自动求导原理3 1 官方解释3 2 自我理解 4 0 实践4 1 Jet 的实现4 2 多项式
  • .adoc使用说明

    开发过程中 xff0c 部分开源代码文档中出现了 adoc文件 xff0c 为了了解并使用这个文件 xff0c 简单记录以下功能和用法 xff0c 方便后续查阅使用 what xff1a AsciiDoc file 标记语言 why xff
  • slam优化eigen,ceres,g2o,gtsam,pcl

    eigen SLAM本质剖析 Eigen 古月居 ceres https guyuehome com 34633 g2o SLAM本质剖析 G2O 古月居 gtsam SLAM本质剖析 GTSAM 古月居 pcl https www guy
  • grub.cfg使用说明

    grub 参数设置参考说明 一 grub cfg详解 说明 xff1a grub cfg默认为只读 xff0c 需要个性化配置文件的 xff0c 建议不要直接修改grub cfg xff0c 请参考链接的pdf文档和google文档 set
  • 安装kalibr踩坑2:fatal error: ceres/rotation.h: No such file or directory #include “ceres/rotation.h“

    fatal error ceres rotation h No such file or directory include 34 ceres rotation h 34 ceres没有装好 xff0c 需要重装 xff0c 安装方法如下
  • 使用说明-Postman-带cookie请求、文件上传

    Postman进行文件上传 选择post方式 xff0c 地址是http 192 168 102 213 7240 foa system upload Headers部分不要填写任何内容 对照后台的接口 xff0c 配置postman 选择
  • Ceres的自动求导实现原理剖析

    目录 数学原理实现原理总结 首先注意数值求导和自动求导在使用的时候的不同之处 实际上 xff0c 正是自动求导这个地方使用了类模板 xff0c 导致它不仅可以传入参数 xff0c 还可以传入Jet类型的数据 xff0c 从而实现了参数的雅可
  • IMU误差模型简介及VINS使用说明

    1 IMU误差来源 2 IMU噪声模型 Noise and Bias kalibr中的imu noise model 参考 xff1a https github com ethz asl kalibr wiki IMU Noise Mode
  • TI的ADS8320使用说明

    在调试程序的过程中遇到一个奇怪的现象 xff0c 使用ADS8320的16位AD采样温度数据 xff0c 在实际使用过程中遇到问题 xff0c 记录如下 xff1a 初始化 ADS8320 拉低片选 读取16位数据 拉高片选 使用STM32
  • ubuntu 20.04 安装 ceres库

    文章目录 一 安装依赖项二 下载源码 xff1a 三 编译并且安装1 进入正确位置 xff1a 2 建立build xff0c 并进入3 编译4 安装 安装完成后是下面这个界面 xff1a 一 安装依赖项 sudo apt span cla
  • R求解:系统完全奇异

    我正在解决简单的优化问题 该数据集有 26 列和 3000 多行 源代码看起来像 Means lt colMeans Returns Sigma lt cov Returns invSigma1 lt solve Sigma 一切都很完美
  • Z3 Solver Java API:意外行为

    通过向求解器添加条件 我想使用 solver check 检查是否存在解 因此 我创建了一个简单的示例来寻找 t1 的解决方案 我知道 t1 有一个解 即 t1 0 然而 求解器的状态不是 SATISFIABLE public static
  • solve_ivp 错误:“缺少 2 个必需的位置参数:”

    我用于solve ivp的函数定义为 def ydot t y kappa4 kappa16 使用solve ivp时如下 sol solve ivp ydot 0 10 initial condition args 50 100 我收到以
  • 在 C++ 中找到一对椭圆的公切线的首选方法[关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我想用 C 来做这个 我有两个想法可以做到这一点 将这对椭圆视为两个不同参数的参数方程 我可以根据这两个参数得到两个方程 这对方程是非
  • 用于未定方程组的 C++ 库 [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我一直在寻找一个 C 库来解决这样的不确定系统 q 是向量 w x y z 变量和 a b c d 常
  • Z3 SMT 求解器中的常数相等

    我正在使用 Microsoft 的 Z3 SMT 求解器 并且我正在尝试定义自定义类型的常量 默认情况下 这些常量似乎并不不平等 假设您有以下程序 declare sort S 0 declare const x S declare con
  • 从字符串解方程得到 C 的结果

    我想知道是否有人有关于如何做一些听起来很简单但在尝试编程时看起来并不像的事情的信息或经验 这个想法是 给出一个包含方程的字符串 例如 2 x 10 这很简单 但它可能会变得非常复杂 例如 sqrt 54 35 x 2 等等on 程序将返回

随机推荐