一.介绍
Ceres库主要由于求解优化问题,通过对测量获取的不十分可靠的数据和理想化的预测模型进行优化处理获取尽可能接近真实值的结果。
二.安装
1.下载ceres库包
git clone https://github.com/ceres-solver/ceres-solver.git
或者到github上直接下载,地址为:
https://github.com/ceres-solver/ceres-solver/releases
下载完后解压到你想要的地方。
2.安装ceres库的依赖项
sudo apt-get install liblapack-dev libsuitesparse-dev libcxsparse3.1.2 libgflags-dev libgoogle-glog-dev libgtest-dev
这一步时,可能会遇到有依赖项无法定位,比如说无法定位libcxsparse3.1.2。
解决办法:
//第一步,打开sources.list
sudo gedit /etc/apt/sources.list
//第二步,将下面的源粘贴到最上方sources.list,并保存
deb http://cz.archive.ubuntu.com/ubuntu trusty main universe
//第三步,更新源
sudo apt-get update
接下来,再重新安装依赖项,成功。
sudo apt-get install liblapack-dev libsuitesparse-dev libcxsparse3.1.2 libgflags-dev libgoogle-glog-dev libgtest-dev
3.编译安装ceres
进入刚刚解压后的ceres的文件夹,打开终端进行编译安装。
如果刚刚使用了git命令安装,可以使用以下命令进入文件夹。
cd ceres-solver
编译安装过程:
mkdir build
cd build
cmake ..
make -j4 //j4为cpu核心数
sudo make install
那么,以上就成功安装啦。
4.验证
为了验证测试一下ceres是否安装成功,可以使用以下命令。
cd build
bin/simple_bundle_adjuster ../data/problem-16-22106-pre.txt
出现如下信息等,即成功验证。
三.实例学习
ceres库主要用于解决优化问题,在slam中应用较多。同时,它还会配合golg库和Eigen库,所以,最好在安装ceres库时将其他也一并安装,或者只取它们的头文件(.h)和动态库文件(.so)也可以。
1.求解优化问题
Ceres问题求解主要分成以下三部分:
(1)构建cost fuction,即代价函数,也就是寻优的目标式(通过预测结果和测量值求误差的函数)。这个部分需要使用仿函数(functor)这一技巧来实现;
(2)通过上一步的代价函数构建待求解的优化问题;
(3)配置求解器参数并求解问题,这个步骤就是设置方程怎么求解、求解过程是否输出等,然后调用一下Solve方法。
问题:求解x值使得1/2(10−x)2最小
代码为:
#include<iostream>
#include<ceres/ceres.h>
using namespace std;
//第一部分:构建代价函数
struct CostFunctor {
//模板函数,泛化函数类型
template <typename T>
//重载符号(),仿函数;传入待优化变量列表和承接残差的变量列表
bool operator()(const T* const x, T* residual) const {
//残差计算步骤
residual[0] = T(0.5)*(T(10.0) - x[0])*(T(10.0) - x[0]);//1/2(10−x)^2
return true;
}
};
//主函数
int main(int argc, char** argv)
{
// 寻优参数x的初始值,为5
double initial_x = 5.0;
double x = initial_x;
// 第二部分:构建寻优问题
//实例化Problem
ceres::Problem problem;
//代价函数赋值
//使用自动求导,将之前的代价函数结构体传入,第一个1是输出维度,即残差的维度,第二个1是输入维度,即待寻优参数x的维度。
// ceres::CostFunction* cost_function = new AutoDiffCostFunction<CostFunctor, 1, 1>(new CostFunctor);
//添加误差项,1、上一步实例化后的代价函数2、核函数3、待优化变量
problem.AddResidualBlock(new ceres::AutoDiffCostFunction<CostFunctor, 1, 1>(new CostFunctor), nullptr, &x);
//第三部分: 配置并运行求解器
ceres::Solver::Options options;
//配置增量方程的解法,此处为QR求解
options.linear_solver_type = ceres::DENSE_QR;
//是否输出到cout
options.minimizer_progress_to_stdout = true;
//优化信息
ceres::Solver::Summary summary;
//求解:1、求解器2、实例化problem 3、优化器
Solve(options, &problem, &summary);
//输出优化的简要信息,迭代次数和每次的cost
std::cout << summary.BriefReport() << "\n";
//最终结果
std::cout << "初始值x : " << initial_x<< " 迭代到-> " << x << "\n";
return 0;
}
得到的结果为,这也我们手算的结果x=10相符:
2.分析
第一部分:构建代价函数结构体
CostFunction结构体中,对括号符号重载的函数中,传入参数有两个,一个是待优化的变量x,另一个是残差residual,也就是代价函数的输出。
struct CostFunctor {
//模板函数,泛化函数类型
template <typename T>
//传入待优化变量列表和承接残差的变量列表
bool operator()(const T* const x, T* residual) const {
//残差计算步骤
residual[0] = T(0.5)*(T(10.0) - x[0])*(T(10.0) - x[0]);//1/2(10−x)^2
return true;
}
};
第二部分:通过代价函数构建待求解的优化问题
这一步最主要的部分是残差块添加函数:AddResidualBlock的使用,涉及到的三个参数分别是(1)自动求导代价函数;(2)是否添加核函数;(3)待优化变量。
其中自动求导函数AutoDiffCostFunction可以单独进行,它内部的三个参数分别为(1)上述定义的代价函数结构体;(2)参差维度;(3)待优化变量的维度。
ceres::Problem problem;
problem.AddResidualBlock(new ceres::AutoDiffCostFunction<CostFunctor, 1, 1>(new CostFunctor), nullptr, &x);
第三部分:配置优化器执行优化
这一部分实现求解器实例化;选择求解方式(这里用QR分解);是否输出运行信息;优化器实例化;调用Slove函数进行问题求解;简要输出执行信息。
其中Slove函数很重要,它负责最后的问题求解,涉及到的三个参数分别是(1)求解器实例化;(2)优化问题实例化;(3)优化器实例化。
ceres::Solver::Options options;
options.linear_solver_type = ceres::DENSE_QR;
options.minimizer_progress_to_stdout = true;
ceres::Solver::Summary summary;
Solve(options, &problem, &summary);
std::cout << summary.BriefReport() << "\n";
std::cout << "初始值x : " << initial_x<< " 迭代到-> " << x << "\n";
第四部分:工程结构和CMakeLists.txt编写
我的工程的结构体为:
│ CMakeLists.txt # cmake的配置文件
│
├─build # 存放 cmake配置生成的文件
├───cmake
│ findcalc.cmake # 动态库的cmake文件
│
└─src # 主项目的源文件
main.cpp
CMakeLists.txt
主目录下的CMakeLists.txt:
# 声明要求的 cmake 最低版本
cmake_minimum_required(VERSION 3.10)
# project name
PROJECT(ubuntu18.04_libs)
ADD_SUBDIRECTORY(src) # 添加src子文件夹
src子文件夹下的CMakeLists.txt:
ADD_EXECUTABLE(main main.cpp)
INCLUDE_DIRECTORIES(/home/wenhaolun/ubuntu18.04_libs/ceres/include /home/wenhaolun/ubuntu18.04_libs/eigen3)
LINK_DIRECTORIES(/home/wenhaolun/ubuntu18.04_libs/ceres /home/wenhaolun/ubuntu18.04_libs/glog)
TARGET_LINK_LIBRARIES(main libceres.so libglog.so)
参考到的博客:
1)https://blog.csdn.net/cqrtxwd/article/details/78956227?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-11.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-11.control
2)https://blog.csdn.net/ABC1225741797/article/details/106489949/