Ceres Solver从零开始手把手教学使用

目录

一 、简介

二、安装

三、介绍

 四、Hello Word!

五、导数

       1 数值导数

        2解析求导

六、实践 

        Powell函数


一 、简介

        笔者已经半年没有更新新的内容了,最近学习视觉SLAM的过程中发现自己之前学习的库基础不够扎实。Ceres作为一个优化库在视觉SLAM中使用非常广泛,笔者会跟随着Ceres Solver的官方教程一直学习下来,并且会在专栏中持续更新,如需转载请声明出处

二、安装

        虽然说是从零开始教学Cere Solver的使用,但是基本linux和git指令还是需要一定基础。具体的安装步骤如下,需要不同的安装版本可以去GitHub上找到。

        1、依赖项

                Ceres Solver 2.2 需要完全符合 C++17 的编译器。

                Cmake需要3.10版本以上和Eigen3.3以上

                注意官方维护的ubuntu版本必须在18.04以上。老版本的ubuntu可能安装使用会出现不兼容。

# CMake
sudo apt-get install cmake
# google-glog + gflags
sudo apt-get install libgoogle-glog-dev libgflags-dev
# Use ATLAS for BLAS & LAPACK
sudo apt-get install libatlas-base-dev
# Eigen3
sudo apt-get install libeigen3-dev
# SuiteSparse (optional)
sudo apt-get install libsuitesparse-dev

        2、安装

                Ceres是使用Cmake进行安装的,具体的步骤如下:

tar zxf ceres-solver-2.1.0.tar.gz
mkdir ceres-bin
cd ceres-bin
cmake ../ceres-solver-2.1.0
make -j3 
make test
# Optionally install Ceres, it can also be exported using CMake which
# allows Ceres to be used without requiring installation, see the documentation
# for the EXPORT_BUILD_DIR option for more information.
make install

           安装完成之后可以测试自己是否安装成功,可以使用Ceres自带的华盛顿大学的 BAL 数据集进行测试运行看是否安装成功。

bin/simple_bundle_adjuster ../ceres-solver-2.1.0/data/problem-16-22106-pre.txt

     这将使用 DENSE_SCHUR 线性求解器运行 Ceres 最多 10 次迭代。Ceres还可以这Window、Mac、ios和Android安装。具体的安装请参看官方文档。本专栏只针对运行在linux上。

三、介绍

        Ceres可以解决以下边界约束鲁棒化的非线性最小二乘问题:

 这种形式的问题在工程领域运用的非常多比如拟合统计曲线到计算机视觉的图片构建等。

        接下来笔者将带大家一起学习Ceres Solver求解, ρi(‖fi(xi1,...,xik)‖2) 被称为ResidualBlock为残差块, fi(⋅) 为损失函数。 [xi1,...,xik]就是我们需要优化的变量,我们将它定位ParameterBlock。接下来为了理解,举一个例子。在视觉SLAM中,平移有3个分量,旋转使用四元数有4个分量,比如我们最小化重投影误差中需要优化的就是位置和位姿。lj和 uj是参数块的界限xj,当然,lj和 uj都可以取负无穷和正无穷,并且优化的参数也可以是一个,这样可以得到一个我们熟知的非线性最小化问题:

 四、Hello Word!

        学习的开始,我们将和编程一样从一个最简单的Hello Word开始!

        首先,我们先考虑以下函数的最小值:

         从式子可以看出最小值计算x=10的时候,用这样一个简单的例子来讲解Ceres。

        1、首先我们定义一个仿函数来评估函数f(x)=10−x。

                这里我先简单介绍一下什么是仿函数,这里需要一定的C++的基础。仿函数就是在类中对()运算符号进行重载。为什么要使用仿函数主要是为了方便维护类的成员函数和运行效率更高。笔者接触这个也很少,在ORB-SLAM中也同样遇到过仿函数,有空对仿函数专门进行更新。

struct CostFunctor {
   template <typename T>
   bool operator()(const T* const x, T* residual) const {
     residual[0] = 10.0 - x[0];
     return true;
   }
};

  这里解释一下输入的const T* const x, const T*x表示 *x指向的对象不可修改,T* const x表示指针不能修改,const T* const x就是两者的结合指向的对象和指针都不能进行修改。这里我们使用了模板函数,这也是C++的基本知识在这里就不详细介绍了。这里的x变量就是我们需要输入数据,x可以是n维向量。residual则是我们误差(或者残差)也就是损失函数。接下来看主函数:

int main(int, char**) {
    
    // 设置初始值
    double ininal_num=5.0;
    double x=ininal_num;

    // 构建问题Problem有两个重要的成员函数:
    // Problem::AddResidalBlock() and Problem::AddParameterBlock()
    ceres::Problem problem;

    //设置损失函数,这里使用自动求导计算雅克比矩阵以我们自己定义的CostFunctor为类型在进行初始化
    ceres::CostFunction* cost_functor=
    new ceres::AutoDiffCostFunction<CostFunctor,1,1>(new CostFunctor);
    // 添加残差
    problem.AddResidualBlock(cost_functor,nullptr,&x);

    // 配置求解器
    ceres::Solver::Options options;
    // options.max_num_iterations=20; //可以设置最大迭代次数
    options.linear_solver_type=ceres::DENSE_QR;
    options.minimizer_progress_to_stdout=true;
    ceres::Solver::Summary summary;
    //开始求解
    ceres::Solve(options,&problem,&summary);
    std::cout<<summary.BriefReport()<<"\n";
    std::cout<<"x:"<<ininal_num<<"->"<<x<<"\n";
    return 0;

}

