zl程序教程

您现在的位置是:首页 >  工具

当前栏目

(01)ORB-SLAM2源码无死角解析-(43) EPnP 源代码分析(3)→find_betas_approx(),gauss_newton()

源码 分析 解析 01 源代码 Find 43 ORB
2023-09-14 09:13:06 时间

讲解关于slam一系列文章汇总链接:史上最全slam从零开始,针对于本栏目讲解的(01)ORB-SLAM2源码无死角解析链接如下(本文内容来自计算机视觉life ORB-SLAM2 课程课件):
(01)ORB-SLAM2源码无死角解析-(00)目录_最新无死角讲解:https://blog.csdn.net/weixin_43013761/article/details/123092196
 
文末正下方中心提供了本人 联系方式, 点击本人照片即可显示 W X → 官方认证 {\color{blue}{文末正下方中心}提供了本人 \color{red} 联系方式,\color{blue}点击本人照片即可显示WX→官方认证} 文末正下方中心提供了本人联系方式,点击本人照片即可显示WX官方认证
 

一、前言

上一篇博客对 src/PnPsolver.cc 文件中的 compute_pose() 函数分析,并且对其中调用的 choose_control_points(),compute_barycentric_coordinates() 进行了讲解,知道了代码中是如何求得 四个控制点,以及它们对应的系数,并且进一步求得了 相机坐标系下的控制点。有了这些信息,根据前面博客 (01)ORB-SLAM2源码无死角解析-(38) EPnP 算法原理详解→理论基础二:分情况求得beta初始解 可以建立矩阵方程:
N = 4 的情况 : \color{blue}{N=4的情况}: N=4的情况:
L 6 × 4 ⋅ β 4 × 1 = ρ 6 × 1 (16) \color{Green} \tag{16} \mathbf{L}_{6 \times 4} \cdot \boldsymbol{\beta}_{4 \times 1}=\boldsymbol{\rho}_{6 \times 1} L6×4β4×1=ρ6×1(16) N = 3 的情况 : \color{blue}{N=3的情况}: N=3的情况:
L 6 × 5 ⋅ β 5 × 1 = ρ 6 × 1 (19) \color{Green} \tag{19} \mathbf{L}_{6 \times 5} \cdot \boldsymbol{\beta}_{5 \times 1}=\boldsymbol{\rho}_{6 \times 1} L6×5β5×1=ρ6×1(19) N = 2 的情况 : \color{blue}{N=2的情况}: N=2的情况:
L 6 × 3 ⋅ β 3 × 1 = ρ 6 × 1 (22) \color{Green} \tag{22} \mathbf{L}_{6 \times 3} \cdot \boldsymbol{\beta}_{3 \times 1}=\boldsymbol{\rho}_{6 \times 1} L6×3β3×1=ρ6×1(22) N = 1 的情况 ( 存在闭解 , 直接求解即可 ) : \color{blue}{N=1的情况(存在闭解,直接求解即可)}: N=1的情况(存在闭解,直接求解即可): β = ∑ { i , j } ∈ [ 1 : 4 ] ∥ v [ i ] − v [ j ] ∥ ⋅ ∥ c i w − c j w ∥ ∑ { i , j } ∈ [ 1 : 4 ] ∥ v [ i ] − v [ j ] ∥ 2 (06) \color{Green} \tag{06} \beta=\frac{\sum_{\{i, j\} \in[1: 4]}\left\|\mathbf{v}^{[i]}-\mathbf{v}^{[j]}\right\| \cdot\left\|\mathbf{c}_{i}^{w}-\mathbf{c}_{j}^{w}\right\|}{\sum_{\{i, j\} \in[1: 4]}\left\|\mathbf{v}^{[i]}-\mathbf{v}^{[j]}\right\|^{2}} β={i,j}[1:4] v[i]v[j] 2{i,j}[1:4] v[i]v[j] ciwcjw (06)
通过如上方程即可求得 β \boldsymbol{\beta} β 的初始解,进一步通过高斯牛顿迭代对其进行优化。下面我们就来看看源码中的实现,其代码都位于src/PnPsolver.cc 文件中,在 compute_pose() 函数中可以看到如下代码:

  // 求解近似解:N=4的情况
  find_betas_approx_1(&L_6x10, &Rho, Betas[1]);
  // 高斯牛顿法迭代优化得到 beta
  gauss_newton(&L_6x10, &Rho, Betas[1]);
  
  // 求解近似解:N=2的情况
  find_betas_approx_2(&L_6x10, &Rho, Betas[2]);
  gauss_newton(&L_6x10, &Rho, Betas[2]);

  // 求解近似解:N=3的情况
  find_betas_approx_3(&L_6x10, &Rho, Betas[3]);
  gauss_newton(&L_6x10, &Rho, Betas[3]);

 

