Ceres 翻译为谷神星,是太阳系中的一颗矮行星,于1801年被意大利神父 Piazzi 首次观测到,但随后 Piazzi 因为生病,跟丢了它的运行轨迹。

几个月后,德国数学家 Gauss,利用最小二乘法,仅仅依靠 Piazzi 之前观测到的12个数据,便成功的预测了谷神星的运行轨迹。

两百多年后,为了解决一些复杂的最优化问题 (如:带边界约束的非线性最小二乘、一般的无约束最优化等),谷歌开发了一个 C++ 库 Ceres Solver

之所以取名 Ceres Solver,是为了纪念 Gauss 利用最小二乘法,成功的预测了谷神星轨迹,这个在最优化、统计学、天文学历史上,都具有重要意义的事件

1  Ceres 简介

1.1  特点

1) 模型接口简洁

- 求导简单;鲁棒的损失函数;局部参数化

2) 求解方法多

- 信赖域法:Lenberg-Marquardt, Powell’s Dogleg, Subspace dogleg

- 线搜索法:Non-linear Conjugate Gradients, BFGS, LBFGS

3) 求解质量高

- 在 NIST 数据集下,按照 Mondragon 和 Borchers 的测试标准,Ceres 的准确度最高

1.2  应用

在谷歌内部,Ceres 已经被应用于多个产品中,如:谷歌街景中汽车、飞行器的位姿估计;PhotoTours 中 3D 模型的建立;SLAM 算法 Cartographer 等

此外,一些公司和研究所也在使用 Ceres,像是 Southwest Research Institute 的机器人视觉系统标定,OpenMVG 的光束平差 (BA) 问题,Willow Garage 的 SLAM 问题等

1.3  非线性最小二乘

带边界约束的非线性最小二乘形式,如下:

$\quad \begin{split} \min_x &\quad \frac{1}{2}\sum_{i} \rho_i\left(\left\|f_i\left(x_{i_1}, x_{i_2}, ... ,x_{i_k}\right)\right\|^2\right) \\\text{s.t.} &\quad l_j \le x_j \le u_j \end{split}$

其中,1) s.t. = "subject to",限定了 $x_j$ 的取值范围

2) $ \rho_i\left(\left\|f_i\left(x_{i_1},x_{i_2},...,x_{i_k}\right)\right\|^2\right) $ 为残差块

3) $f_i(\cdot)$ 为代价函数,取决于参数块 $\left[x_{i_1},x_{i_2},... , x_{i_k}\right]$

4) $\rho_i$ 为损失函数,是一个标量函数,主要用来消除异常点对求解过程的影响

如果令损失函数 $\rho_i = x$ 为恒等函数,且放宽边界约束条件为 $[-\infty, \infty]$

则非线性最小二乘问题,可简化为如下形式:

$\quad \begin{split}\frac{1}{2}\sum_{i} \left\|f_i\left(x_{i_1}, ... ,x_{i_k}\right)\right\|^2 \end{split}$

上面的最小二乘形式,在科学和工程领域有着广泛的应用,例如,统计学中的曲线拟合,计算机视觉的三维重建等

2  编译配置

Win10  64-bit ;VS 2019 社区版,下载地址 ;CMake 解压版,下载地址

2.1  源文件

- Ceres Solver 源文件,下载地址,从 2.0 开始,需要支持 C++14 的编译器

- eigen 源文件,必须,>=3.3,下载地址

- glog 源文件,推荐,>=0.3.1,下载地址,及其依赖库 gflags,下载地址

2.2  配置生成

1)  将源文件 ceres、eigen、glog 和 gflags 解压,运行 cmake-gui.exe,配置生成 eigen (先点 "Configure",再点 "Generate" 即可)

2)  编译 gflags,先点 "Configure",再点 "Generate",然后点 "Open Project",在 VS 中打开工程,最后在 debug 和 release 模式下分别编译

3)  编译 glog,操作同 3),其中 cmake 配置不再赘述,如:CMAKE_CONFGURATION_TYPES 只保留 Debug 和 Release,gflags_DIR 指向含 gflags-config.cmake 的目录等

