SLAM基础——滑动窗口中的三角测量

前言:简单的三角化

  理想情况下,两张图像中关联的同一个三维特征点   P \ P  P 满足下述方程:

{ s 2 x 2 = P s 1 R 21 x 1 + t 21 = P s 2 x 2 = s 1 R 1 x 1 + t 1 \left\{ \begin{aligned} s_2x_2 = P \\ s_1R_{21}x_1 + t_{21}=P\\ \end{aligned} \right.\\ s_2x_2 = s_1R_1x_1 + t_1\\ {s2x2=Ps1R21x1+t21=Ps2x2=s1R1x1+t1
其中   s 1 、 s 2 \ s_1、s_2  s1s2 为深度信息,   x 1 、 x 2 \ x_1、x_2  x1x2对应归一化坐标,同时   R 21 、 t 21 \ R_{21}、t_{21}  R21t21 十分精准,可以通过等式两边同时叉乘   x 2 \ x_2  x2直接解出   s 1 、 s 2 \ s_1、s_2  s1s2 :
s 2 x 2 × x 2 = 0 = s 1 x 2 × R 21 x 1 + x 2 × t 21 s_2x_2\times x_2 = 0 = s_1x_2\times R_{21}x_1 + x_2\times t_{21}\\ s2x2×x2=0=s1x2×R21x1+x2×t21
《SLAM十四讲》(第二版)p177中已经讲得较为详细。

最小二乘法求解

推广形式

  实际情况中, 上述公式中的   R 21 、 t 21 \ R_{21}、t_{21}  R21t21 并不精确,且存在多帧图像“tracking”到同一个特征点,基于上述“存在误差、多组数据”可以很自然地想到最小二乘法。
首先将公式拓展成一般形式:
l o s s i = s i x i × x i = δ i = s 1 x i × R i 1 x 1 + x i × t i 1 loss_i = s_ix_i\times x_i = \delta_i = s_1x_i\times R_{i1}x_1 + x_i\times t_{i1}\\ lossi=sixi×xi=δi=s1xi×Ri1x1+xi×ti1
为方便表示,令   X 1 = s 1 x 1 \ X_1=s_1x_1  X1=s1x1 X 1 X_1 X1表示在图像1坐标系下   P \ P  P点坐标:
l o s s i = x i × R i 1 X 1 + x 2 × t i 1 = δ i L o s s = 1 2 ∑ i = 2 n l o s s i 2 loss_i = x_i\times R_{i1}X_1 + x_2\times t_{i1} = \delta_i\\ Loss = \frac{1}{2}\sum_{i=2}^{n}lossi^2 lossi=xi×Ri1X1+x2×ti1=δiLoss=21i=2nlossi2
因为子函数   l o s s i \ loss_i  lossi 全部为线性,可以转换成求   A X 1 = 0 \ AX_1 = 0  AX1=0 最小二乘问题,采用SVD求解   A \ A  A 的零空间向量(近似的零空间向量,认为特征值最小的特征向量近似于零空间向量),求出的零空间向量则为   X 1 \ X_1  X1的具体数值。

进一步简化

  X 1 \ X_1  X1 扩展成齐次坐标后,(注意之后   X 1 \ X_1  X1 可能为齐次坐标也可能非齐次)公式如下:
l o s s i = x i × T i 1 X 1 loss_i = x_i\times T_{i1}X_1 \\ lossi=xi×Ti1X1
l o s s i = [ 0 − 1 v i 1 0 − u i − v i u i 0 ] T i 1 X 1 loss_i = \begin{bmatrix} 0 & -1 & v_i\\ 1 & 0 & -u_i\\-v_i & u_i &0 \end{bmatrix} T_{i1}X_1 \\ lossi=01vi10uiviui0Ti1X1
l o s s i = [ − T i 1 r o w 2 + v i T i 1 r o w 3 T i 1 r o w 1 − u i T i 1 r o w 3 − v i T i 1 r o w 1 + u i T i 1 r o w 2 ] X 1 loss_i =\begin{bmatrix} -T_{i1row2} +v_iT_{i1row3} \\ T_{i1row1} -u_iT_{i1row3}\\-v_i T_{i1row1}+u_iT_{i1row2}\end{bmatrix}X_1 lossi=Ti1row2+viTi1row3Ti1row1uiTi1row3viTi1row1+uiTi1row2X1
第三行可以由上两行线性变换所得,可以简化成:
l o s s i = [ − T i 1 r o w 2 + v i T i 1 r o w 3 T i 1 r o w 1 − u i T i 1 r o w 3 ] X 1 loss_i =\begin{bmatrix} -T_{i1row2} +v_iT_{i1row3} \\ T_{i1row1} -u_iT_{i1row3}\end{bmatrix}X_1 lossi=[Ti1row2+viTi1row3Ti1row1uiTi1row3]X1
整个 L o s s Loss Loss为:
L o s s i = [ − T 21 r o w 2 + v 2 T 21 r o w 3 T 21 r o w 1 − u 2 T 21 r o w 3 . . . . − T n 1 r o w 2 + v 2 T n 1 r o w 3 T n 1 r o w 1 − u 2 T n 2 r o w 3 ] X 1 Loss_i =\begin{bmatrix} -T_{21row2} +v_2T_{21row3} \\ T_{21row1} -u_2T_{21row3}\\ .... \\ -T_{n1row2} +v_2T_{n1row3} \\ T_{n1row1} -u_2T_{n2row3}\end{bmatrix}X_1 Lossi=T21row2+v2T21row3T21row1u2T21row3....Tn1row2+v2Tn1row3Tn1row1u2Tn2row3X1
利用线性代数性质,整齐一点的写法:(主要是针对写代码时候看得舒服)
L o s s i = [ u 2 T 21 r o w 3 − T 21 r o w 1 v 2 T 21 r o w 3 − T 21 r o w 2 . . . . u n T n 1 r o w 3 − T n 1 r o w 1 v n T n 1 r o w 3 − T n 1 r o w 2 ] X 1 Loss_i =\begin{bmatrix} u_2T_{21row3} -T_{21row1} \\ v_2T_{21row3}-T_{21row2}\\ .... \\ u_nT_{n1row3} -T_{n1row1} \\ v_nT_{n1row3}-T_{n1row2} \end{bmatrix}X_1 Lossi=u2T21row3T21row1v2T21row3T21row2....unTn1row3Tn1row1vnTn1row3Tn1row2X1

滑动窗口中的三角化——VINS为例

VINS中滑动窗口优化的逆深度为当前滑动窗口中第一次看到该特征点的图像下的逆深度。同时又加入相机外参,显得稍微复杂些。
{ T w b 0 T b c X 1 = P T w b i T b c X i = P \left\{ \begin{aligned} T_{wb_0}T_{bc}X_1 = P \\ T_{wb_i}T_{bc}X_i = P\\ \end{aligned} \right.\\ {Twb0TbcX1=PTwbiTbcXi=P
公式展开,并进行简单的等式变换后也可得如下的形式:
s i x i = s 1 R i ′ x 1 + t i ′ s_ix_i = s_1R_i^{'}x_1 + t_i^{'} sixi=s1Rix1+ti
只不过 R i ′ 、 t i ′ R_i^{'}、t_i^{'} Riti是通过数学变换,努力向之前已有的公式上“蹭”。
在这里插入图片描述Latex敲得头大,直接手写。

对应VINS中的代码:

void FeatureManager::triangulate(Vector3d Ps[], Vector3d tic[], Matrix3d ric[])
{
    for (auto &it_per_id : feature)
    {
        it_per_id.used_num = it_per_id.feature_per_frame.size();
        if (!(it_per_id.used_num >= 2 && it_per_id.start_frame < WINDOW_SIZE - 2))
            continue;

        if (it_per_id.estimated_depth > 0)
            continue;
        int imu_i = it_per_id.start_frame, imu_j = imu_i - 1;

        ROS_ASSERT(NUM_OF_CAM == 1);
        Eigen::MatrixXd svd_A(2 * it_per_id.feature_per_frame.size(), 4);
        int svd_idx = 0;

        Eigen::Matrix<double, 3, 4> P0;
        Eigen::Vector3d t0 = Ps[imu_i] + Rs[imu_i] * tic[0];
        Eigen::Matrix3d R0 = Rs[imu_i] * ric[0];
        P0.leftCols<3>() = Eigen::Matrix3d::Identity();
        P0.rightCols<1>() = Eigen::Vector3d::Zero();

        for (auto &it_per_frame : it_per_id.feature_per_frame)
        {
            imu_j++;

            Eigen::Vector3d t1 = Ps[imu_j] + Rs[imu_j] * tic[0];
            Eigen::Matrix3d R1 = Rs[imu_j] * ric[0];
            Eigen::Vector3d t = R0.transpose() * (t1 - t0);
            Eigen::Matrix3d R = R0.transpose() * R1;
            Eigen::Matrix<double, 3, 4> P;

			//对应公式中最后要求的R' t'
			
            P.leftCols<3>() = R.transpose();
            P.rightCols<1>() = -R.transpose() * t;
            Eigen::Vector3d f = it_per_frame.point.normalized();
            svd_A.row(svd_idx++) = f[0] * P.row(2) - f[2] * P.row(0);
            svd_A.row(svd_idx++) = f[1] * P.row(2) - f[2] * P.row(1);

            if (imu_i == imu_j)
                continue;
        }
        ROS_ASSERT(svd_idx == svd_A.rows());
        Eigen::Vector4d svd_V = Eigen::JacobiSVD<Eigen::MatrixXd>(svd_A, Eigen::ComputeThinV).matrixV().rightCols<1>();
        double svd_method = svd_V[2] / svd_V[3];
        //it_per_id->estimated_depth = -b / A;
        //it_per_id->estimated_depth = svd_V[2] / svd_V[3];

        it_per_id.estimated_depth = svd_method;
        //it_per_id->estimated_depth = INIT_DEPTH;

        if (it_per_id.estimated_depth < 0.1)
        {
            it_per_id.estimated_depth = INIT_DEPTH;
        }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值