选择正确的基本矩阵

时间:2017-07-04 13:15:13

标签: matlab opencv computer-vision

我想使用Matlab编写自己的sfm管道代码,因为我需要一些opencv函数不能提供的输出。但是,我使用opencv进行比较。

Opencv函数[E,mask] = cv.findEssentialMat(points1, points2, 'CameraMatrix',K, 'Method','Ransac');使用Nister的五点算法和RANSAC提供基本矩阵解决方案。

使用以下内容找到inlier指数:InliersIndices=find(mask>0);

我使用了Nister算法的Matlab实现:

Fivepoint_algoithm_code

对该功能的调用如下:

[E_all, R_all, t_all, Eo_all] = five_point_algorithm( pts1, pts2, K, K);

该算法最多可输出10个基本矩阵解。但是,我遇到了以下问题:

  1. 上述启示仅用于完美对应(没有Ransac),并且我使用InliersIndices向算法5提供对应关系,输出的基本矩阵(最多10个)都不同于由Opencv返回。
  2. 所有返回的基本矩阵应该是解决方案,那么为什么当我使用以下函数对每个矩阵进行三角测量时,我不能获得相同的3D点?
  3. 如何选择合适的基本marix解决方案?
  4. 我使用matlab工具箱的功能进行三角测量

    投影矩阵:

    P1=K*[eye(3) [0;0;0]];
    P2=K*[R_all{i} t_all{i}];
    
    [pts3D,rep_error] = triangulate(pts1', pts2', P1',P2');
    

    修改

    [E,mask] = cv.findEssentialMat(points1, points2, 'CameraMatrix',K, 'Method','Ransac');

    返回的E.
    E =
    
        0.0052   -0.7068    0.0104
        0.7063    0.0050   -0.0305
       -0.0113    0.0168    0.0002
    

    对于5点Matlab实现,从内点得到5个随机索引:

    pts1 =
    
      736.7744  740.2372  179.2428  610.5297  706.8776
      112.2673  109.9687   45.7010   91.4371   87.8194
    
    pts2 =
    
      722.3037  725.3770  150.3997  595.3550  692.5383
      111.7898  108.6624   43.6847   90.6638   86.8139
    
    K =
    
      723.3631    7.9120  601.7643
       -3.8553  719.6517  182.0588
        0.0075    0.0044    1.0000
    

    返回4个解决方案:

    E1 =
    
       -0.2205    0.9436   -0.1835
        0.8612    0.2447   -0.1531
        0.4442   -0.0600   -0.0378
    
     E2 =
    
       -0.2153    0.9573    0.1626
        0.8948    0.2456   -0.3474
        0.1003    0.1348   -0.0306
    E3 =
    
        0.0010   -0.9802   -0.0957
        0.9768    0.0026   -0.1912
        0.0960    0.1736   -0.0019
    E4 =
    
       -0.0005   -0.9788   -0.1427
        0.9756    0.0021   -0.1658
        0.1436    0.1470   -0.0030
    

    EDIT2:

    pts1和pts2当使用基本矩阵E进行三角测量时,R和t返回[R, t] = cv.recoverPose(E, p1, p2,'CameraMatrix',K);

    X1 =
    
       -0.0940    0.0478   -0.4984
       -0.0963    0.0497   -0.4987
        0.3033    0.1009   -0.5202
       -0.0065    0.0636   -0.5053
       -0.0737    0.0653   -0.5011
    

    R =
    
       -0.9977   -0.0063    0.0670
        0.0084   -0.9995    0.0305
        0.0667    0.0310    0.9973
    

    t =
    
        0.0239
        0.0158
        0.9996
    

    使用Matlab代码进行三角测量时,所选解决方案为E_all{2}

    R_all{2}=
    
       -0.8559   -0.2677    0.4425
       -0.1505    0.9475    0.2821
       -0.4948    0.1748   -0.8512
    

    t_all{2}=
    
       -0.1040
       -0.1355
        0.9853
    
    X2 =
    
        0.1087   -0.0552    0.5762
        0.1129   -0.0578    0.5836
        0.4782    0.1582   -0.8198
        0.0028   -0.0264    0.2099
        0.0716   -0.0633    0.4862
    

    做的时候

    X1./X2
    
    ans =
    
       -0.8644   -0.8667   -0.8650
       -0.8524   -0.8603   -0.8546
        0.6343    0.6376    0.6346
       -2.3703   -2.4065   -2.4073
       -1.0288   -1.0320   -1.0305
    

    三角形3D点之间存在几乎恒定的比例因子。 但是,旋转矩阵是不同的,并且在翻译之间没有比例因子。

     t./t_all{2}=
           -0.2295
           -0.1167
            1.0145
    

    使得绘制的轨迹错误

1 个答案:

答案 0 :(得分:1)

回答编号的问题:

  1. 请注意,Nister的5点算法有很多实现,但是大多数都能很好地工作。个人经验和同事未发表的工作表明,OpenCV没有很好的实现。 Bundler和其他工作 SfM管道中的开放式实施在实践中效果更好(但仍有很多的改进空间)。

  2. 这10个解仅是某个多项式方程的零。就多项式方程式可以描述问题而言,这10个解均使方程式为零。该方程式并未描述这10个点是真实的,或者与每个5个点对应的3D点对于每个解决方案都必须相同,而只是说明有一些3D点(对每个解决方案)都投影到5个点上点,甚至不考虑3D点是否在相应摄像机的前面。此外,很可能有两组3D点和相机恰好会生成5点的相同图像,因此您必须通过其他一些步骤将它们除掉(如下)。

  3. 通常通过多种技术来选择10种复杂解决方案中的正确解决方案:

    • 舍弃可能导致纯复杂点或3D点深度为负的解决方案(当前,Bundler不会最后检查)
    • 由于其他原因丢弃非物理解决方案(您可能需要为应用程序自行完成其中的一部分)
    • 更常见的过程:对于每个剩余的解决方案,检查哪个与其他对应关系更一致。在真实的系统中,您不知道哪些其他对应是正确的,哪些是纯垃圾。因此,对每种解决方案都运行RANSAC,并保持最合理的解决方案。这在计算上很繁琐,因此应将其作为最后的手段。

您可以在文件5point.c line 668中查看Bundler的操作方式:

    generate_Ematrix_hypotheses(5, r_pts_inner, l_pts_inner, &num_hyp, E);

    for (i = 0; i < num_hyp; i++) {
        int best_inlier;
        double score = 0.0;

        double E2[9], tmp[9], F[9];
        memcpy(E2, E + 9 * i, 9 * sizeof(double));
        E2[0] = -E2[0];
        E2[1] = -E2[1];
        E2[3] = -E2[3];
        E2[4] = -E2[4];
        E2[8] = -E2[8];

        matrix_transpose_product(3, 3, 3, 3, K2_inv, E2, tmp);
        matrix_product(3, 3, 3, 3, tmp, K1_inv, F);

        inliers = evaluate_Ematrix(n, r_pts, l_pts, // r_pts_norm, l_pts_norm, 
                                   thresh_norm, F, // E + 9 * i, 
                                   &best_inlier, &score);

        if (inliers > max_inliers ||
            (inliers == max_inliers && score < min_score)) {
            best = 1;
            max_inliers = inliers;
            min_score = score;
            memcpy(E_best, E + 9 * i, sizeof(double) * 9);
            r_best = r_pts_norm[best_inlier];
            l_best = l_pts_norm[best_inlier];
        }

        inliers_hyp[i] = inliers;
    }