上次写博客还是高中时候,那时候会在qq空间写些随想,这么多年过去了,如今再开始写博客还有些小激动哈哈。头一次写技术博客,也不知道会不会有人来看,全当记录自己走过的一些坑,如果恰好能够帮助到一些有需要的人也是极好的。
最近由于项目需求,需要使用第三方Ceres库来求解一些定义的约束问题。头一次接触Ceres库,期间着实踩了很多坑。本文接下来将逐步阐释如何在Mac下安装,以及如何在Cmake配置文件中配置Ceres库。最后会展示出一个调用Ceres的完整Demo。
后续我会写一篇如何在Android平台下编译Ceres库的教程,网上关于Android平台下Ceres库配置真的很少,官网也是简单提了一下没有很详细的说明。
想一个很简单的问题,我们定义一个函数y = wx + b
,同时有很多组数据(x=1, y=2) (x=2, y=4)等等,我们希望求解w
b
来使得函数可以很好地拟合这组数据,如何来求解呢。Ceres就可以用来帮助我们求解这样一个问题,我们只需要定义好输入数据和待求量以及损失函数,Ceres就可以帮我求解了。
当然Ceres的用处远不止于次,可以用来迭代求解一些很复杂带有边界约束的非线性问题。Ceres库于2014年被谷歌开源,目前在计算机视觉领域(slam等)有着很广泛的应用。
官方网站在这里,里面有很详细的用法描述。如果碰到问题也可以在github社区参与讨论。
那么如何安装Ceres库为我们所用,其实官网已经说得很明确了,这里只是照搬一下过程。
用mac的小伙伴都知道mac有一个神器–HomeBrew,有了它在mac下一键安装各种(opencv等)不再是问题!没有homebrew的小伙伴直接在百度搜homebrew安装即可。
同样,对于我们的主角Ceres也是如此,用homebrew可以一键搞定。只需要打开终端,输入brew install ceres-solver
即可。Mac会自动帮我们安装好Ceres以及它所依赖的第三方库(glog、eigen、suite-sparse)。
如果不确定自己是否已经完全安装了Ceres依赖的第三方库,可以依次在终端输入
brew install glog
brew install eigen
brew install suite-sparse
正常所有依赖库都应该显示如下的提示,这表明依赖库已经安装了,如果没有下面提示则会自动安装。
Warning: suite-sparse 5.3.0_1 is already installed and up-to-date
To reinstall 5.3.0_1, run `brew reinstall suite-sparse`
等待这些四个库都安装完成后,在mac/usr/local/Cellar
目录下,会生成这几个库文件夹。大功告成
通过上一节安装教程后,我们已经可以调用Ceres库了,不过不能多线程加速。如果想要多线程加速的话,这里我们不能通过homebrew来一键安装,需要自己手动通过cmake来开启多线程选项并编译源码。
1.首先我们需要在Ceres官方github上下载Ceres的源码包并解压到某一路径下。以下是我解压的示例,正常除了ceres-bin
这个文件夹是我自己创建的以外,其他文件夹应该都是有的。
2.通过homebrew安装第三方依赖的库。
brew install glog
brew install eigen
brew install suite-sparse
由于需要多线程,所以还需要安装额外的第三方多线程库。官方给出了3种加速方式:TBB
OPENMP
和CXX11_THREADS
。这里只讲如何安装附带TBB的Ceres库。
同样需要通过brew来安装TBB
brew install TBB
3.准备工作都已做好,接下来就需要通过cmake来编译了。
首先在编译之前,我们需要修改CMakeLists.txt,这是因为CMakeLists.txt中把多线程的选项默认关了…
打开CMakeLists.txt,找到115行 122行,原来红框的部分都是OFF的,把这两个地方现在都换成ON。
4.打开终端,并切换目录到ceres源码的根目录下。
然后依次运行
mkdir ceres-bin
cd ceres-bin
如上面CMakeLists.txt所示,我们需要再编译中把CXX11
设置成ON
,OPENMP
CXX11_THREADS
都设成OFF
,只有这样TBB才会默认开启。
cmake -DCXX11=ON -DOPENMP=OFF -DCXX11_THREADS=OFF ..
make -j3
make install
大功告成!这波操作后ceres就会安装到mac系统当中,与上一节homebrew的效果是一样的,只不过多了多线程TBB的支持。
安装完Ceres库后,接下来我们展示如何通过调用Ceres。
首先我们建立一个testCeres.cpp,并贴上一段谷歌ceres给的官方调用示例。顺便说一下,谷歌提供了大量的调用示例,各种case讲的还是挺详细的。
下面代码来自于示例网站中的helloworld.cc
,主要干的事情就是采用双线程迭代求x,使得0.5 (10-x)^2
的损失loss最小,划重点是平方,不是10-x,ceres内部是有平方运算的,千万不要定义错了。
#include "ceres/ceres.h"
#include "glog/logging.h"
using ceres::AutoDiffCostFunction;
using ceres::CostFunction;
using ceres::Problem;
using ceres::Solver;
using ceres::Solve;
// A templated cost functor that implements the residual r = 10 -
// x. The method operator() is templated so that we can then use an
// automatic differentiation wrapper around it to generate its
// derivatives.
struct CostFunctor {
template <typename T> bool operator()(const T* const x, T* residual) const {
residual[0] = 10.0 - x[0];
return true;
}
};
int main(int argc, char** argv) {
google::InitGoogleLogging(argv[0]);
// The variable to solve for with its initial value. It will be
// mutated in place by the solver.
double x = 0.5;
const double initial_x = x;
// Build the problem.
Problem problem;
// Set up the only cost function (also known as residual). This uses
// auto-differentiation to obtain the derivative (jacobian).
CostFunction* cost_function =
new AutoDiffCostFunction<CostFunctor, 1, 1>(new CostFunctor);
problem.AddResidualBlock(cost_function, NULL, &x);
// Run the solver!
Solver::Options options;
options.num_threads = 2;
options.minimizer_progress_to_stdout = true;
Solver::Summary summary;
Solve(options, &problem, &summary);
std::cout << summary.BriefReport() << "\n";
std::cout << "x : " << initial_x
<< " -> " << x << "\n";
return 0;
}
如果通过cmake来执行的话是编不过的,这是因为没有引入Ceres的库路径和头文件路径以及它所依赖的第三方库相关信息。所以接下来我会贴上如何在CMakeLists.txt中写入有关ceres的所有配置。
同样,ceres官网上已经做了很明确的说明,对于本博客讲述不清楚的地方可以参考官网Installation的Using Ceres with Cmake部分。
cmake_minimum_required(VERSION 3.10)
set(LIBRARY_NAME TESTCeres)
project(${LIBRARY_NAME})
set(CMAKE_CXX_STANDARD 11)
# ceres module
FIND_PACKAGE(ceres REQUIRED)
# Eigen module
INCLUDE_DIRECTORIES(${EIGEN_INCLUDE_DIR})
# 搜集testCeres.cpp源码文件
file(GLOB SRC your/path/to/testCeres.cpp)
set(SOURCE_FILES ${SRC})
add_executable(${LIBRARY_NAME} ${SOURCE_FILES})
target_link_libraries(${LIBRARY_NAME}
ceres
)
很简洁的CMakeLists.txt配置,利用FIND_PACKAGE
找到ceres的依赖包,再INCLUDE_DIRECTORIES
包含下EIGEN的系统路径就可以了。这些都归功于homebrew,它直接把这些包的路径帮我们捋顺好了。
安装好Ceres库以及相应的第三方库,编写好cmakelists配置文件后,就可以运行看效果啦。
在CMakeLists.txt 同目录下输入如下命令
mkdir cmake_build
cd cmake_build
cmake ..
make
./TESTCeres
最终如果看到如下的log说明Ceres配置成功并可以开心地使用啦。
Scanning dependencies of target TESTCeres
[ 50%] Building CXX object CMakeFiles/TESTCeres.dir/Users/subowen/Project/MTWideAngleUnDistortion/test/testCeres.cpp.o
[100%] Linking CXX executable TESTCeres
[100%] Built target TESTCeres
iter cost cost_change |gradient| |step| tr_ratio tr_radius ls_iter iter_time total_time
0 4.512500e+01 0.00e+00 9.50e+00 0.00e+00 0.00e+00 1.00e+04 0 6.51e-05 3.26e-04
1 4.511598e-07 4.51e+01 9.50e-04 9.50e+00 1.00e+00 3.00e+04 1 1.07e-03 1.45e-03
2 5.012552e-16 4.51e-07 3.17e-08 9.50e-04 1.00e+00 9.00e+04 1 2.48e-05 1.49e-03
Ceres Solver Report: Iterations: 3, Initial cost: 4.512500e+01, Final cost: 5.012552e-16, Termination: CONVERGENCE
x : 0.5 -> 10