1 #include <opencv2/core/core.hpp>
  2 #include <ceres/ceres.h>
  3 #include <chrono>
  4
  5 using namespace std;
  6
  7 // 代价函数的计算模型
  8 struct CURVE_FITTING_COST
  9 {
 10     CURVE_FITTING_COST ( double x, double y ) : _x ( x ), _y ( y ) {}
 11     // 残差的计算
 12     template <typename T>
 13     bool operator() (
 14         const T* const abc,     // 模型参数,有3维 当没有必要分类的时候 就用一个数组来存储未知的系数,方便管理,而不是设3个变量,之后在()重载函数的形式参数个数变为3个
 15         T* residual ) const     // 残差
 16     {
 17         residual[0] = T ( _y ) - ceres::exp ( abc[0]*T ( _x ) *T ( _x ) + abc[1]*T ( _x ) + abc[2] ); // y-exp(ax^2+bx+c)
 18         return true;
 19     }
 20     const double _x, _y;    // x,y数据
 21 };
 22
 23 int main ( int argc, char** argv )
 24 {
 25     double a=1.0, b=2.0, c=1.0;         // 真实参数值
 26     int N=100;                          // 数据点
 27     double w_sigma=1.0;                 // 噪声Sigma值(根号下方差)
 28     cv::RNG rng;                        // OpenCV随机数产生器
 29     double abc[3] = {0.8,2.1,0.9};      // abc参数的估计值 (修改初始值 下面求解迭代过程会不同)
 30
 31     vector<double> x_data, y_data;      // 数据
 32
 33     /*生成符合曲线的样本*/
 34     cout<<"generating data: "<<endl;   //下面是从真实的曲线中取得样本数据
 35     for ( int i=0; i<N; i++ )
 36     {
 37         double x = i/100.0;
 38         x_data.push_back ( x );
 39         y_data.push_back (
 40             exp ( a*x*x + b*x + c ) + rng.gaussian ( w_sigma )
 41         );
 42         //cout<<x_data[i]<<" "<<y_data[i]<<endl;//输出生成数据
 43     }
 44
 45     // 构建最小二乘问题
 46     ceres::Problem problem;
 47     for ( int i=0; i<N; i++ )
 48     {
 49         /* 第一个参数 CostFunction* : 描述最小二乘的基本形式即代价函数 例如书上的116页fi(.)的形式
 50          * 第二个参数 LossFunction* : 描述核函数的形式 例如书上的ρi(.)
 51          * 第三个参数 double* :       待估计参数(用数组存储)
 52          * 这里仅仅重载了三个参数的函数,如果上面的double abc[3]改为三个double a=0 ,b=0,c = 0;
 53          * 此时AddResidualBlock函数的参数除了前面的CostFunction LossFunction 外后面就必须加上三个参数 分别输入&a,&b,&c
 54          * 那么此时下面的 ceres::AutoDiffCostFunction<>模板参数就变为了 <CURVE_FITTING_COST,1,1,1,1>后面三个1代表有几类未知参数
 55          * 我们修改为了a b c三个变量,所以这里代表了3类,之后需要在自己写的CURVE_FITTING_COST类中的operator()函数中,
 56          * 把形式参数变为了const T* const a, const T* const b, const T* const c ,T* residual
 57          * 上面修改的方法与本例程实际上一样,只不过修改的这种方式显得乱,实际上我们在用的时候,一般都是残差种类有几个,那么后面的分类 就分几类
 58          * 比如后面讲的重投影误差,此事就分两类 一类是相机9维变量,一类是点的3维变量,然而残差项变为了2维
 59          *
 60          * (1): 修改后的写法(当然自己定义的代价函数要对应修改重载函数的形式参数,对应修改内部的残差的计算):
 61          *      ceres::CostFunction* cost_function
 62          *              = new ceres::AutoDiffCostFunction<CURVE_FITTING_COST, 1, 1 ,1 ,1>(
 63          *                  new CURVE_FITTING_COST ( x_data[i], y_data[i] ) );
 64          *      problem.AddResidualBlock(cost_function,nullptr,&a,&b,&c);
 65          * 修改后的代价函数的计算模型:
 66          *   struct CURVE_FITTING_COST
 67          *   {
 68          *       CURVE_FITTING_COST ( double x, double y ) : _x ( x ), _y ( y ) {}
 69          *       // 残差的计算
 70          *       template <typename T>
 71          *       bool operator() (
 72          *          const T* const a,
 73          *          const T* const b,
 74          *          const T* const c,
 75          *          T* residual   ) const     // 残差
 76          *       {
 77          *           residual[0] = T ( _y ) - ceres::exp ( a[0]*T ( _x ) *T ( _x ) + b[0]*T ( _x ) + c[0] ); // y-exp(ax^2+bx+c)
 78          *           return true;
 79          *       }
 80          *       const double _x, _y;    // x,y数据
 81          *   };//代价类结束
 82          *
 83          *
 84          * (2): 本例程下面的语句通常拆开来写(看起来方便些):
 85          * ceres::CostFunction* cost_function
 86          *              = new ceres::AutoDiffCostFunction<CURVE_FITTING_COST, 1, 3>(
 87          *                  new CURVE_FITTING_COST ( x_data[i], y_data[i] ) );
 88          * problem.AddResidualBlock(cost_function,nullptr,abc)
 89          * */
 90         problem.AddResidualBlock (     // 向问题中添加误差项
 91         // 使用自动求导,模板参数:误差类型,Dimension of residual(输出维度 表示有几类残差,本例程中就一类残差项目,所以为1),输入维度,维数要与前面struct中一致
 92                 /*这里1 代表*/
 93             new ceres::AutoDiffCostFunction<CURVE_FITTING_COST, 1, 3> (
 94                 new CURVE_FITTING_COST ( x_data[i], y_data[i] )// x_data[i], y_data[i] 代表输入的获得的试验数据
 95             ),
 96             nullptr,            // 核函数,这里不使用,为空  这里是LossFunction的位置
 97             abc                 // 待估计参数3维
 98         );
 99     }
100
101     // 配置求解器ceres::Solver (是一个非线性最小二乘的求解器)
102     ceres::Solver::Options options;     // 这里有很多配置项可以填Options类嵌入在Solver类中 ,在Options类中可以设置关于求解器的参数
103     options.linear_solver_type = ceres::DENSE_QR;  // 增量方程如何求解 这里的linear_solver_type 是一个Linear_solver_type的枚举类型的变量
104     options.minimizer_progress_to_stdout = true;   // 为真时 内部错误输出到cout,我们可以看到错误的地方,默认情况下,会输出到日志文件中保存
105
106     ceres::Solver::Summary summary;                // 优化信息
107     chrono::steady_clock::time_point t1 = chrono::steady_clock::now();//记录求解时间间隔
108     //cout<<endl<<"求解前....."<<endl;
109     /*下面函数需要3个参数:
110      * 1、 const Solver::Options& options <----> optione
111      * 2、 Problem* problem               <----> &problem
112      * 3、 Solver::Summary* summary       <----> &summart (即使默认的参数也需要定义该变量 )
113      * 这个函数会输出一些迭代的信息。
114      * */
115     ceres::Solve ( options, &problem, &summary );  // 开始优化
116     //cout<<endl<<"求解后....."<<endl;
117     chrono::steady_clock::time_point t2 = chrono::steady_clock::now();
118     chrono::duration<double> time_used = chrono::duration_cast<chrono::duration<double>>( t2-t1 );
119     cout<<"solve time cost = "<<time_used.count()<<" seconds. "<<endl;
120
121     // 输出结果
122     // BriefReport() : A brief one line description of the state of the solver after termination.
123     cout<<summary.BriefReport() <<endl;
124     cout<<"estimated a,b,c = ";
125     /*auto a:abc  或者下面的方式都可以*/
126     for ( auto &a:abc ) cout<<a<<" ";
127     cout<<endl;
128
129     return 0;
130 }

