选择正确的本质矩阵

5
我想使用Matlab自己编写sfm管道,因为我需要一些opencv函数不提供的输出。然而,我正在使用opencv进行比较。
Opencv函数[E,mask] = cv.findEssentialMat(points1,points2,'CameraMatrix',K,'Method','Ransac');使用Nister的五点算法和RANSAC提供了基本矩阵解决方案。
使用以下代码找到内点索引: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),而我向算法提供了5个对应关系,使用InliersIndices,输出的本质矩阵(最多10个)与Opencv返回的不同。
2. 所有返回的本质矩阵都应该是解决方案,那么为什么当我使用下面的函数对每个本质矩阵进行三角测量时,我没有得到相同的三维点?
3. 如何选择正确的本质矩阵解决方案?
我使用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

编辑2:

使用本质矩阵E对pts1和pts2进行三角测量后,通过[R, t] = cv.recoverPose(E, p1, p2,'CameraMatrix',K);返回R和t。

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

When doing

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

这会导致轨迹图出现错误。


我能看到OpenCV和Matlab的结果矩阵吗?我猜它们只是一个比例因子的差别。 - dari
对于三角化的3D点,当我使用第一个返回的本质矩阵除以另一个解中三角化的点所得到的坐标时,会发现一个恒定的比例因子。即使与opencv返回的解不同,选择最小化重投影误差的解是否正确? - Daphnee
问题在于当我使用 Matlab 代码绘制轨迹时,得到的结果是垃圾。OpenCV 函数和 Matlab 函数三角化后的 3D 点相当,只相差一个比例因子。如何获得相同的旋转和平移以使绘制的轨迹正确? - Daphnee
1个回答

2
回答你的编号问题:

  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;
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接