我想用OpenCV做一些Structure-from-Motion。到目前为止,我有基本矩阵和基本矩阵。有了基本矩阵,我正在做 SVD 以获得 R 和 T。
我的问题是,我有 2 个可能的 R 解决方案和 2 个可能的 T 解决方案,这导致整体姿势有 4 个解决方案,其中 4 个解决方案中只有一个是正确的。如何找到正确的解决方案?
这是我的代码:
private void calculateRT(Mat E, Mat R, Mat T){
Mat w = new Mat();
Mat u = new Mat();
Mat vt = new Mat();
Mat diag = new Mat(3,3,CvType.CV_64FC1);
double[] diagVal = {1,0,0,0,1,0,0,0,1};
diag.put(0, 0, diagVal);
Mat newE = new Mat(3,3,CvType.CV_64FC1);
Core.SVDecomp(E, w, u, vt, Core.DECOMP_SVD);
Core.gemm(u, diag, 1, vt, 1, newE);
Core.SVDecomp(newE, w, u, vt, Core.DECOMP_SVD);
publishProgress("U: " + u.dump());
publishProgress("W: " + w.dump());
publishProgress("vt:" + vt.dump());
double[] W_Values = {0,-1,0,1,0,0,0,0,1};
Mat W = new Mat(new Size(3,3), CvType.CV_64FC1);
W.put(0, 0, W_Values);
double[] Wt_values = {0,1,0-1,0,0,0,0,1};
Mat Wt = new Mat(new Size(3,3), CvType.CV_64FC1);
Wt.put(0,0,Wt_values);
Mat R1 = new Mat();
Mat R2 = new Mat();
// u * W * vt = R
Core.gemm(u, Wt, 1, vt, 1, R2);
Core.gemm(u, W, 1, vt, 1, R1);
publishProgress("R: " + R.dump());
// +- T (2 possible solutions for T)
Mat T1 = new Mat();
Mat T2 = new Mat();
// T = u.t
u.col(2).copyTo(T1);
publishProgress("T : " + T.dump());
Core.multiply(T, new Scalar(-1.0, -1.0, -1.0), T2);
// TODO Here I have to find the correct combination for R1 R2 and T1 T2
}
从两个相机的基本矩阵重建两个相机的相对欧几里得姿势时,存在理论模糊性。这种模糊性与以下事实有关:给定图像中的2D点,经典的针孔相机模型无法判断相应的3D点是在相机前面还是后面。为了消除这种歧义,您需要知道图像中的一个点对应关系:由于这两个2D点被假定为位于两个相机前面的单个3D点的投影(因为它在两个图像中都是可见的),这将允许选择正确的R和T。
为此,在以下博士论文的§6.1.4(p47)中解释了一种方法:"三焦点张量的几何,约束和计算",由C.Ressl(PDF)。下面概述了此方法。我将用 x1 和 x2 表示两个对应的 2D 点,用 K1 和 K2 表示两个相机矩阵,用 E12 表示基本矩阵。
i. 计算基本矩阵E12 = U * S * V'
的 SVD 。如果det(U) < 0
设置U = -U
.如果det(V) < 0
设置V = -V
.
ii. 定义W = [0,-1,0; 1,0,0; 0,0,1]
、R2 = U * W * V'
和T2 = third column of U
iii. 定义M = [ R2'*T2 ]x
、X1 = M * inv(K1) * x1
和X2 = M * R2' * inv(K2) * x2
iv. 如果X1(3) * X2(3) < 0
,则设置R2 = U * W' * V'
并重新计算M
和X1
五.如果X1(3) < 0
设置T2 = -T2
vi. 定义P1_E = K1 * [ I | 0 ]
和P2_E = K2 * [ R2 | T2 ]
符号'
表示转置,步骤 iii. 中使用的符号[.]x
对应于斜对称运算符。在 3x1 向量上应用斜对称运算符e = [e_1; e_2; e_3]
会产生以下结果(请参阅维基百科关于跨积的文章):
[e]x = [0,-e_3,e_2; e_3,0,-e_1; -e_2,e_1,0]
最后,请注意,T2
的范数将始终为 1,因为它是正交矩阵的列之一。这意味着您将无法恢复两个摄像机之间的真实距离。为此,您需要知道场景中两点之间的真实距离,并考虑到这一点来计算摄像机之间的真实距离。