二、find_betas_approx_1

/**
 * @brief 计算N=4时候的粗糙近似解,暴力将其他量置为0
 * 
 * @param[in]  L_6x10  矩阵L
 * @param[in]  Rho     非齐次项 \rho, 列向量
 * @param[out] betas   计算得到的beta
 */
void PnPsolver::find_betas_approx_1(const CvMat * L_6x10, const CvMat * Rho,
			       double * betas)
{
  // 计算N=4时候的粗糙近似解,暴力将其他量置为0
  // betas10        = [B11 B12 B22 B13 B23 B33 B14 B24 B34 B44]  -- L_6x10中每一行的内容
  // betas_approx_1 = [B11 B12     B13         B14            ]  -- L_6x4 中一行提取出来的内容

  double l_6x4[6 * 4], b4[4];
  CvMat L_6x4 = cvMat(6, 4, CV_64F, l_6x4);
  CvMat B4    = cvMat(4, 1, CV_64F, b4);

  // 提取L_6x10矩阵中每行的第0,1,3,6个元素,得到L_6x4
  for(int i = 0; i < 6; i++) {
    cvmSet(&L_6x4, i, 0, cvmGet(L_6x10, i, 0)); //将L_6x10的第i行的第0个元素设置为L_6x4的第i行的第0个元素
    cvmSet(&L_6x4, i, 1, cvmGet(L_6x10, i, 1));
    cvmSet(&L_6x4, i, 2, cvmGet(L_6x10, i, 3));
    cvmSet(&L_6x4, i, 3, cvmGet(L_6x10, i, 6));
  }

  // SVD方式求解方程组 L_6x4 * B4 = Rho
  cvSolve(&L_6x4, Rho, &B4, CV_SVD);
  // 得到的解是 b00 b01 b02 b03 因此解出来b00即可
  if (b4[0] < 0) {
    betas[0] = sqrt(-b4[0]);
    betas[1] = -b4[1] / betas[0];
    betas[2] = -b4[2] / betas[0];
    betas[3] = -b4[3] / betas[0];
  } else {
    betas[0] = sqrt(b4[0]);
    betas[1] = b4[1] / betas[0];
    betas[2] = b4[2] / betas[0];
    betas[3] = b4[3] / betas[0];
  }
}

 

三、find_betas_approx_2

/**
 * @brief 计算N=2时候的粗糙近似解,暴力将其他量置为0
 * 
 * @param[in]  L_6x10  矩阵L
 * @param[in]  Rho     非齐次项 \rho, 列向量
 * @param[out] betas   计算得到的beta
 */