五、导数

        和大多数的优化库一样,Ceres能够在任意参数值下估计目标函数中每个项的值和导数。上面我们就使用到了自动求导。现在我们讨论两种解析导数和数值导数。

       1 数值导数

                在某些情况下,是不能写出模板损失函数,比如损失函数使用了其他库中的函数,这样就不能使用自动求导AutoDiffCostFunction。在这种情况下我们可以使用数值导数。数值导数也和自动求导类似,首先定义一个仿函数,之后在传递给NumericDiffCostFunctor。例如:

struct NumericDiffCostFunctor {
  bool operator()(const double* const x, double* residual) const {
    residual[0] = 10.0 - x[0];
    return true;
  }
};
//添加到problem中

CostFunction* cost_function =
  new NumericDiffCostFunction<NumericDiffCostFunctor, ceres::CENTRAL, 1, 1>(
      new NumericDiffCostFunctor);
problem.AddResidualBlock(cost_function, nullptr, &x);

基本的构造和AutoDiffCostFunction相同,就是多了一个参数的输入。这个多出来参数用于计算数值导数的有限差分种类,这个之后讲解。在刚开始学习的过程官方也推荐我们最好使用自动求导

        2解析求导

                解析求导就是在以封闭式计算导数则不能使用自动求导,这是官方所说的有点难懂。简单来说就是你定义了一个抽象函数或者说这个函数中包含了更多函数时,Ceres就不能帮你自动求导了。这种情况就是自己提供残差和雅克比计算了。我们以10-x函数为例子(只是为了方便理解,这个函数可以使用自动求导解决):

class QuadraticCostFunction : public ceres::SizedCostFunction<1, 1> {
 public:
  virtual ~QuadraticCostFunction() {}
  virtual bool Evaluate(double const* const* parameters,
                        double* residuals,
                        double** jacobians) const {
    const double x = parameters[0][0];
    residuals[0] = 10 - x;

    //计算雅克比矩阵
    if (jacobians != nullptr && jacobians[0] != nullptr) {
      jacobians[0][0] = -1;
    }
    return true;
  }
};

我们重构虚函数Evaluate,第一个输入为参数数组,第二个为残差,第三个为雅克比矩阵。Evaluate检查雅克比矩阵是否为空,如果是则用残差函数的导数填充。本例子中因为是线性函数,所以是数值。

官方推荐我们如果我们有能力管理自己的雅克比计算,就使解析导数。否则还是优先自动求导和数值求导。

        Ceres提供了更多的导数计算,还有更加高级的计算DynamicAutoDiffCostFunction和CostFunctionToFunctor在之后我会进一步补充。

六、实践 

        可能你现在还一头雾水,不太理解上面代码的详细功能。接下来我将带大家完成几个例子加深对代码的理解。

        Powell函数

现在我们来考虑一个复一定的问题。powell函数x=[x1,x2,x3,x4]是F(x)中的四个参数有以下等式:

 可以看出我们有四个残差,我们希望1/2‖F(x)‖2是最小的。

首先我们从f4这个式子开始:

 首先还是一样需要定义目标函数中的项进行评估:

struct F1 {
  template <typename T>
  bool operator()(const T* const x1, const T* const x2, T* residual) const {
    // f1 = x1 + 10 * x2;
    residual[0] = x1[0] + 10.0 * x2[0];
    return true;
  }
};
struct F2 {
  template <typename T>
  bool operator()(const T* const x3, const T* const x4, T* residual) const {
    // f2 = sqrt(5) (x3 - x4)
    residual[0] = sqrt(5.0) * (x3[0] - x4[0]);
    return true;
  }
};
struct F3 {
  template <typename T>
  bool operator()(const T* const x2, const T* const x3, T* residual) const {
    // f3 = (x2 - 2 x3)^2
    residual[0] = (x2[0] - 2.0 * x3[0]) * (x2[0] - 2.0 * x3[0]);
    return true;
  }
};
struct F4 {
  template <typename T>
  bool operator()(const T* const x1, const T* const x4, T* residual) const {
    // f4 = sqrt(10) (x1 - x4)^2
    residual[0] = sqrt(10.0) * (x1[0] - x4[0]) * (x1[0] - x4[0]);
    return true;
  }
};

之后的我们开始构造问题:

 double x1 = 3.0;
  double x2 = -1.0;
  double x3 = 0.0;
  double x4 = 1.0;
  Problem problem;
     //添加残差并且使用自动求导
  problem.AddResidualBlock(
      new AutoDiffCostFunction<F1, 1, 1, 1>(new F1), nullptr, &x1, &x2);
  problem.AddResidualBlock(
      new AutoDiffCostFunction<F2, 1, 1, 1>(new F2), nullptr, &x3, &x4);
  problem.AddResidualBlock(
      new AutoDiffCostFunction<F3, 1, 1, 1>(new F3), nullptr, &x2, &x3);
  problem.AddResidualBlock(
      new AutoDiffCostFunction<F4, 1, 1, 1>(new F4), nullptr, &x1, &x4);