4)  编译 ceres,操作同 3),注意配置 eigen、glog 和 gflags 的 _DIR 目录,并勾上 BUILD_SHARED_LIBS 以便生成 dll 库

2.3  VS 配置

将生成的 .lib 和 .dll 文件放在特定目录下,并新建 include 文件夹,汇总对应的 .h 文件

  1)环境变量

计算机 -> 属性 -> 高级系统设置 -> 环境变量,编辑系统变量里的 path 变量

D:\3rdparty\gflags\bin\Debug
D:\3rdparty\glog\bin\Debug
D:\3rdparty\ceres\bin\Debug  

  2)  头文件和库文件

在 VS 中配置 ceres, eigen, glog 和 gflags 的 头文件目录,以及 库文件目录

注:在编译时,若出现头文件缺失,则在源文件中找到对应的 .h,拷贝到 include 目录中即可

  3)  依赖库

添加对应的 .lib 依赖库,如下:

ceres-debug.lib
gflags_debug.lib
glogd.lib

  4)  错误处理

运行程序,如出现如下错误,则在 "项目属性 - 预处理器定义" 中,定义 _USE_MATH_DEFINES 宏可解决

3  代码实例

给定一个目标函数 $\begin{split} \frac{1}{2}(10 -x)^2 \end{split}$,求其取最小值时,对应的 $x$ 为多少

3.1  求解步骤

    1)  构建代价函数

Ceres 中利用仿函数,通过重载 operator() 运算符,来实现代价函数的定义,本例中的代价函数为 $f(x) = 10 -x $

// A templated cost functor that implements the residual r = x - 10
struct CostFunctor {
template <typename T> bool operator()(const T* const x, T* residual) const {
residual[0] = x[0] - 10.0;
return true;
}
};  

    2)  构建残差块

   // Build the problem
Problem problem;
// Set up the cost function (also known as residual)
CostFunction* cost_function = new AutoDiffCostFunction<CostFunctor, 1, 1>(new CostFunctor);
problem.AddResidualBlock(cost_function, NULL, &x);  

    3)  配置求解器

    // The options structure, which controls how the solver operates
Solver::Options options;
options.linear_solver_type = ceres::DENSE_QR;
options.minimizer_progress_to_stdout = true;  

    4)  求解

    // Run the solver
Solver::Summary summary;
Solve(options, &problem, &summary);

3.2  完整代码      

#include "ceres/ceres.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 = x - 10.
struct CostFunctor {
template <typename T> bool operator()(const T* const x, T* residual) const {
residual[0] = 10.0 - x[0];
return true;
}
}; int main()
{
// The variable to solve for with its initial value
double x = 0.5;
const double initial_x = x; // Build the problem.
Problem problem;
// Set up the cost function (also known as residual)
CostFunction* cost_function = new AutoDiffCostFunction<CostFunctor, 1, 1>(new CostFunctor);
problem.AddResidualBlock(cost_function, NULL, &x); // The options structure, which controls how the solver operates
Solver::Options options;
options.linear_solver_type = ceres::DENSE_QR;
options.minimizer_progress_to_stdout = true; // Run solver
Solver::Summary summary;
Solve(options, &problem, &summary); std::cout << summary.BriefReport() << "\n";
std::cout << "x : " << initial_x << " -> " << x << "\n";
}  

运行结果如下:

参考资料

Ceres Solver 在 Windows 下的安装

Mondragon 和 Borchers 标准对比测试