转载于:https://www.cnblogs.com/newneul/p/8407365.html

视觉slam十四讲ch6曲线拟合 代码注释(笔记版)相关推荐

  1. 视觉SLAM十四讲CH6代码解析及课后习题详解

    gaussNewton.cpp #include <iostream> #include <chrono> #include <opencv2/opencv.hpp> ...

  2. 视觉SLAM十四讲从理论到实践第二版源码调试笔记(理论基础1-6章)

    2019-2020-2学期机器人工程专业需要开设SLAM技术课程,使用教材为视觉SLAM十四讲从理论到实践第二版. 为方便学生学习课程知识,将Arduino.ROS1.ROS2和SLAM集成到课程定制 ...

  3. 视觉SLAM十四讲 ch3 (三维空间刚体运动)笔记

    本讲目标 ●理解三维空间的刚体运动描述方式:旋转矩阵.变换矩阵.四元数和欧拉角. ●学握Eigen库的矩阵.几何模块使用方法. 旋转矩阵.变换矩阵 向量外积 向量外积(又称叉积或向量积)是一种重要的向 ...

  4. tensorflow 语义slam_研究《视觉SLAM十四讲从理论到实践第2版》PDF代码+《OpenCV+TensorFlow深度学习与计算机视觉实战》PDF代码笔记...

    我们知道随着人工神经网络和深度学习的发展,通过模拟视觉所构建的卷积神经网络模型在图像识别和分类上取得了非常好的效果,借助于深度学习技术的发展,使用人工智能去处理常规劳动,理解语音语义,帮助医学诊断和支 ...

  5. Ubuntu20/视觉SLAM十四讲踩坑记录

    Ubuntu/视觉SLAM十四讲踩坑记录 Ubuntu(20)/视觉SLAM十四讲踩坑记录: 共性问题: 1.安装OpenCV后,例程仍无法找到OpenCV文件 ch3 visualizeGeomet ...

  6. 视觉SLAM十四讲学习笔记专栏汇总

    专栏汇总 视觉SLAM十四讲学习笔记-第一讲_goldqiu的博客-CSDN博客 视觉SLAM十四讲学习笔记-第二讲-初识SLAM_goldqiu的博客-CSDN博客 视觉SLAM十四讲学习笔记-第二 ...

  7. 视觉SLAM十四讲(第二版)环境安装心得体会

    前言 将高博的视觉SLAM14讲(第二版)看完后,也将里面所有的代码都跑了一遍,在安装环境的时候遇到了无数的坑.为了后来的人能够更加快速上手SLAM,现将书中环境安装心得记录如下. 环境安装 1. 安 ...

  8. 视觉SLAM十四讲学习笔记-第六讲-非线性优化的实践-高斯牛顿法和曲线拟合

    专栏系列文章如下: 视觉SLAM十四讲学习笔记-第一讲_goldqiu的博客-CSDN博客 视觉SLAM十四讲学习笔记-第二讲-初识SLAM_goldqiu的博客-CSDN博客 视觉SLAM十四讲学习 ...

  9. 视觉SLAM十四讲CH10代码解析及课后习题详解

    g2o_viewer问题解决 在进行位姿图优化时候,如果出现g2o_viewer: command not found,说明你的g2o_viewer并没有安装上,打开你之前安装的g2o文件夹,打开bi ...

