非线性最小二乘库 ceres

 

  1. ceres::Problem problem   生成一个非线性最小二乘problem

     2. struct/class costFunctor{ 

         代价函数,用以计算jacobin矩阵

         template<typename t> bool operator(){}

         }

     3.probelm.AddResidualBlock(new AutoDiffCostFunction<costFunctor,1,1,1>(new costFunctor())); 生成jacobin

     4.Solver::Options  非线性最小二乘求解时的选项,如迭代次数,矩阵分解方法等

     5.Solver::Summary summary

     6.Solve(options,&problem,&summary)

总体来说,ceres库就像是一个黑盒,只需要把测量值和观测值输入代价函数中,即可自动求解jacobin矩阵,并进行非线性最小二乘迭代。

//1.构造代价函数

// Templated pinhole camera model for used with Ceres.  The camera is

// parameterized using 9 parameters: 3 for rotation, 3 for translation, 1 for

// focal length and 2 for radial distortion. The principal point is not modeled

// (i.e. it is assumed be located at the image center).

/*该简易simple_bundle_adjuster只优化9个参数,包括3个旋转,3个平移,1个焦距,2个径向畸变因子等。主点被认为是在图像中心,

该结构体用来描述代价函数,其中待优化的未知数为camera,包括之前所说的9个参数;point表示三维点,structure*/

struct SnavelyReprojectionError {

  SnavelyReprojectionError(double observed_x, double observed_y)

      : observed_x(observed_x), observed_y(observed_y) {}

  template <typename T>

  bool operator()(const T* const camera,

                  const T* const point,

                  T* residuals) const {

    // camera[0,1,2] are the angle-axis rotation.

    T p[3];

    ceres::AngleAxisRotatePoint(camera, point, p);

    // camera[3,4,5] are the translation.

    p[0] += camera[3];

    p[1] += camera[4];

    p[2] += camera[5];

    // Compute the center of distortion. The sign change comes from

    // the camera model that Noah Snavely's Bundler assumes, whereby

    // the camera coordinate system has a negative z axis.

    T xp = - p[0] / p[2];

    T yp = - p[1] / p[2];

    // Apply second and fourth order radial distortion.

    const T& l1 = camera[7];

    const T& l2 = camera[8];

    T r2 = xp*xp + yp*yp;

    T distortion = 1.0 + r2  * (l1 + l2  * r2);

    // Compute final projected point position.

    const T& focal = camera[6];

    T predicted_x = focal * distortion * xp;

    T predicted_y = focal * distortion * yp;

    // The error is the difference between the predicted and observed position.

    residuals[0] = predicted_x - observed_x;

    residuals[1] = predicted_y - observed_y;

    return true;

  }

//该代价函数实现了重投影过程。

//2.构造代价函数的偏导数  

// Factory to hide the construction of the CostFunction object from

  // the client code.

//对构造生成的代价函数求偏导

  static ceres::CostFunction* Create(const double observed_x,

                                     const double observed_y) {

    return (new ceres::AutoDiffCostFunction<SnavelyReprojectionError, 2, 9, 3>(

                new SnavelyReprojectionError(observed_x, observed_y)));

  }

  double observed_x;

  double observed_y;

};

3.在构造好代价函数的偏导数后,利用solve求解非线性最小二乘

// Create residuals for each observation in the bundle adjustment problem. The

// parameters for cameras and points are added automatically.

//读取文件中的相机参数和三维点,按照costFunction计算梯度

  ceres::Problem problem;

  for (int i = 0; i < bal_problem.num_observations(); ++i) {

    // Each Residual block takes a point and a camera as input and outputs a 2

    // dimensional residual. Internally, the cost function stores the observed

    // image location and compares the reprojection against the observation.

    ceres::CostFunction* cost_function =

        SnavelyReprojectionError::Create(observations[2 * i + 0],

                                         observations[2 * i + 1]);

    problem.AddResidualBlock(cost_function,

                             NULL /* squared loss */,

                             bal_problem.mutable_camera_for_observation(i),

                             bal_problem.mutable_point_for_observation(i));

  }

  // Make Ceres automatically detect the bundle structure. Note that the

  // standard solver, SPARSE_NORMAL_CHOLESKY, also works fine but it is slower

  // for standard bundle adjustment problems.

  ceres::Solver::Options options;

  options.linear_solver_type = ceres::DENSE_SCHUR;

  options.minimizer_progress_to_stdout = true;

  ceres::Solver::Summary summary;

  ceres::Solve(options, &problem, &summary);

  std::cout << summary.FullReport() << "\n";

结论:

目前对ceres的理解只到达整体框架的程度,但是对于

1)其内部如何求偏导

2)选用何种非线性最小二乘算法

等具体的内部如何实现还不清晰。

 

清晰一发:

对于一个BA问题,如有p个相机,q个三维点。变量向量x有如下的块结构:

x = [y1,...,yp,z1,...,zq].

其中,y对应相机参数,相机参数块个数c=6/9

    z对应三维点参数,参数个数s=3

对于BA问题,求解的是 JTJ * X = b

针对JTJ=H

H矩阵又可以写成上述形式,其中B是一个pc*pc的块稀疏矩阵

                 C是一个qs*qs的块对焦矩阵

                 E是一个pc*qs的块稀疏矩阵

上述线性方程求解可写成:

对上述系数矩阵进行高斯消元,可以得到C是一个块对角矩阵,并且每个块也是对焦矩阵。因此,求解C的逆是非常简单,并且运算代价非常小的。因此,利用C矩阵这一特性,可以消去Δz。

,将其带入分块矩阵第一行,可得,

则最终就简化成,只需要计算pc*pc大小的系数矩阵块的线性方程组了。而且在一般情况下,相机数量p是远小于三维点数量q的。

 

还有两处不理解:

为什么三维点对应的矩阵块C是块对角的?

 

回答上头的问题:

BA中正规方程的稀疏性分析

这里以一个例子进行说明:

如图所示,以两个相机和六个三维点的对应作为样例,说明BA的稀疏性,首先列写jacobin矩阵J,并计算JTJ,可以看出,对应相机元素的矩阵块,是块对角矩阵,对应三维点元素的矩阵块,也是块对角矩阵,对三维点的元素的块进行高斯消元,可以得到一个3x3的对角矩阵,因此,整个三维点元素对应的分块矩阵就是一个对角矩阵,因此在求解时,可以直接求倒数得到矩阵块的逆。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值