之后的优化和之前一样配置就可以了:

Solver::Options options;
options.max_num_iterations = 100;
options.linear_solver_type = ceres::DENSE_QR;
options.minimizer_progress_to_stdout = true;
Solver::Summary summary;
Solve(options, &problem, &summary);
std::cout << summary.FullReport() << "\n";

从我们自身进行观察我们就可以看出最优解是x1=x2=x3=x4=0 ,可以看出最终的优化结果也是是否接近。

 

  • 3
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
### 回答1: 如果您在Ubuntu 18.04系统上安装ceres-solver,您可以使用以下步骤进行安装: 1. 更新您的系统: ``` sudo apt-get update sudo apt-get upgrade ``` 2. 安装必要的软件包: ``` sudo apt-get install libatlas-base-dev libsuitesparse-dev ``` 3. 下载并安装Ceres Solver: ``` wget http://ceres-solver.org/ceres-solver-1.14.0.tar.gz tar xvf ceres-solver-1.14.0.tar.gz cd ceres-solver-1.14.0 mkdir build cd build cmake .. make sudo make install ``` 4. 检查安装是否成功: ``` ceres_version ``` 如果它输出了Ceres Solver的版本号,则说明安装成功。 请注意,在安装过程中,您可能需要先安装一些其他的依赖项,如果您在安装过程中遇到问题,请检查您的系统是否缺少任何必要的软件包。 ### 回答2: Ubuntu18.04是一种广泛使用的开源操作系统,而Ceres-solver则是一种用于最小化非线性代数方程的C ++,被广泛应用于计算机视觉和机器人领域。在本文中,我们将探讨如何在Ubuntu18.04上安装Ceres-solver。 方法一:通过软件包管理器安装 Ubuntu18.04已经包含了Ceres-solver,因此我们可以通过软件包管理器轻松地安装它。具体步骤如下: 1. 通过终端窗口打开软件包管理器: ``` sudo apt-get update sudo apt-get install libceres-dev ``` 2. 安装后,我们可以检查Ceres-solver是否成功安装。通过终端窗口输入以下命令进行检查: ``` pkg-config --modversion ceres ``` 如果Ceres-solver成功安装,则会显示Ceres-solver的版本号。 方法二:通过源代码安装 如果您想安装最新版本的Ceres-solver,或者如果软件包管理器无法提供所需的版本,则可以通过源代码安装。具体步骤如下: 1. 从Ceres-solver官方网站下载 Ceres-solver的源代码:http://ceres-solver.org/installation.html 2. 下载后,将压缩文件解压缩。在终端窗口中进入解压缩后的文件夹,并运行以下命令: ``` sudo mkdir build cd build sudo cmake .. sudo make sudo make install ``` 3. 安装完成后,我们可以检查Ceres-solver是否成功安装。通过终端窗口输入以下命令进行检查: ``` pkg-config --modversion ceres ``` 如果Ceres-solver成功安装,则会显示Ceres-solver的版本号。 总结: 通过软件包管理器安装Ceres-solver可能更为简单,但这并不意味着源代码安装不是好选择。如果您想安装最新版本的软件,或者 Ubuntu 软件包管理器没有所需软件包。我们希望这篇文章对您有所帮助,让您成功在Ubuntu18.04上安装Ceres-solver。 ### 回答3: ceres-solver是一个广泛应用于计算机视觉、机器人和自动驾驶领域的C++,它提供了许多优秀的优化算法。在ubuntu18.04中安装ceres-solver非常简单,下面给出步骤: 1. 打开终端,安装必要的依赖:sudo apt-get install cmake libgoogle-glog-dev libatlas-base-dev 2. 从官方网站下载ceres-solver的源代码包,解压tar.gz包到/home/user/文件夹中(user为当前用户名),并进入解压后的文件夹 3. 在终端中进入解压后的文件夹,先建立build文件夹:`mkdir build`, 然后进入该文件夹:`cd build` 4. 对于64位系统的用户,可以在终端中使用如下命令设置编译器参数:cmake .. -DCMAKE_CXX_FLAGS="-std=c++11"【注:-std=c++11是C++11标准,用于支持新的特性】;对于32位系统的用户,使用cmake .. 就可以了 5. 在终端中输入:make -j4(其中- j 后面的数字是并行编译的数量,按实际情况进行调整),编译源代码,此时电脑会开始编译并生成ceres-solver,时间较长,请耐心等待。 6. 输入如下命令进行安装:sudo make install 7. 检查是否安装成功,在终端中输入:pkg-config --modversion ceres。若显示版本号,则代表安装成功。 这样,ceres-solver已经成功安装到了ubuntu18.04系统中。此时您可以在自己的程序中使用ceres-solver,实现自动优化和计算。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

每日亿学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值