这个程序使用C开源图优化库g2o拟合一个较为复杂的非线性函数。真实的函数模型是代码里给的真实值a1,b2,c1,把abc代入函数模型得到具体的模型f(x)加入随机噪声后生成了散点图.下面的图片同时绘制了真实曲线和散点图。程序会根据散点图的数据拟合出a,b,c.这是绘制出来的拟合曲线这是程序输出的优化报告代码里116行设置了最大迭代次数为10次.需要注意第6到9次迭代的chi2并不相同看上去相同是显示位数不够。下面是优化结果的列表对比代码#include iostream #include g2o/core/g2o_core_api.h #include g2o/core/base_vertex.h #include g2o/core/base_unary_edge.h #include g2o/core/block_solver.h #include g2o/core/optimization_algorithm_levenberg.h #include g2o/core/optimization_algorithm_gauss_newton.h #include g2o/core/optimization_algorithm_dogleg.h #include g2o/solvers/dense/linear_solver_dense.h #include Eigen/Core #include opencv2/core/core.hpp #include cmath #include chrono using namespace std; // 曲线模型的顶点模板参数优化变量维度和数据类型 class CurveFittingVertex : public g2o::BaseVertex3, Eigen::Vector3d { public: EIGEN_MAKE_ALIGNED_OPERATOR_NEW // 重置 virtual void setToOriginImpl() override { _estimate 0, 0, 0; } // 更新 virtual void oplusImpl(const double *update) override { _estimate Eigen::Vector3d(update); } // 存盘和读盘留空 virtual bool read(istream in) {} virtual bool write(ostream out) const {} }; // 误差模型 模板参数观测值维度类型连接顶点类型 class CurveFittingEdge : public g2o::BaseUnaryEdge1, double, CurveFittingVertex { public: EIGEN_MAKE_ALIGNED_OPERATOR_NEW CurveFittingEdge(double x) : BaseUnaryEdge(), _x(x) {} // 计算曲线模型误差 virtual void computeError() override { const CurveFittingVertex *v static_castconst CurveFittingVertex * (_vertices[0]); const Eigen::Vector3d abc v-estimate(); _error(0, 0) _measurement - std::exp(abc(0, 0) * _x * _x abc(1, 0) * _x abc(2, 0)); } // 计算雅可比矩阵 virtual void linearizeOplus() override { const CurveFittingVertex *v static_castconst CurveFittingVertex * (_vertices[0]); const Eigen::Vector3d abc v-estimate(); double y exp(abc[0] * _x * _x abc[1] * _x abc[2]); _jacobianOplusXi[0] -_x * _x * y; _jacobianOplusXi[1] -_x * y; _jacobianOplusXi[2] -y; } virtual bool read(istream in) {} virtual bool write(ostream out) const {} public: double _x; // x 值 y 值为 _measurement }; 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随机数产生器 vectordouble 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)); } // 构建图优化先设定g2o typedef g2o::BlockSolverg2o::BlockSolverTraits3, 1 BlockSolverType; // 每个误差项优化变量维度为3误差值维度为1 typedef g2o::LinearSolverDenseBlockSolverType::PoseMatrixType LinearSolverType; // 线性求解器类型 // 梯度下降方法可以从GN, LM, DogLeg 中选 auto solver new g2o::OptimizationAlgorithmGaussNewton( g2o::make_uniqueBlockSolverType(g2o::make_uniqueLinearSolverType())); g2o::SparseOptimizer optimizer; // 图模型 optimizer.setAlgorithm(solver); // 设置求解器 optimizer.setVerbose(true); // 打开调试输出 // 往图中增加顶点 CurveFittingVertex *v new CurveFittingVertex(); v-setEstimate(Eigen::Vector3d(ae, be, ce)); v-setId(0); optimizer.addVertex(v); // 往图中增加边 for (int i 0; i N; i) { CurveFittingEdge *edge new CurveFittingEdge(x_data[i]); edge-setId(i); edge-setVertex(0, v); // 设置连接的顶点 edge-setMeasurement(y_data[i]); // 观测数值 edge-setInformation(Eigen::Matrixdouble, 1, 1::Identity() * 1 / (w_sigma * w_sigma)); // 信息矩阵协方差矩阵之逆 optimizer.addEdge(edge); } // 执行优化 cout start optimization endl; chrono::steady_clock::time_point t1 chrono::steady_clock::now(); optimizer.initializeOptimization(); optimizer.optimize(10); chrono::steady_clock::time_point t2 chrono::steady_clock::now(); chrono::durationdouble time_used chrono::duration_castchrono::durationdouble(t2 - t1); cout solve time cost time_used.count() seconds. endl; // 输出优化值 Eigen::Vector3d abc_estimate v-estimate(); cout estimated model: abc_estimate.transpose() endl; return 0; }参考高翔《视觉SLAM十四讲》