void PnPsolver::find_betas_approx_2(const CvMat * L_6x10, const CvMat * Rho,
			       double * betas)
{
  // betas10        = [B11 B12 B22 B13 B23 B33 B14 B24 B34 B44]
  // betas_approx_2 = [B11 B12 B22                            ] 
  double l_6x3[6 * 3], b3[3];
  CvMat L_6x3  = cvMat(6, 3, CV_64F, l_6x3);
  CvMat B3     = cvMat(3, 1, CV_64F, b3);

  // 提取
  for(int i = 0; i < 6; i++) {
    cvmSet(&L_6x3, i, 0, cvmGet(L_6x10, i, 0));
    cvmSet(&L_6x3, i, 1, cvmGet(L_6x10, i, 1));
    cvmSet(&L_6x3, i, 2, cvmGet(L_6x10, i, 2));
  }

  // 求解方程组
  cvSolve(&L_6x3, Rho, &B3, CV_SVD);

  // 从b11 b12 b22 中恢复 b1 b2
  if (b3[0] < 0) {
    betas[0] = sqrt(-b3[0]);
    betas[1] = (b3[2] < 0) ? sqrt(-b3[2]) : 0.0;
  } else {
    betas[0] = sqrt(b3[0]);
    betas[1] = (b3[2] > 0) ? sqrt(b3[2]) : 0.0;
  }

  if (b3[1] < 0) betas[0] = -betas[0];

  // 这俩没有使用到
  betas[2] = 0.0;
  betas[3] = 0.0;
}

 

四、find_betas_approx_3

/**
 * @brief 计算N=3时候的粗糙近似解,暴力将其他量置为0
 * 
 * @param[in]  L_6x10  矩阵L
 * @param[in]  Rho     非齐次项 \rho, 列向量
 * @param[out] betas   计算得到的beta
 */
void PnPsolver::find_betas_approx_3(const CvMat * L_6x10, const CvMat * Rho,
			       double * betas)
{
  // betas10        = [B11 B12 B22 B13 B23 B33 B14 B24 B34 B44]
  // betas_approx_3 = [B11 B12 B22 B13 B23                    ]
  double l_6x5[6 * 5], b5[5];
  CvMat L_6x5 = cvMat(6, 5, CV_64F, l_6x5);
  CvMat B5    = cvMat(5, 1, CV_64F, b5);

  // 获取并构造矩阵
  for(int i = 0; i < 6; i++) {
    cvmSet(&L_6x5, i, 0, cvmGet(L_6x10, i, 0));
    cvmSet(&L_6x5, i, 1, cvmGet(L_6x10, i, 1));
    cvmSet(&L_6x5, i, 2, cvmGet(L_6x10, i, 2));
    cvmSet(&L_6x5, i, 3, cvmGet(L_6x10, i, 3));
    cvmSet(&L_6x5, i, 4, cvmGet(L_6x10, i, 4));
  }

  // 求解这个方程组
  cvSolve(&L_6x5, Rho, &B5, CV_SVD);

  // 从 B11 B12 B22 B13 B23 中恢复出 B1 B2 B3
  if (b5[0] < 0) {
    betas[0] = sqrt(-b5[0]);
    betas[1] = (b5[2] < 0) ? sqrt(-b5[2]) : 0.0;
  } else {
    betas[0] = sqrt(b5[0]);
    betas[1] = (b5[2] > 0) ? sqrt(b5[2]) : 0.0;
  }
  if (b5[1] < 0) betas[0] = -betas[0];
  betas[2] = b5[3] / betas[0];

  // N=3的时候没有B4
  betas[3] = 0.0;
}

 

六、gauss_newton

通过上面的代码注释,很详细的展示出了分情况求得beta初始解的过程,其原理也比较简单,就是先建立缩小版本的 L β = ρ \mathbf L \boldsymbol {\beta}=\boldsymbol{\rho} Lβ=ρ 矩阵方程,然后通过 SVD奇异值分解获得最优解。进一步通过高斯牛顿迭代对其进行优化,代码注释如下:

/**
 * @brief 对计算出来的Beta结果进行高斯牛顿法优化,求精. 过程参考EPnP论文中式(15) 
 * 
 * @param[in] L_6x10  
 * @param[in] Rho 
 * @param[in] betas 
 */