最新文章

  1. opencv 无法找到tbb_debug.dll
  2. asp.net 利用多表联合查询进行汇总统计
  3. 详解python 3下文本文件的编解码
  4. Hbase PageFilter 取出数量不准确问题
  5. 第六章—条件语句和循环
  6. linux jenkins 插件,使用Jenkins Dashboard插件可视化部署,
  7. CentOS常用基础命令大全
  8. Mysql存储过程和函数区别介绍
  9. linux 扫描开放的端口命令,如何在 Linux 中检查(扫描)开放端口
  10. 实习期间工作、学习、成长、收获总结
  11. 「图像处理」使用Python+Openface实现人脸识别与关键点(landmarks)检测
  12. python大数据技术_大数据技术python
  13. ESP32-C3入门教程 WiFi篇②——WiFi Station 模式连接到 AP 热点接入点
  14. 德鲁克:卓有成效的管理者,一次只做一件事
  15. 工业网络安全 智能电网,SCADA和其他工业控制系统等关键基础设施的网络安全(总结)...
  16. 无胁科技-TVD每日漏洞情报-2022-7-20
  17. 程序设计之B - 东东学打牌(C++
  18. DPDK(二):准备5---cache 颠簸
  19. Spring Cloud Alibaba搭建(二):Nacos注册中心
  20. 高效建设网站管理网站的功能有哪些呢?

热门文章

  1. uClinux下移植Ne2000兼容的网卡驱动程序(转)
  2. python3(一)数字Number
  3. 机器学习中倒三角符号_机器学习的三角误差
  4. alexnet vgg_从零开始:建立著名的分类网2(AlexNet / VGG)
  5. Ubuntu16.04安装docker
  6. keras的学习笔记
  7. 高性能计算机 和服务器,一种高性能计算机服务器
  8. python打印所有花数_Python中使用while循环实现花式打印乘法表
  9. python sum函数numpy_解决Numpy中sum函数求和结果维度的问题
  10. GPU Gems2 - 2 使用基于GPU几何体裁剪图的地形渲染(Terrain Rendering Using GPU-Based Geometry Clipmaps)