SLAM--三角测量SVD分解法、最小二乘法及R t矩阵的判断

2023-11-16

一、三角测量

方法一:SVD分解法的推导

我们假设在相机坐标1和2存在这样的重投影关系:
[ u 1 v 1 1 ] = 1 s 1 K T 1 w P w \begin{bmatrix} u_1\\v_1\\1\end{bmatrix}=\frac 1 {s_1}KT_{1w}P_w u1v11=s11KT1wPw
[ u 2 v 2 1 ] = 1 s 2 K T 2 w P w \begin{bmatrix} u_2\\v_2\\1\end{bmatrix}=\frac 1 {s_2}KT_{2w}P_w u2v21=s21KT2wPw
如果只考虑相机位姿1和2的相对关系,则又可以写成:
{ [ u 1 v 1 1 ] = 1 s 1 K ⋅   [   I   ∣   0   ]   ⋅ P w ,   P 1 = P w = [ X Y Z 1 ]   [ u 2 v 2 1 ] = 1 s 2 K ⋅   [   R 21   ∣   t   ]   ⋅ P 1 (2) \left \{ \begin{aligned} \begin{bmatrix} u_1\\v_1\\1\end{bmatrix}&=\frac 1 {s_1}K\cdot\space[\space I\space|\space 0 \space]\space \cdot P_w\quad,\space P_1 = P_w =\begin{bmatrix} X\\Y\\Z\\1\end{bmatrix} \\~\\ \begin{bmatrix} u_2\\v_2\\1\end{bmatrix} &=\frac 1 {s_2}K\cdot\space[\space R_{21}\space|\space t \space]\space \cdot P_1 \end{aligned} \right.\tag{2} u1v11 u2v21=s11K [ I  0 ] Pw, P1=Pw=XYZ1=s21K [ R21  t ] P1(2)
这里,一般我们是知道相机内参 K K K的,所以为了忽略相机内参,我们令映射矩阵(3X4):
p r 1 = K ⋅   [   I   ∣   0   ]   p r 2 = K ⋅   [   R 21   ∣   t   ] pr_1 = K\cdot\space[\space I\space|\space 0 \space]\\~\\ pr_2 = K\cdot\space[\space R_{21}\space|\space t \space] pr1=K [ I  0 ] pr2=K [ R21  t ]
写成行向量的形式
p r 1 = [ p r 1 , 1 p r 1 , 2 p r 1 , 3 ] , p r 2 = [ p r 2 , 1 p r 2 , 2 p r 2 , 3 ] pr_1 = \begin{bmatrix} pr_{1,1}\\pr_{1,2}\\pr_{1,3}\end{bmatrix}, pr_2 = \begin{bmatrix} pr_{2,1}\\pr_{2,2}\\pr_{2,3}\end{bmatrix} pr1=pr1,1pr1,2pr1,3,pr2=pr2,1pr2,2pr2,3
投影映射方程变为:
[ s 1 u 1 s 1 v 1 s 1 ] = [ p r 1 , 1 p r 1 , 2 p r 1 , 3 ] P 1   [ s 2 u 2 s 2 v 2 s 2 ] = [ p r 2 , 1 p r 2 , 2 p r 2 , 3 ] P 1 \begin{bmatrix} s_1u_1\\s_1v_1\\s_1\end{bmatrix}=\begin{bmatrix} pr_{1,1}\\pr_{1,2}\\pr_{1,3}\end{bmatrix}P_1\\~\\ \begin{bmatrix} s_2u_2\\s_2v_2\\s_2\end{bmatrix}=\begin{bmatrix} pr_{2,1}\\pr_{2,2}\\pr_{2,3}\end{bmatrix}P_1 s1u1s1v1s1=pr1,1pr1,2pr1,3P1 s2u2s2v2s2=pr2,1pr2,2pr2,3P1

我们观察两个方程,可以发现能用第三行消去深度参数,所以有:
[ p r 1 , 3 ⋅ P 1 ⋅ u 1 p r 1 , 3 ⋅ P 1 ⋅ v 1 ] = [ p r 1 , 1 ⋅ P 1 p r 1 , 2 ⋅ P 1 ]   [ p r 2 , 3 ⋅ P 1 ⋅ u 2 p r 2 , 3 ⋅ P 1 ⋅ v 2 ] = [ p r 2 , 1 ⋅ P 1 p r 2 , 2 ⋅ P 1 ]   \begin{bmatrix} pr_{1,3}\cdot P_1\cdot u_1\\pr_{1,3}\cdot P_1\cdot v_1\end{bmatrix}=\begin{bmatrix} pr_{1,1}\cdot P_1\\pr_{1,2}\cdot P_1\end{bmatrix}\\~\\ \begin{bmatrix} pr_{2,3}\cdot P_1\cdot u_2\\pr_{2,3}\cdot P_1\cdot v_2\end{bmatrix}=\begin{bmatrix} pr_{2,1}\cdot P_1\\pr_{2,2}\cdot P_1\end{bmatrix}\\~\\ [pr1,3P1u1pr1,3P1v1]=[pr1,1P1pr1,2P1] [pr2,3P1u2pr2,3P1v2]=[pr2,1P1pr2,2P1] 
我们把要求的P1提出来,就可以得到线性方程:
[ p r 1 , 3 ⋅ u 1 − p r 1 , 1 p r 1 , 3 ⋅ v 1 − p r 1 , 2 ] P 1 = 0   [ p r 2 , 3 ⋅ u 2 − p r 2 , 1 p r 2 , 3 ⋅ v 2 − p r 2 , 2 ] P 1 = 0   \begin{bmatrix} pr_{1,3}\cdot u_1-pr_{1,1}\\pr_{1,3}\cdot v_1-pr_{1,2}\end{bmatrix}P_1=0\\~\\ \begin{bmatrix} pr_{2,3}\cdot u_2-pr_{2,1}\\pr_{2,3}\cdot v_2-pr_{2,2}\end{bmatrix}P_1=0\\~\\ [pr1,3u1pr1,1pr1,3v1pr1,2]P1=0 [pr2,3u2pr2,1pr2,3v2pr2,2]P1=0 
即:
[ p r 1 , 3 ⋅ u 1 − p r 1 , 1 p r 1 , 3 ⋅ v 1 − p r 1 , 2 p r 2 , 3 ⋅ u 2 − p r 2 , 1 p r 2 , 3 ⋅ v 2 − p r 2 , 2 ] P 1 = 0 \begin{bmatrix} pr_{1,3}\cdot u_1-pr_{1,1}\\pr_{1,3}\cdot v_1-pr_{1,2}\\pr_{2,3}\cdot u_2-pr_{2,1}\\pr_{2,3}\cdot v_2-pr_{2,2}\end{bmatrix} P_1=0 pr1,3u1pr1,1pr1,3v1pr1,2pr2,3u2pr2,1pr2,3v2pr2,2P1=0
我们利用SVD分解的方法来解这个方程,求出P1,但我们发现,这其实是一个超定方程,所以利用SVD分解来得到一个最小二乘解,(可以回顾下矩阵论的知识,超定方程怎么求最小二乘解);

我们令:
A = [ p r 1 , 3 ⋅ u 1 − p r 1 , 1 p r 1 , 3 ⋅ v 1 − p r 1 , 2 p r 2 , 3 ⋅ u 2 − p r 2 , 1 p r 2 , 3 ⋅ v 2 − p r 2 , 2 ] A = \begin{bmatrix} pr_{1,3}\cdot u_1-pr_{1,1}\\pr_{1,3}\cdot v_1-pr_{1,2}\\pr_{2,3}\cdot u_2-pr_{2,1}\\pr_{2,3}\cdot v_2-pr_{2,2}\end{bmatrix} A=pr1,3u1pr1,1pr1,3v1pr1,2pr2,3u2pr2,1pr2,3v2pr2,2
对A进行奇异值分解:
A 4 × 4 = U W V T A_{4\times4} = UWV^T A4×4=UWVT

A = U ⋅ [ σ 1 σ 2 σ 3 σ 4 ] [ V 1 V 2 V 3 V 4 ] T , σ 1 ≥ σ 2 ≥ σ 3 ≥ σ 4 ≥ 0 A= U\cdot \begin{bmatrix} \sigma_1 \\&\sigma_2\\& &\sigma_3\\ &&&\sigma_4\end{bmatrix}[V1\quad V2\quad V3 \quad V4] ^T,\sigma_1 \geq \sigma_2 \geq \sigma_3 \geq \sigma_4 \geq 0 A=Uσ1σ2σ3σ4[V1V2V3V4]Tσ1σ2σ3σ40
根据 A x = 0 Ax=0 Ax=0最小二乘法求解方法,其最小二乘解即为 A T A A^TA ATA最小特征值的特征向量。
参考:
证明AX=0的最小二乘解是ATA最小特征值对应的特征向量

所以我们取SVD分解得到的V矩阵最后一列作为 P 1 P_1 P1的解,但我们还需要归一化以后才能使用。
 
 

方法二:最小二乘法求解

我们知道的投影关系:(P1和P2分别是在相机1和相机2坐标系下的点)
[ u 1 v 1 1 ] = 1 s 1 K P 1 \begin{bmatrix} u_1\\v_1\\1\end{bmatrix}=\frac 1 {s_1}KP_1 u1v11=s11KP1
[ u 2 v 2 1 ] = 1 s 2 K P 2 \begin{bmatrix} u_2\\v_2\\1\end{bmatrix}=\frac 1 {s_2}KP_2 u2v21=s21KP2
所以可以推出:
K − 1 [ u 1 v 1 1 ] = 1 s 1 P 1 = e 1   K − 1 [ u 2 v 2 1 ] = 1 s 2 P 2 = e 2 K^{-1}\begin{bmatrix} u_1\\v_1\\1\end{bmatrix}=\frac 1 {s_1}P_1 = e_1\\~\\ K^{-1} \begin{bmatrix} u_2\\v_2\\1\end{bmatrix}=\frac 1 {s_2}P_2=e_2 K1u1v11=s11P1=e1 K1u2v21=s21P2=e2
其中相机坐标系下坐标 P 1 P_1 P1 P 2 P_2 P2存在关系:
P 2 = R 21 ⋅ P 1 + t 21 P_2 = R_{21}\cdot P_1+t_{21} P2=R21P1+t21
所以联合上面的式子我们可以得到:
K − 1 [ u 2 v 2 1 ] = 1 s 2 ( s 1 ⋅ R 21 ⋅ K − 1 [ u 1 v 1 1 ] + t 21 ) K^{-1} \begin{bmatrix} u_2\\v_2\\1\end{bmatrix}=\frac 1 {s_2}(s_1\cdot R_{21}\cdot K^{-1}\begin{bmatrix} u_1\\v_1\\1\end{bmatrix}+t_{21} ) K1u2v21=s21(s1R21K1u1v11+t21)
简单表示,即:
e 2 = 1 s 2 ( s 1 ⋅ R 21 ⋅ e 1 + t 21 )   ⟹ s 2 ⋅ e 2 = ( s 1 ⋅ R 21 ⋅ e 1 + t 21 )   ⟹ [ − R 21 ⋅ e 1 e 2 ] [ s 1 s 2 ] = t 21 e_2=\frac 1 {s_2}(s_1\cdot R_{21}\cdot e_1+t_{21} )\\~\\ \Longrightarrow s_2\cdot e_2=(s_1\cdot R_{21}\cdot e_1+t_{21} )\\~\\ \Longrightarrow \begin{bmatrix} -R_{21}\cdot e_1&e_2 \end{bmatrix} \begin{bmatrix} s_1 \\ s_2\end{bmatrix} = t_{21} e2=s21(s1R21e1+t21) s2e2=(s1R21e1+t21) [R21e1e2][s1s2]=t21
这样我们就得到了线性方程的形式: A x = b Ax = b Ax=b
这里:
A = [ − R 21 ⋅ e 1 e 2 ] , x = [ s 1 s 2 ] A=\begin{bmatrix} -R_{21}\cdot e_1&e_2 \end{bmatrix} ,x=\begin{bmatrix} s_1 \\ s_2\end{bmatrix} A=[R21e1e2]x=[s1s2]
我们根据矩阵论的知识可以知道,一个无解方程组存在唯一的最小二乘解,一般我们会对A矩阵进行BC满秩分解:
若 r a n k ( A ) = r , A m × n = B m × r C r × n   若 r = m ( 行 满 秩 ) , A = E A   若 r = n ( 列 满 秩 ) , A = A E 若rank(A) = r,A_{m\times n} = B_{m\times r}C_{r\times n}\\~\\ 若r = m(行满秩),A = EA\\~\\ 若r = n (列满秩),A=AE rank(A)=rAm×n=Bm×rCr×n r=mA=EA r=n()A=AE
则A的广义逆矩阵为:
A + = C T ( C C T ) − 1 ( B T B ) − 1 B T   A^{+} = C^T(CC^T)^{-1}(B^TB)^{-1}B^T\\~\\ A+=CT(CCT)1(BTB)1BT 
特殊情况:
行 满 秩 : A + = A T ( A A T ) − 1   列 满 秩 : A + = ( A T A ) − 1 A T 行满秩:A^+ = A^T(AA^T)^{-1}\\~\\列满秩:A^+=(A^TA)^{-1}A^T A+=AT(AAT)1 A+=(ATA)1AT

我们的最小二乘解就是: x = A + b x = A^+b x=A+b(不进行推导了,可自行复习矩阵论的知识)

在这里我们的A是列满秩(3X2的矩阵),对于无解方程组,其最小二乘解:
[ s 1 s 2 ] = ( A T A ) − 1 A T ⋅ t 21 \begin{bmatrix} s_1 \\ s_2\end{bmatrix}= (A^TA)^{-1}A^T\cdot t_{21} [s1s2]=(ATA)1ATt21
s 1 s_1 s1 s 2 s_2 s2分别是在两个相机坐标系下的深度;
 
 

二、ORB_SLAM2 三角测量源码:

void Initializer::Triangulate(const cv::KeyPoint &kp1, const cv::KeyPoint &kp2, const cv::Mat &P1, const cv::Mat &P2, cv::Mat &x3D)
{
    cv::Mat A(4,4,CV_32F);

    A.row(0) = kp1.pt.x*P1.row(2)-P1.row(0);
    A.row(1) = kp1.pt.y*P1.row(2)-P1.row(1);
    A.row(2) = kp2.pt.x*P2.row(2)-P2.row(0);
    A.row(3) = kp2.pt.y*P2.row(2)-P2.row(1);

    cv::Mat u,w,vt;
    cv::SVD::compute(A,w,u,vt,cv::SVD::MODIFY_A| cv::SVD::FULL_UV);
    x3D = vt.row(3).t();//取SVD分解得到的V矩阵最后一列作为$P_1$的解
    x3D = x3D.rowRange(0,3)/x3D.at<float>(3);
}

 
 

三、利用Eigen源码实现三角测量:

方法一:SVD分解法

为了更好的理解过程,利用Eigen实现了三角测量:

Eigen::Vector3d triangulatedByEigenSVD(Point2f pixel_1,Point2f pixel_2,Mat R,Mat t,Mat &K)
{
    Eigen::Matrix3d K_eigen;
    cv::cv2eigen(K,K_eigen);//eigen 类型的K内参 需要包含 #include <opencv2/core/eigen.hpp>

    Eigen::Matrix<double,3,4> T_1,T_21;
    T_1<<   1, 0, 0, 0,
            0, 1, 0, 0,
            0, 0, 1, 0;

    T_21<<  R.at<double>(0,0), R.at<double>(0,1), R.at<double>(0,2), t.at<double>(0,0),
            R.at<double>(1,0), R.at<double>(1,1), R.at<double>(1,2), t.at<double>(1,0),
            R.at<double>(2,0), R.at<double>(2,1), R.at<double>(2,2), t.at<double>(2,0);

    Eigen::Matrix<double,3,4> ProjectMatrix_1,ProjectMatrix_2;

    ProjectMatrix_1 = K_eigen * T_1;
    ProjectMatrix_2 = K_eigen * T_21;

    Eigen::Matrix4d A;
    A.row(0) = ProjectMatrix_1.row(2)*pixel_1.x - ProjectMatrix_1.row(0);
    A.row(1) = ProjectMatrix_1.row(2)*pixel_1.y - ProjectMatrix_1.row(1);
    A.row(2) = ProjectMatrix_2.row(2)*pixel_2.x - ProjectMatrix_2.row(0);
    A.row(3) = ProjectMatrix_2.row(2)*pixel_2.y - ProjectMatrix_2.row(1);

    Eigen::JacobiSVD<Eigen::MatrixXd> svd(A, Eigen::ComputeThinU | Eigen::ComputeThinV);
    Eigen::Matrix4d U = svd.matrixU();
    Eigen::Matrix4d V = svd.matrixV();
    Eigen::Vector4d S = svd.singularValues();

    Eigen::Vector4d p_w = V.col(3);
    p_w /= p_w(3,0);

    return Eigen::Vector3d(p_w(0),p_w(1),p_w(2));
}

方法二:最小二乘法求解(速度最快)

Eigen::Vector3d triangulatedByEigenLeastSquare(Point2f pixel_1, Point2f pixel_2, Mat R, Mat t, Mat &K)
{
    Eigen::Vector3d point_1,point_2;
    point_1<<pixel_1.x,pixel_1.y,1;//齐次坐标
    point_2<<pixel_2.x,pixel_2.y,1;

    Eigen::Matrix3d K_eigen,R_eigen;
    Eigen::Vector3d t_eigen;
    cv::cv2eigen(K,K_eigen);//eigen 类型的K内参
    cv::cv2eigen(R,R_eigen);//eigen 类型的R
    cv::cv2eigen(t,t_eigen);//eigen 类型的t

    Eigen::Matrix<double,3,2> A;
    A.block(0,0,3,1) = -R_eigen*K_eigen.inverse()*point_1;
    A.block(0,1,3,1) = K_eigen.inverse()*point_2;

    //行满秩 最小二乘解:x = A^T * (A*A^T)^-1 b
    //列满秩 最小二乘解:x = (A^T*A)^-1 * A^T b
    Eigen::Vector2d d =(A.transpose()*A).inverse()*A.transpose()*t_eigen;//d[0],d[1]就是相机坐标系1 和 2下特征点深度

    Eigen::Vector3d p1 = d[0]*K_eigen.inverse()*point_1;
    //Eigen::Vector3d p2 = d[1]*K_eigen.inverse()*point_2;//p_2也能求出
    return p1;
}

方法三:利用OpenCV自带函数

参考源码:视觉SLAM十四讲–高翔

//像素坐标系到相机坐标系
Point3d pixel2camera( const Mat &K,const Point2d &p,const double depth = 1.0 )
{
  return Point3d
    (
      depth*(p.x - K.at<double>(0, 2)) / K.at<double>(0, 0),
      depth*(p.y - K.at<double>(1, 2)) / K.at<double>(1, 1),
              depth
    );
}

void triangulation(vector<Point2f> pixel_1,vector<Point2f> pixel_2,Mat R,Mat t,vector< Point3d >& points)
{
    Mat projMatr1 = (Mat_<float> (3,4) <<
            1,0,0,0,
            0,1,0,0,
            0,0,1,0);
    Mat projMatr2 = (Mat_<float> (3,4) <<
            R.at<double>(0,0), R.at<double>(0,1), R.at<double>(0,2), t.at<double>(0,0),
            R.at<double>(1,0), R.at<double>(1,1), R.at<double>(1,2), t.at<double>(1,0),
            R.at<double>(2,0), R.at<double>(2,1), R.at<double>(2,2), t.at<double>(2,0)
        );

    vector<Point2f> projPoints1,projPoints2;
    for(size_t i =0;i<pixel_1.size();i++)
    {
        Point3d camera_1 = pixel2camera(K,pixel_1[i],1.0);
        Point3d camera_2 = pixel2camera(K,pixel_2[i],1.0);
        projPoints1.push_back(Point2f(camera_1.x,camera_1.y));
        projPoints2.push_back(Point2f(camera_2.x,camera_2.y));
    }

    Mat points4D;
    cv::triangulatePoints( projMatr1, projMatr2, projPoints1, projPoints2, points4D );

    // 转换成非齐次坐标
    for ( int i=0; i<points4D.cols; i++ )
    {
        Mat x = points4D.col(i);
        x /= x.at<float>(3,0); // 归一化
        Point3d p (
            x.at<float>(0,0),
            x.at<float>(1,0),
            x.at<float>(2,0)
        );
        points.push_back( p );
    }
}

四、对求解的R t筛选的方法:

我们利用求解的两个相机坐标系下坐标点深度的正负的比例来判断R t 是否是最佳的(pixel_1是匹配特征点在相机1的像素坐标,pixel_2是在相机2中的):

bool checkRt(Eigen::Matrix3d R_eigen, Eigen::Vector3d t_eigen, vector<Point2f> pixel_1, vector<Point2f> pixel_2)
{
    Mat R,t;
    cv::eigen2cv(R_eigen,R);
    cv::eigen2cv(t_eigen,t);
    vector<Eigen::Vector3d> P_1,P_2;
    for(auto i=0;i<pixel_1.size();i++)
    {
        P_1.push_back(triangulatedByEigenSVD(pixel_1[i],pixel_2[i],R,t,K));
        //P2 = RP1 + t
        P_2.push_back(R_eigen * P_1[i] + t_eigen);
    }

    int good_num_p1 = 0,good_num_p2 = 0;
    for(auto ptr_1:P_1)
    {
        if (ptr_1(2,0) > 0)
        {
            good_num_p1++;
        }
    }

    for(auto ptr_2:P_2)
    {
        if (ptr_2(2,0) > 0)
        {
            good_num_p2++;
        }
    }

    //cout<<good_num_p1<<" "<<good_num_p2;

    //设定阈值
    double posibility = (good_num_p1/(double)P_1.size())*(good_num_p2/(double)P_2.size());
    if(posibility > 0.7)
        return true;
    else
        return false;
}

使用演示:
首先可以利用本质矩阵opencv 解出的essential_matrix,进行SVD分解求出四组 R , t:

    Eigen::Matrix3d A;
    cv::cv2eigen(essential_matrix,A);
    Eigen::JacobiSVD<Eigen::MatrixXd> svd(A, Eigen::ComputeThinU | Eigen::ComputeThinV);
    auto U = svd.matrixU();
    auto V = svd.matrixV();
    auto S = svd.singularValues();
    cout<<"A = \n"<<A<<endl;
    cout<<"S = \n"<<S<<endl;
    cout<<"U = \n"<<U<<endl;
    cout<<"VT = \n"<<V.transpose()<<endl;
    auto A_souce = U*S.asDiagonal()*V.transpose();
    cout<<"A constructed by U*S*VT is \n"<<A_souce<<endl;
    Eigen::Matrix3d Z,W;
    Z<<0,1,0,
       -1,0,0,
       0,0,0;
    W<<0,-1,0,
       1,0,0,
       0,0,1;
    //四种情况,需要利用深度信息(正负)来判断和筛选。
    Eigen::Matrix3d t_eigen_hat_1 = U*Z*U.transpose();              // 也可利用 U.col(2).transpose()
    Eigen::Matrix3d t_eigen_hat_2 = U*Z.transpose()*U.transpose();  // 也可利用 -U.col(2).transpose()
    Eigen::Matrix3d R_eigen_1 = U*W*V.transpose();
    Eigen::Matrix3d R_eigen_2 = U*W.transpose()*V.transpose();

    //----------转换为3X1的向量------
    Eigen::Vector3d t_eigen_1,t_eigen_2;
        t_eigen_1<<-t_eigen_hat_1(1,2),t_eigen_hat_1(0,2),-t_eigen_hat_1(0,1);
        t_eigen_2<<-t_eigen_hat_2(1,2),t_eigen_hat_2(0,2),-t_eigen_hat_2(0,1);

再利用checkRt函数进行判断筛选:

    bool index_1 = checkRt(R_eigen_1,t_eigen_1,pixel_1,pixel_2);
    bool index_2 = checkRt(R_eigen_1,t_eigen_2,pixel_1,pixel_2);
    bool index_3 = checkRt(R_eigen_2,t_eigen_1,pixel_1,pixel_2);
    bool index_4 = checkRt(R_eigen_2,t_eigen_2,pixel_1,pixel_2);
    cout<<"The R1 t1 is score:"<<index_1<<endl;
    cout<<"The R1 t2 is score:"<<index_2<<endl;
    cout<<"The R2 t1 is score:"<<index_3<<endl;
    cout<<"The R2 t2 is score:"<<index_4<<endl;

    cout<<"The best Rotation and translation is :\n";
    if(index_1 == 1)
    {
        cout<<"R_eigen_1:\n"<<R_eigen_1<<endl;
        cout<<"t_eigen_1:\n"<<t_eigen_1.transpose()<<endl;
    }
    else if(index_2 == 1)
    {
        cout<<"R_eigen_1:\n"<<R_eigen_1<<endl;
        cout<<"t_eigen_2:\n"<<t_eigen_2.transpose()<<endl;
    }
    else if(index_3 == 1)
    {
        cout<<"R_eigen_2:\n"<<R_eigen_2<<endl;
        cout<<"t_eigen_1:\n"<<t_eigen_1.transpose()<<endl;
    }
    else if(index_4 == 1)
    {
        cout<<"R_eigen_2:\n"<<R_eigen_2<<endl;
        cout<<"t_eigen_2:\n"<<t_eigen_2.transpose()<<endl;
    }

运行结果:

The R1 t1 is score:1
The R1 t2 is score:0
The R2 t1 is score:0
The R2 t2 is score:0
The best Rotation and translation is :
R_eigen_1:
  0.996291 -0.0532112  0.0676278
 0.0503369   0.997784  0.0435187
-0.0697936 -0.0399531   0.996761
t_eigen_1:
  -0.9663 -0.182217   0.18183
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

SLAM--三角测量SVD分解法、最小二乘法及R t矩阵的判断 的相关文章

  • Java单元测试用例的编写

    作者 阿里技术 链接 https www zhihu com question 449470796 answer 1781246366 来源 知乎 著作权归作者所有 商业转载请联系作者获得授权 非商业转载请注明出处 编写Java单元测试用例
  • javascript if else优化指南

    不管是平时在学习js中还是在项目书中写js代码 都避免不了一个问题就是有时候要做大量的分支判断 很多人的第一反应就是使用if else 无可厚非 if else早平时做分支判断的时候是非常好用的 但是代码中嵌套的if else结构往往导致代

随机推荐

  • python函数与模块实验报告_python学习笔记及作业(函数,内置模块,模块与包)...

    1 作业 爬取内容牛超的poping 视频并存入本地 importrequests res requests get http f us sinaimg cn 001lksTilx07uuNOl74Q01041200dBV50E010 mp
  • python作业代码敲写

    1 判断以下哪些不能作为标识符 B D A a B a C 12 D a 12 E false F False 2 输入数 判断这个数是否是质数 要求使用函数 for循环 3 求50 150之间的质数是那些 4 打印输出标准水仙花数 输出这
  • 小白看React Native

    欢迎大家前往云 社区 获取更多腾讯海量技术实践干货哦 作者 MelonTeam 1 What is React Native 众所周知 产品的需求总是想快速的迭代 但是由于应用分发市场的审核机制 主要是iOS审核 使一些快速迭代的需求只能选
  • 最火视频直播应用Meerkat: 简单到令人发指 却成功了

    最火视频直播应用Meerkat 简单到令人发指 却成功了 分析师 王鑫 2015 03 24 分享 1 作为一款手机视频直播应用 Meerkat的产品设计足够简单 这种简单不仅体现在操作交互层面 还蕴含于产品的核心逻辑中 类似阅后即焚的直播
  • Markdown基础语法

    Markdown基础语法 一 Markdown简介 Markdown 是一种轻量级标记语言 它允许人们使用易读易写的纯文本格式编写文档 Markdown 语言在 2004 由约翰 格鲁伯 英语 John Gruber 创建 Markdown
  • MATLAB中conv2的详细用法

    转自 https blog csdn net jinv5 article details 52874880 conv2函数 1 用法 C conv2 A B shape 卷积滤波 复制代码 A 输入图像 B 卷积核 假设输入图像A大小为ma
  • 安装 VMware 出现 failed to install the hcmon driver

    安装 VMware 出现 failed to install the hcmon driver 1 先删除所有带vmware注册表 删除后重启电脑 在装一遍 无还是无效 2 在c盘搜索hcmon sys文件 有就删除 删除之后重启电脑 再重
  • 响应式人力资源招聘企业网站源码

    介绍 响应式人力资源招聘企业网站源码 网盘下载地址 http kekewangLuo cc 6lqETgRAZ6a0 图片
  • mysql 表分区 插入数据,分区表导入数据库

    如果是10g及以上版本 可以使用参数REMAP TABLESPACE 来映射表空间 1 在ascii数据库中建立3个tablespaces tbs1 tbs2 tbs3 SQL gt create tablespace tbs1 dataf
  • 百分位数

    来源
  • dedecmscan漏洞扫描

    介绍 推荐一款 大佬编写 实用工具 只做推荐 请勿违法 如有侵权 请联系我删除 dedescan是一款可以扫描所有已公开的dedecms漏洞的扫描器 github地址 https github com lengjibo dedecmscan
  • C++中智能指针的设计和使用

    转载请标明出处 原文地址 http blog csdn net hackbuteer1 article details 7561235 智能指针 smart pointer 是存储指向动态分配 堆 对象指针的类 用于生存期控制 能够确保自动
  • libtorch 1.12.1 cuda11.3 torch1.12.1 visual stdio2019环境搭建

    conda 的环境 name torch1 12 1 channels https mirrors tuna tsinghua edu cn anaconda cloud pytorch https mirrors tuna tsinghu
  • 如何关闭rabbitmq

    rabbitmqctl stop 方式2 先用ps ef grep rabbitmq 查询出进程号 然后用kill 9 进程号 杀死进程 RabbitMQ常用命令 说明 命令 启用Web控制台 rabbitmq plugins enable
  • 路由器ipv6怎么设置才能上网_设置路由器时,如何正确选择上网方式?

    设置路由器时 常见有自动获得IP地址 宽带拨号上网 固定IP地址三种上网方式 选择任意一个 均可进入下一步 但上网方式选择错误 即使设置步骤完成 也不能上网 那么设置路由器时 如何正确选择上网方式呢 取决于当前宽带线路的上网方式 本文以Wi
  • NoSQL -- 1.NoSQL与TRDB的区别

    TRDB TRDB Traditional Relational Database 即 传统关系型数据库 关系型数据库 是指采用了关系模型来组织数据的数据库 其以行和列的形式存储数据 以便于用户理解 关系型数据库这一系列的行和列被称为表 一
  • 将一个对象的属性值赋值给另一个对象

    java 对象属性复制 将一个对象的属性值赋值给另一个对象 属性名需要相同 import org springframework beans BeanUtils BeanUtils copyProperties 源对象 目标对象
  • 一位老学长的真实互联网校招求职心路历程~

    自我介绍 听说很多家公司2019年的春招已经陆续开始了 作为一个备战过2018年春招和秋招的求职狗 想来聊一下自己的校招求职经历 我本科是哈尔滨的一所211大学 万年老二 学的是电子信息工程 由于当年高考发挥失常 自己又不想复读 所以从入学
  • Java+GeoTools(开源的Java GIS工具包)快速入门-实现读取shp文件并显示

    场景 GeoTools GeoTools 是一个开源的 Java GIS 工具包 可利用它来开发符合标准的地理信息系统 GeoTools 提供了 OGC Open Geospatial Consortium 规范的一个实现来作为他们的开发
  • SLAM--三角测量SVD分解法、最小二乘法及R t矩阵的判断

    目录 一 三角测量 方法一 SVD分解法的推导 方法二 最小二乘法求解 二 ORB SLAM2 三角测量源码 三 利用Eigen源码实现三角测量 方法一 SVD分解法 方法二 最小二乘法求解 速度最快 方法三 利用OpenCV自带函数 四