我有多台校准过的相机拍摄平面场景。为简单起见,我们假设有3个摄像头。这些摄像机正在进行一般运动,但主要是平移加上一些轻微的旋转。摄像机位置示例
任务是把它们缝在一起。我对3D坐标一无所知,只知道用校准过的相机拍摄的一组图像。
我做什么:
我在OpenCV中检测SURF/SIFT实现的特征,通过在每对图像(1-> 2,2 -> 3,1 ->3)之间使用findHomography来获得初始同形图。从这些同形异构词中,我得到了每个相机姿势的初始估计(类似于这个过程)
然后我尝试使用束调整技术来最小化每个匹配对的重投影误差。优化的参数是三个平移值和三个旋转值(从Rodrigues的旋转公式中获得),尽管我可以稍后添加内在参数(焦点,主点等)。
假设图像#2是参考帧(通过与其他两个图像有最多的匹配),它的旋转和平移矩阵分别是单位矩阵和零矩阵。
我计算关键点(在图像#2和图像#1中都可见)从图像#2到图像#1的重投影为(伪代码)
[x1_; y1_; z1_] = K1*R1*inv(K2)*[x2; y2; 1] + K1*T1/Z2;
x1 = x1_/z1_;
y1 = y1_/z1_;
或
x1 = ((f1/f2)*r11*x2 + (f1/f2)*r12*y2 + f1*r13 + f1*tx/Z2) / ((1/f2)*r31*x2 + (1/f2)*r32*y2 + r33 + tx/Z2)
y1 = ((f1/f2)*r21*x2 + (f1/f2)*r22*y2 + f1*r23 + f1*ty/Z2) / ((1/f2)*r31*x2 + (1/f2)*r32*y2 + r33 + ty/Z2)
,其中r__是R1矩阵的元素,两个本征矩阵的形式为
[f 0 0]
[0 f 0]
[0 0 1]
我假设参考系的Z2坐标为1。
下一步是使用得到的相机矩阵(K1,R1,T1,K3,R3,T3)将图像#1和#3扭曲成图像#2的公共坐标系。
问题是我不知道Z1和Z3需要正确的重投影到图像#2的参考帧中,因为从图像#1到>#2的反向重投影看起来像这样:
x2 = ((f2/f1)*R11*x1 + (f2/f1)*R12*y1 + f2*R13 - f0/Z1*(R11*tx + R12*ty + R13*tz)) / ((1/f1)*R31*x1 + (1/f1)*R32*y1 + R33 - 1/Z1*(R31*tx + R32*ty + R33*tz))
y2 = ((f2/f1)*R21*x1 + (f2/f1)*R22*y1 + f2*R23 - f0/Z1*(R21*tx + R22*ty + R23*tz)) / ((1/f1)*R31*x1 + (1/f1)*R32*y1 + R33 - 1/Z1*(R31*tx + R32*ty + R33*tz))
其中R__为inv(R1)矩阵的元素。
是否有更好的方法计算重投影误差束调整(2d->2d),然后扭曲图像到共同坐标系?我注意到OpenCV在他们的拼接模块中有非常相似的框架,但它在纯旋转运动的假设下运行,而不是这里的情况。
我在我的帖子中自动回答了这个问题如何从外部参数中获得立体图像中的点
请注意,我使用的方法(经过测试和工作!)只有当物体在3D坐标(现实世界!)是平面的,并且它在Z=0(你校准相机的外部参数的点)时才有效。在这种情况下,这个方法和你的校准一样精确。注意:对于最好的校准检查opencv圆校准,它有0.018像素的再现误差(由在我大学工作的博士生测试)。
您可能已经在拒绝错误中发现了一个错误。它与这一行有关:
[x1_; y1_; z1_] = K1*R1*inv(K2)*[x2; y2; 1] + K1*T1/Z2;
The point [x2;y2;1]在尺度常数C*[x2;y2;1]在这里,当它通常是未知的时候,你设置C=1。在第一个视图中,可能性轨迹表现为极线。您可以使用最小二乘三角剖分来找到这条线上最可能存在3D点的点,然后计算重新投影的点如下:
[x1_; y1_; z1_] = K1*(R1*X + T1);
,然后按照上面的方法继续。点云中每个这样的点X的三维坐标可以使用其相应的归一化坐标(x1,y1), (x2,y2),…,以及相应的旋转矩阵和平移向量,将它们格式化为矩阵问题:
A X = b
,然后求解最小二乘:
min |A X - b|_2