void PnPsolver::gauss_newton(const CvMat * L_6x10, const CvMat * Rho,
			double betas[4])
{
  // 只进行5次迭代
  const int iterations_number = 5;

  /** 这里是求解增量方程组Ax=B,其中的x就是增量. 根据论文中的式15,可以得到优化的目标函数为:
   *  \f$ f(\mathbf{\beta})=\sum_{(i,j \  s.t. \  i<j)} 
   *      \left( ||\mathbf{c}^c_i-\mathbf{c}^c_j ||^2 - ||\mathbf{c}^w_i-\mathbf{c}^w_j ||^2 \right) \f$
   * 而根据高斯牛顿法,增量方程为:
   * \f$ \mathbf{H}\mathbf{\Delta x}=\mathbf{g} \f$ 
   * 也就是:(参考视觉SLAM十四讲第一版P112式6.21 6.22)
   * \f$ \mathbf{J}^T\mathbf{J}\mathbf{\Delta x}=-\mathbf{J}^T f(x) \f$
   * 不过这里在计算的时候将等式左右两边的雅克比 \f$ \mathbf{J}^T \f$ 都给约去了,得到精简后的增量方程:
   * \f$  \mathbf{J}\mathbf{\Delta x}=-f(x) \f$
   * 然后分别对应为程序代码中的系数矩阵A和非齐次项B.
   */
  double a[6*4], b[6], x[4];
  CvMat A = cvMat(6, 4, CV_64F, a);   // 系数矩阵
  CvMat B = cvMat(6, 1, CV_64F, b);   // 非齐次项
  CvMat X = cvMat(4, 1, CV_64F, x);   // 增量,待求量

  // 对于每次迭代过程
  for(int k = 0; k < iterations_number; k++) {
    // 计算增量方程的系数矩阵和非齐次项
    compute_A_and_b_gauss_newton(L_6x10->data.db, Rho->data.db,
				 betas, &A, &B);
    // 使用QR分解来求解增量方程,解得当前次迭代的增量X
    qr_solve(&A, &B, &X);

    // 应用增量,对估计值进行更新;估计值是beta1~beta4组成的向量
    for(int i = 0; i < 4; i++)
      betas[i] += x[i];
  }
}

从源码上看,也就是比较建档的,就是求得增量方程的系数矩阵和非齐次项,然后建立增量方程,求得增量 Δ β \Delta \boldsymbol{\beta} Δβ。其具体理论过程可以参考前面的博客: (01)ORB-SLAM2源码无死角解析-(39) EPnP 算法原理详解→理论基础三:高斯牛顿迭代。其核心就是求得一阶雅克比矩阵:
J = ∂ f ( β ) β = [ ∂ f ( β ) ∂ β 1 ∂ f ( β ) ∂ β 2 ∂ f ( β ) ∂ β 3 ∂ f ( β ) ∂ β 4 ] = [ ∂ ( L β ) ∂ β 1 ∂ ( L β ) ∂ β 2 ∂ ( L β ) ∂ β 3 ∂ ( L β ) ∂ β 4 ] (15) \color{Green} \tag{15} \begin{aligned} \mathbf{J}=\frac{\partial f(\boldsymbol{\beta})}{\boldsymbol{\beta}} &=\left[\begin{array}{llll} \frac{\partial f(\boldsymbol{\beta})}{\partial \beta_{1}} & \frac{\partial f(\boldsymbol{\beta})}{\partial \beta_{2}} & \frac{\partial f(\boldsymbol{\beta})}{\partial \beta_{3}} & \frac{\partial f(\boldsymbol{\beta})}{\partial \beta_{4}} \end{array}\right] \\ &=\left[\begin{array}{llll} \frac{\partial(\mathbf{L} \boldsymbol{\beta})}{\partial \beta_{1}} & \frac{\partial(\mathbf{L} \boldsymbol{\beta})}{\partial \beta_{2}} & \frac{\partial(\mathbf{L} \beta)}{\partial \beta_{3}} & \frac{\partial(\mathbf{L} \boldsymbol{\beta})}{\partial \beta_{4}} \end{array}\right] \end{aligned} J=βf(β)=[β1f(β)β2f(β)β3f(β)β4f(β)]=[β1(Lβ)β2(Lβ)β3(Lβ)β4(Lβ)](15)
以及 Δ y = f ( β ) = L β − ρ (19) \color{Green} \tag{19} \Delta \mathbf{y}=f(\boldsymbol{\beta})=\mathbf{L} \boldsymbol{\beta}-\boldsymbol{\rho} Δy=f(β)=Lβρ(19)其上的 J \mathbf{J} J 对应源码中的 A A A, Δ y \Delta \mathbf{y} Δy 对应源码中的 B B B。这样能构建增量方程: J Δ β = Δ y \mathbf{J} \Delta \boldsymbol{\beta}= \Delta \mathbf{y} JΔβ=Δy,源码构建的方程为:
A Δ β = Δ B (30) \color{Green} \tag{30} \mathbf{A} \Delta \boldsymbol{\beta}= \Delta \mathbf{B} AΔβ=ΔB(30)

