天天看點

非線性最小二乘庫 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).

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 ,

                             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

非線性最小二乘庫 ceres

H矩陣又可以寫成上述形式,其中B是一個pc*pc的塊稀疏矩陣

                 C是一個qs*qs的塊對焦矩陣

                 E是一個pc*qs的塊稀疏矩陣

上述線性方程求解可寫成:

非線性最小二乘庫 ceres
非線性最小二乘庫 ceres

對上述系數矩陣進行高斯消元,可以得到C是一個塊對角矩陣,并且每個塊也是對焦矩陣。是以,求解C的逆是非常簡單,并且運算代價非常小的。是以,利用C矩陣這一特性,可以消去Δz。

非線性最小二乘庫 ceres

,将其帶入分塊矩陣第一行,可得,

非線性最小二乘庫 ceres

則最終就簡化成,隻需要計算pc*pc大小的系數矩陣塊的線性方程組了。而且在一般情況下,相機數量p是遠小于三維點數量q的。

還有兩處不了解:

為什麼三維點對應的矩陣塊C是塊對角的?

回答上頭的問題:

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

這裡以一個例子進行說明:

如圖所示,以兩個相機和六個三維點的對應作為樣例,說明BA的稀疏性,首先列寫jacobin矩陣J,并計算JTJ,可以看出,對應相機元素的矩陣塊,是塊對角矩陣,對應三維點元素的矩陣塊,也是塊對角矩陣,對三維點的元素的塊進行高斯消元,可以得到一個3x3的對角矩陣,是以,整個三維點元素對應的分塊矩陣就是一個對角矩陣,是以在求解時,可以直接求倒數得到矩陣塊的逆。

非線性最小二乘庫 ceres

繼續閱讀