ceres被广泛用于解决最小二乘问题,最小二乘分为线性最小二乘和非线性最小二乘,其对应的数值解决方法通常为梯度法、直接法和梯度方法、牛顿法、高斯牛顿法、LM算法,可以参考之前的博客。
1下载
可以在github官方下载(官方版本会和eigen3(3.3.7)有冲突,编译时会报错),我选择了按照slam14讲第二版里面的方法,因此这里在高博git下载。
2安装
2.1按照slam14讲
打开终端输入
sudo apt-get install liblapack-dev libsuitesparse-dev libcxsparse3 libgflags-dev libgoogle-glog-dev libgtest-dev
2.2解压文件,在终端里利用cd命令打开该文件夹路径
创建编译目录
mkdir build
打开编译文件
cd build
生成makefile
cmake ..
编译
make -j4
make test
安装
sudo make install
2.3测试,继续在build路径下输入
bin/simple_bundle_adjuster ../data/problem-16-22106-pre.txt
如果生成以下内容,则证明成功
iter cost cost_change |gradient| |step| tr_ratio tr_radius ls_iter iter_time total_time
0 4.185660e+06 0.00e+00 1.09e+08 0.00e+00 0.00e+00 1.00e+04 0 7.66e-02 2.30e-01
1 1.062590e+05 4.08e+06 8.99e+06 5.36e+02 9.82e-01 3.00e+04 1 1.79e-01 4.09e-01
2 4.992817e+04 5.63e+04 8.32e+06 3.19e+02 6.52e-01 3.09e+04 1 1.70e-01 5.78e-01
3 1.899774e+04 3.09e+04 1.60e+06 1.24e+02 9.77e-01 9.26e+04 1 1.62e-01 7.40e-01
4 1.808729e+04 9.10e+02 3.97e+05 6.39e+01 9.51e-01 2.78e+05 1 1.64e-01 9.04e-01
5 1.803399e+04 5.33e+01 1.48e+04 1.23e+01 9.99e-01 8.33e+05 1 1.64e-01 1.07e+00
6 1.803390e+04 9.02e-02 6.35e+01 8.00e-01 1.00e+00 2.50e+06 1 1.60e-01 1.23e+00
Solver Summary (v 1.14.0-eigen-(3.3.7)-lapack-suitesparse-(4.4.6)-cxsparse-(3.1.4)-eigensparse-openmp-no_tbb)
Original Reduced
Parameter blocks 22122 22122
Parameters 66462 66462
Residual blocks 83718 83718
Residuals 167436 167436
Minimizer TRUST_REGION
Dense linear algebra library EIGEN
Trust region strategy LEVENBERG_MARQUARDT
Given Used
Linear solver DENSE_SCHUR DENSE_SCHUR
Threads 1 1
Linear solver ordering AUTOMATIC 22106,16
Schur structure 2,3,9 2,3,9
Cost:
Initial 4.185660e+06
Final 1.803390e+04
Change 4.167626e+06
Minimizer iterations 7
Successful steps 7
Unsuccessful steps 0
Time (in seconds):
Preprocessor 0.152995
Residual only evaluation 0.097879 (7)
Jacobian & residual evaluation 0.441241 (7)
Linear solver 0.524864 (7)
Minimizer 1.169322
Postprocessor 0.005134
Total 1.327451
Termination: CONVERGENCE (Function tolerance reached. |cost_change|/cost: 1.769761e-09 <= 1.000000e-06)
找一段代码进行测试:
#include <iostream>
#include <ceres/ceres.h>
#include <glog/logging.h>
using ceres::AutoDiffCostFunction;
using ceres::CostFunction;
using ceres::Problem;
using ceres::Solver;
using ceres::Solve;
struct CostFunctor {
template <typename T>
bool operator()(const T* const x, T* residual) const {
residual[0] = T(10.0) - x[0];
return true;
}
};
int main(int argc, char** argv) {
google::InitGoogleLogging(argv[0]);
// 设定求解的未知数的初值
double initial_x = 5.0;
double x = initial_x;
//建立Problem
Problem problem;
//设置唯一的残差方程CostFunction。用自动求导获得导数(或者雅克比矩阵)
//自动求导的模板参数<误差类型, 输出维度, 输入维度>
CostFunction* cost_function = new AutoDiffCostFunction<CostFunctor, 1, 1>(new CostFunctor);
//设置残差模块,参数(代价函数,核函数,待估计参数)
problem.AddResidualBlock(cost_function, NULL, &x);
//运行求解器
Solver::Options options;
options.linear_solver_type = ceres::DENSE_QR; //增量方程的求解方式
options.minimizer_progress_to_stdout = true; //是否把优化最小二乘的过程输出到cout
Solver::Summary summary; //优化信息
Solve(options, &problem, &summary); //开始优化
std::cout << summary.BriefReport() << std::endl; //输出结果
std::cout << "x : " << initial_x << " -> " << x << std::endl;
return 0;
}
CmakeLists.txt:
cmake_minimum_required(VERSION 3.5)
project(1ceres-test)
set(CMAKE_CXX_STANDARD 11)
find_package(Ceres REQUIRED)
include_directories( ${CERES_INCLUDE_DIRS} )
set(SOURCE_FILES main.cpp)
add_executable(1ceres-test ${SOURCE_FILES})
target_link_libraries(1ceres-test ${CERES_LIBRARIES})
显示如下内容则成功:
iter cost cost_change |gradient| |step| tr_ratio tr_radius ls_iter iter_time total_time
0 1.250000e+01 0.00e+00 5.00e+00 0.00e+00 0.00e+00 1.00e+04 0 2.72e-05 1.89e-04
1 1.249750e-07 1.25e+01 5.00e-04 5.00e+00 1.00e+00 3.00e+04 1 1.13e-04 3.58e-04
2 1.388518e-16 1.25e-07 1.67e-08 5.00e-04 1.00e+00 9.00e+04 1 1.91e-05 3.94e-04
Ceres Solver Report: Iterations: 3, Initial cost: 1.250000e+01, Final cost: 1.388518e-16, Termination: CONVERGENCE
如果提示Eigen库报错,例如<Eigen/dense>,是因为/usr/local对应的是eigen3文件夹,需要做个链接
sudo ln -sf eigen3/Eigen Eigen
sudo ln -sf eigen3/unsupported unsupported
或者在cmakelist.txt中添加
include_directories("/usr/include/eigen3")
参考博客