0. 前言
在了解SLAM的原理、流程后,个人经常实时困惑该如何去从零开始去设计编写一套能够符合我们需求的SLAM框架。作者认为Ceres、Eigen、Sophus、G2O这几个函数库无法避免,尤其是Ceres函数库在激光SLAM和V-SLAM的优化中均有着大量的应用。所以作者已从Ceres作为开端,这一篇文章主要对Eigen函数库进行详细的阐述,来方便各位后续的开发。
1. Eigen示例
相较于Ceres而言,Eigen函数库相对较为简单,我们上一篇文章详细描述了Ceres的使用以及注意事项,由于Ceres能够使用
ceres::AutoDiffCostFunction
这一类的自动求导函数,相对而言更加轻松,所以Eigen更多的是做矩阵运算。这里我们给出上一篇文章最后的Ceres求解的Eigen版本。我们可以看到本质上差别不大,只是Eigen需要自己求解雅克比矩阵
J
,并在用
GN
构建增量方程后,使用
ldlt
求解线性方程
HX=g
。
#include<iostream>#include<opencv2/opencv.hpp>#include<Eigen/Core>#include<Eigen/Dense>#include<ctime>usingnamespace std;usingnamespace Eigen;intmain(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值
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));}// 开始Gauss-Newton迭代int iterations =100;// 迭代次数double cost =0, lastCost =0;// 本次迭代的cost和上一次迭代的costfor(int iter =0; iter < iterations; iter++){
Matrix3d H =Matrix3d::Zero();// Hessian = J^T J in Gauss-Newton
Vector3d b =Vector3d::Zero();// bias
cost =0;//-----------------用GN构建增量方程,HX=g---------------------------------//for(int i =0; i < N; i++){double xi = x_data[i], yi = y_data[i];// 第i个数据点// start your code here// double error = 0; // 填写计算error的表达式double error = yi-exp(ae * xi * xi + be * xi + ce);// 第i个数据点的计算误差
Vector3d J;// 雅可比矩阵,3x1
J[0]=-xi*xi*exp(ae * xi * xi + be * xi + ce);// de/da,函数求倒数,-df/da
J[1]=-xi*exp(ae * xi * xi + be * xi + ce);;// de/db
J[2]=-exp(ae * xi * xi + be * xi + ce);;// de/dc
H += J * J.transpose();// GN近似的H
b +=-error * J;// end your code here
cost += error * error;}// 求解线性方程 Hx=b,建议用ldlt// start your code here
Vector3d dx;//LDL^T Cholesky求解// clock_t time_stt2 = clock();
dx = H.ldlt().solve(b);//Hx=b,,,H.ldlt().solve(b)// cout<<"LDL^T分解,耗时:\n"<<(clock()-time_stt2)/(double)// CLOCKS_PER_SEC<<"ms"<<endl;
cout<<"\n dx:"<<dx.transpose()<<endl;// return 0;//一写就死// end your code hereif(isnan(dx[0])){
cout <<"result is nan!"<< endl;break;}if(iter >0&& cost > lastCost){// 误差增长了,说明近似的不够好
cout <<"cost: "<< cost <<", last cost: "<< lastCost << endl;break;}// 更新abc估计值
ae += dx[0];
be += dx[1];
ce += dx[2];
lastCost = cost;
cout <<"total cost: "<< cost << endl;}
cout <<"estimated abc = "<< ae <<", "<< be <<", "<< ce << endl;return0;}
TIP:值得注意的是Eigen函数库是不存在动态链接库的,我们在CMakeList.txt编译时候只需要引入include即可。
include_directories(BEFORE /home/xxx/eigen3_3/complex_eigen/install/include/eigen3/)
2. Eigen模块和头文件归纳
…详情请参照古月居
版权归原作者 敢敢のwings 所有, 如有侵权,请联系我们删除。