我想使用Matlab编写自己的sfm管道代码,因为我需要一些opencv函数不提供的输出.但是,我使用opencv进行比较.
Opencv函数[E,mask] = cv.findEssentialMat(points1,points2,’CameraMatrix’,K,’Method’,’Ransac’);使用Nister的五点算法和RANSAC提供基本矩阵解决方案.
使用以下内容找到inlier指数:InliersIndices = find(mask> 0);
我使用了Nister算法的Matlab实现:
对函数的调用如下:
[E_all, R_all, t_all, Eo_all] = five_point_algorithm( pts1, pts2, K, K);
该算法输出多达10个基本矩阵的解.但是,我遇到了以下问题:
>上面提到的impelmentation仅用于完美对应(没有Ransac),并且我使用InliersIndices为算法5提供对应,输出的基本矩阵(最多10个)都不同于Opencv返回的矩阵.
>所有返回的基本矩阵应该是解决方案,那么为什么当我使用以下函数对每个矩阵进行三角测量时,我不会获得相同的3D点?
>如何选择合适的基本marix解决方案?
我使用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]返回的E = cv.findEssentialMat(points1,points2,’CameraMatrix’,K,’Method’,’Ransac’);
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
这使得绘制的轨迹错误
最佳答案 回答你的问题:
>注意Nister的5点算法有很多实现,但大多数都不能很好地工作.同事的个人经验和未发表的工作表明,OpenCV没有很好的实施. Bundler和其他工作SfM管道的开放实施在实践中工作得更好(但仍有很大的改进空间).
> 10个解决方案只是某个多项式方程的零点.就多项式方程可以描述问题而言,这10个解决方案都将方程式归零.该等式没有描述这10个点是真实的,或者对应于5个点对应的3D点对于每个解决方案必须是相同的,而只是有一些3D点(对于每个解决方案)投射到5点,甚至没有考虑3D点是否在相应的摄像机前面.此外,可能会有两组3D点和相机碰巧生成相同的5点图像,因此您必须使用其他一些程序(下图)将它们清除掉.
>在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;
}