Ceres 四重奏 之 入门简介的更多相关文章

  1. 掌握 Ajax,第 1 部分: Ajax 入门简介

    转:http://www.ibm.com/developerworks/cn/xml/wa-ajaxintro1.html 掌握 Ajax,第 1 部分: Ajax 入门简介 理解 Ajax 及其工作 ...

  2. MongoDB入门简介

    MongoDB入门简介 http://blog.csdn.net/lolinzhang/article/details/4353699 有关于MongoDB的资料现在较少,且大多为英文网站,以上内容大 ...

  3. (转)Web Service入门简介(一个简单的WebService示例)

    Web Service入门简介 一.Web Service简介 1.1.Web Service基本概念 Web Service也叫XML Web Service WebService是一种可以接收从I ...

  4. NodeJS入门简介

    NodeJS入门简介 二.模块 在Node.js中,以模块为单位划分所有功能,并且提供了一个完整的模块加载机制,这时的我们可以将应用程序划分为各个不同的部分. const http = require ...

  5. ASP.NET Core学习之一 入门简介

    一.入门简介 在学习之前,要先了解ASP.NET Core是什么?为什么?很多人学习新技术功利心很重,恨不得立马就学会了. 其实,那样做很不好,马马虎虎,联系过程中又花费非常多的时间去解决所遇到的“问 ...

  6. webservice入门简介

    为了梦想,努力奋斗! 追求卓越,成功就会在不经意间追上你 webservice入门简介 1.什么是webservice? webservice是一种跨编程语言和跨操作系统平台的远程调用技术. 所谓的远 ...

  7. Web Service入门简介(一个简单的WebService示例)

    Web Service入门简介 一.Web Service简介 1.1.Web Service基本概念 Web Service也叫XML Web Service WebService是一种可以接收从I ...

  8. Android精通教程-第一节Android入门简介

    前言 大家好,给大家带来Android精通教程-第一节Android入门简介的概述,希望你们喜欢 每日一句 If life were predictable it would cease to be ...

  9. Nginx入门简介

    Nginx入门简介 Nginx 介绍 Nginx (engine x) 是一个高性能的HTTP和反向代理服务,也是一个IMAP/POP3/SMTP服务.Nginx是由伊戈尔·赛索耶夫为俄罗斯访问量第二 ...

随机推荐

  1. python+appium运行提示找不到adb.exe “An unknown server-side error occurred while processing the command. Original error: Could not find 'adb.exe' in ["D:\\adt\\sdk;\\platform-tools\\adb.exe"”

    自己踩过的坑,不记下来就会忘掉,忘了就会不断的重复踩坑!! 重来在一台电脑上搭建了python的环境,在运行的时候,提示找不到adb.exe,看到这个问题我在想是不是我的环境变量配置有问题,我就去改了 ...

  2. HttpRunner_参数化进阶

    一.获取返回包数据   在提取参数时,当 HTTP 的请求响应结果为 JSON 格式,则可以采用.运算符的方式,逐级往下获取到参数值:响应结果的整体内容引用方式为 content 或者 body,如上 ...

  3. Hive的导入导出和常用过滤语句的学习

    原文: https://www.toutiao.com/i6769166601871688196/?group_id=6769166601871688196 数据的导入 load data [loca ...

  4. 曾经大量使用的Model1开发模式,虽不常用,但可以帮我们理解JSP

    注:图片如果损坏,点击文章链接:https://www.toutiao.com/i6513394762370777604/ 1.<JSP页面实际上就是Servlet> 2.<JSP页 ...

  5. 如何向内核提交补丁?——FirstKernelPatch

    参考 https://kernelnewbies.org/FirstKernelPatch

  6. ffmpeg+nginx截取屏幕实时画面并进行rtmp推流在前端播放

    准备环境和文件 1.下载ffmpeg的包[https://foxbaby.lanzoui.com/iYjPmup51cd] 地址:https://ffmpeg.org/download.html#bu ...

  7. Sentry 开发者贡献指南 - 测试技巧

    作为 CI 流程的一部分,我们在 Sentry 运行了多种测试. 本节旨在记录一些 sentry 特定的帮助程序, 并提供有关在构建新功能时应考虑包括哪些类型的测试的指南. 获取设置 验收和 pyth ...

  8. JSP页面打印输出,两种方法。out、《%=

    使用out.println()输出: <%@ page contentType="text/html;charset=UTF-8"%> <html> < ...

  9. 【解决了一个小问题】golang中引用一个路径较长的库,导致goland中出现"module contains a go.mod file, so major version must be compatible: should be v0 or v1, not v2"

    在项目中的go.mod文件中有这样一句: require ( github.com/xxx-devops/xx1/sdk/go v2.2.3 ) 项目的编译没有问题,但是goland中出现如下提示: ...

  10. FHQtreap(我有个绝妙的理解方法,但课的时间不够[doge])

    FHQtreap板子(P1486 [NOI2004] 郁闷的出纳员) 会了FHQ,treap什么的就忘了吧...... #include<bits/stdc++.h> using name ...