compute_A_and_b_gauss_newton 代码的注释如下:

/**
 * @brief 计算高斯牛顿法优化时,增量方程中的系数矩阵和非齐次项
 * @param[in]  l_6x10 L矩阵
 * @param[in]  rho    Rho矩向量
 * @param[in]  cb     当前次迭代得到的beta1~beta4
 * @param[out] A      计算得到的增量方程中的系数矩阵
 * @param[out] b      计算得到的增量方程中的非齐次项
 */
void PnPsolver::compute_A_and_b_gauss_newton(const double * l_6x10, const double * rho,
					double betas[4], CvMat * A, CvMat * b)
{
  // 以下推导就是求解一阶雅克比矩阵

  // /* 根据前面函数 gauss_newton 中的一些工作,可以发现这里的系数矩阵其实就是目标函数雅克比的转置. 原目标函数:
  //  * \f$ f(\mathbf{\beta})=\sum_{(i,j \  s.t. \  i<j)} \left( ||\mathbf{c}^c_i-\mathbf{c}^c_j ||^2 - ||\mathbf{c}^w_i-\mathbf{c}^w_j ||^2 \right)  \f$ 
  //  * 然后观察一下每一项的组成: \f$ ||\mathbf{c}^c_i-\mathbf{c}^c_j ||^2  \f$ 由论文中式12可以发现就对应着矩阵 L 中的一行,
  //  * 同样地对于 \f$ ||\mathbf{c}^w_i-\mathbf{c}^w_j ||^2  \f$ 则对应着式(13)中向量 \f$  \mathbf{\rho} \f$ 的每一行.所以目标函数完全可以写成矩阵的形式:
  //  * \f$ f(\mathbf{\beta})=\mathbf{L}\mathbf{\bar{\beta}}-\mathbf{\rho}  \f$
  //  * 注意这里使用的符号:
  //  * \f$ \mathbf{\bar{\beta}}= \begin{bmatrix} \beta_{11}\\\beta_{12}\\\beta_{22}\\\beta_{13}\\\beta_{23}\\\beta_{33}\\\beta_{14}\\\beta_{24}\\\beta_{34}\\\beta_{44} \end{bmatrix} \f$
  //  * 为了方便求导,计算得到一个中间结果先:
  //  * \f$ \begin{split}
  //  *  \mathbf{\bar{L}}&=\mathbf{L}\mathbf{\bar{\beta}}\\
  //  *  &=
  //  *  \begin{bmatrix}
  //  *  L_{11}\beta_{11}+L_{12}\beta_{12}+L_{13}\beta_{22}+\cdots+L_{1A}\beta_{44}\\
  //  *  L_{21}\beta_{11}+L_{22}\beta_{22}+L_{13}\beta_{22}+\cdots+L_{2A}\beta_{44}\\
  //  *  \cdots\\
  //  *  L_{61}\beta_{11}+L_{62}\beta_{22}+L_{63}\beta_{22}+\cdots+L_{6A}\beta_{44}\\
  //  *  \end{bmatrix}
  //  *  &=
  //  *  \begin{bmatrix}
  //  *  \mathbf{L_1}\\\mathbf{L_2}\\\cdots\\\mathbf{L_3}
  //  *  \end{bmatrix}
  //  *  \end{split} \f$
  //  *  然后原来的目标函数矩阵表示变成为了:
  //  *  \f$  f(\mathbf{\beta})=\mathbf{\bar{L}}-\mathbf{\rho} \f$
  //  *  接下来准备求目标函数的雅克比.注意到只有矩阵 \f$ \mathbf{\bar{L}} \f$ 和优化变量 \f$ \mathbf{\beta} \f$ 有关系,因此有:
  //  * \f$ \begin{split}
  //  * \frac{\partial f(\mathbf{\beta})}{\partial \mathbf{\beta}}&=\frac{\partial \mathbf{L}}{\partial \mathbf{\beta}}\\
  //  * &=
  //  * \begin{bmatrix}
  //  * \frac{\partial \mathbf{L}}{\partial \beta_1}&\frac{\partial \mathbf{L}}{\partial \beta_2}&
  //  * \frac{\partial \mathbf{L}}{\partial \beta_3}&\frac{\partial \mathbf{L}}{\partial \beta_4}
  //  * \end{bmatrix} \\
  //  * &=
  //  * \begin{bmatrix}
  //  * \frac{\partial \mathbf{L}_1}{\partial \beta_1}&\frac{\partial \mathbf{L}_1}{\partial \beta_2}&
  //  * \frac{\partial \mathbf{L}_1}{\partial \beta_3}&\frac{\partial \mathbf{L}_1}{\partial \beta_4}\\
  //  * \frac{\partial \mathbf{L}_2}{\partial \beta_1}&\frac{\partial \mathbf{L}_2}{\partial \beta_2}&
  //  * \frac{\partial \mathbf{L}_2}{\partial \beta_3}&\frac{\partial \mathbf{L}_2}{\partial \beta_4}\\
  //  * \cdots&\cdots&\cdots&\cdots\\
  //  * \frac{\partial \mathbf{L}_6}{\partial \beta_1}&\frac{\partial \mathbf{L}_6}{\partial \beta_2}&
  //  * \frac{\partial \mathbf{L}_6}{\partial \beta_3}&\frac{\partial \mathbf{L}_6}{\partial \beta_4}
  //  * \end{bmatrix}
  //  * \end{split} \f$
  //  * 从优化目标函数的概念触发,其中的每一行的约束均由一对点来提供,因此不同行之间其实并无关系,可以相互独立地计算,因此对于其中的每一行:(以第一行为例)
  //  * \f$ \mathbf{L}_1=
  //  * \beta_{11}L_{11}+\beta_{12}L_{12}+\beta_{22}L_{13}+\beta_{13}L_{14}+\beta_{23}L_{15}+
  //  * \beta_{33}L_{16}+\beta_{14}L_{17}+\beta_{24}L_{18}+\beta_{34}L_{19}+\beta_{44}L_{1A} \f$
  //  * 分别对beat进行求导:(注意为了方便这里把L的下标从1开始变成了从0开始)
  //  * \f$ \frac{\partial \mathbf{L}_1}{\partial \beta_1}=2\beta_1L_{10}+\beta_2L_{11}+\beta_3L_{13}+\beta_4L_{16} \\
  //  * \frac{\partial \mathbf{L}_1}{\partial \beta_2}=\beta_1L_{11}+2\beta_2L_{12}+\beta_3L_{14}+\beta_4L_{17} \\
  //  * \frac{\partial \mathbf{L}_1}{\partial \beta_3}=\beta_1L_{13}+\beta_2L_{14}+2\beta_3L_{15}+\beta_4L_{18} \\
  //  * \frac{\partial \mathbf{L}_1}{\partial \beta_4}=\beta_1L_{16}+\beta_2L_{17}+\beta_3L_{18}+2\beta_4L_{19}  \f$
  //  * 就是下面计算每一行的雅克比的式子.
  //  * 
  //  * 另外对于当前行的非齐次项, 在 gauss_newton 中简化后得到的结果为 -f(x), 也就是:
  //  * \f$ ||\mathbf{c}^w_i-\mathbf{c}^w_j ||^2 - ||\mathbf{c}^c_i-\mathbf{c}^c_j ||^2 \f$
  //  * 每一行都会有一个特定的i和j.上式中的前者可以直接由 \f$ \mathbf{\rho} \f$ 的对应行给定,而后者则要根据论文公式(12)给出了:
  //  * \f$ ||\mathbf{c}^c_i-\mathbf{c}^c_j ||^2 = \mathbf{L}_k\mathbf{\bar{\beta}} \f$ 
  //  * 这个也就是非齐次项部分的计算过程
  //  */



  // 一共有六个方程组, 对每一行(也就是每一个方程展开遍历);
  // 从优化目标函数的概念出发,其中的每一行的约束均由一对点来提供,因此不同行之间其实并无关系,可以相互独立地计算
  for(int i = 0; i < 6; i++) {
    // 获得矩阵L中的行指针
    const double * rowL = l_6x10 + i * 10;
    double * rowA = A->data.db + i * 4;

    // Step 1: 计算当前行的雅克比
    rowA[0] = 2 * rowL[0] * betas[0] +     rowL[1] * betas[1] +     rowL[3] * betas[2] +     rowL[6] * betas[3];
    rowA[1] =     rowL[1] * betas[0] + 2 * rowL[2] * betas[1] +     rowL[4] * betas[2] +     rowL[7] * betas[3];
    rowA[2] =     rowL[3] * betas[0] +     rowL[4] * betas[1] + 2 * rowL[5] * betas[2] +     rowL[8] * betas[3];
    rowA[3] =     rowL[6] * betas[0] +     rowL[7] * betas[1] +     rowL[8] * betas[2] + 2 * rowL[9] * betas[3];

    // Step 2: 计算当前行的非齐次项
    cvmSet(b, i, 0, rho[i] -
	   (                                    // 从0开始的下标 | 从1开始的下标
	    rowL[0] * betas[0] * betas[0] +     //b00 b11
	    rowL[1] * betas[0] * betas[1] +     //b01 b12
	    rowL[2] * betas[1] * betas[1] +     //b11 b22
	    rowL[3] * betas[0] * betas[2] +     //b02 b13
	    rowL[4] * betas[1] * betas[2] +     //b12 b23
	    rowL[5] * betas[2] * betas[2] +     //b22 b33
	    rowL[6] * betas[0] * betas[3] +     //b03 b14
	    rowL[7] * betas[1] * betas[3] +     //b13 b24
	    rowL[8] * betas[2] * betas[3] +     //b23 b34
	    rowL[9] * betas[3] * betas[3]       //b33 b44
	    ));
  }
}

 

六、结语

通过上面博客的介绍,最终在高斯牛顿(gauss_newton)函数中建立了增量方程 A Δ β = Δ B \mathbf{A} \Delta \boldsymbol{\beta}= \Delta \mathbf{B} AΔβ=ΔB,那么下一步就是求解增量 Δ B \Delta \mathbf{B} ΔB。源码中是通过 QR分解(豪斯霍尔德Householder变换) 实现的,对应于上面的函数 qr_solve(&A, &B, &X),在下一篇博客中会进行详细的讲解。

 
 
本文内容来自计算机视觉life ORB-SLAM2 课程课件