如何使用OpenCV捆绑调整技术

12

我已经计算了5个摄像机矩阵(c1, ... c5),这些矩阵是通过将一个3D物体放置在5个不同的位置并为每个位置计算摄像机矩阵(且摄像机保持不变)来计算得出的。摄像机矩阵使用SVD方法计算。

现在我想使用opencv中的束调整算法得到一个最优的摄像机矩阵。我在这里找到了文档。

但是文档不清晰,而且我也找不到任何示例代码。有人能解释一下如何使用opencv的束调整算法来获得最优的摄像机矩阵吗?


你的问题不太有意义,因为捆绑调整技术通常用于联合估计多个相机帧的姿态(即描述方向和位置的T=[R|t])和一些观察点的三维位置。要估计相机矩阵(即内部参数矩阵K),您通常会使用校准过程,例如在此处解释的过程:http://docs.opencv.org/2.4/doc/tutorials/calib3d/camera_calibration/camera_calibration.html#cameracalibrationopencv。 - BConic
@AldurDisciple 捆绑调整不仅限于优化姿态,您还可以添加用于优化K的方程。OpenCV的代码也是如此。虽然有一个可以用来指定要优化哪些K成员或不优化任何成员的掩码。 - fireant
@fireant true,如果OpenCV支持它,这是一个好消息。但从问题中仍然不清楚OP是否有意提到Bundle Adjustment或只是作为一种联合优化的方式。值得注意的是,calibrateCamera函数的设计比标准校准模式更通用,并且它还可以处理抽象的3D模式。 - BConic
2个回答

17
我的答案假设您使用了一个具体的三维对象,其尺寸已知“准确”,以从该对象的多个图像中估计出“一个相机”的内部参数。考虑到您对@fireant的答案的评论,我认为这适用于您的问题。
关于“相机矩阵”含义的快速说明:
术语“相机矩阵”非常模糊,可以有多种理解:
- 相机姿态T=[R|t],也称外部相机参数。 - 内部相机矩阵K=[fx,s,cx; 0,fy,cy; 0,0,1]。 - 相机投影矩阵P=K.[R|t]。
由于您提到拥有多个图像但只需要一个相机矩阵,因此我认为您是在谈论内部相机矩阵K。
为什么不应使用捆绑调整:
捆绑调整是一种解决比相机校准更一般化的问题的技术,其中外部相机参数(即3D方向和位置)和3D地标(例如3D点)均未知。正如@fireant所指出的那样,也可以在此全局联合优化中包括内部相机参数。另一方面,相机校准假定已知3D地标并且由单个相机在多个图像中观察到,因此它优化了单组内部相机参数和每个图像的一个相机姿态。
需要理解的是,更一般化的优化问题涉及更多要优化的变量,因此很难使它们具有充分的约束性。如果它们没有充分的约束性,它们将以一种确实减少全局误差但不对应于您真正问题的解决方案的方式优化您的变量。这就是为什么在使用联合优化算法时,您应该尝试减少要优化的变量数量的原因。
在捆绑调整与相机校准之间的情况下,只有在您对3D地标的位置“没有准确的想法”时才应使用捆绑调整。即使如此,最好还是尝试将问题分离开,例如先对3D对象进行校准。如果您确切知道3D地标的位置,则它们不应被视为要优化的变量,因此应使用相机校准技术。
优化的初始估计:
您说您拥有相机矩阵K的多个不精确估计,并希望执行联合优化以获得单个更精确的估计。问题在于,由于您希望估计单个相机矩阵,因此您需要向联合优化算法提供“仅一个初始估计”。
你可以尝试选择距离真实解最近的初始估计值作为优化算法的初始估计值,以便仍然使用多个近似估计。为此,您可以使用几个启发式标准。例如,您可以选择与最小重投影误差相关联的标准,或者您可以使用与校准对象最大的图像相关联的标准等。
但是,这可能不会对相机矩阵的最终估计产生很大影响。
如何使用“calibrateCamera”完成此任务
假设您有一个具有特征点的校准对象。它可以是标准的2D棋盘或非对称圆网格,也可以是任何已校准的3D对象。并且假设您已经开发了一种方法来在图像中检测此校准对象(例如自定义特征检测器或手动确定对象位置的工具)。然后,您可以定义一个包含可以检测到的对象上的3D点的向量allObjectPoints。然后对于每个图像i,您可以确定一个向量imagePoints_i,其中包含检测到的用于观察某些对象的3D点的2D点(请注意,某些对象点可能被遮挡,因此可能比allObjectPoints中的项目少)。然后,由于所有对象点都是可识别的(直接或通过推理),因此您可以确定向量objectPoints_i,其中包含实际在图像i中观察到的对象3D点,并与imagePoints_i一致排序。
然后,您将所有objectPoints_i向量堆叠在一个大的向量向量objectPoints中。同样,您将所有imagePoints_i向量堆叠在一个大的向量向量imagePoints中。然后,您可以调用calibrateCamera,并使用CV_CALIB_USE_INTRINSIC_GUESS标志指示您希望优化算法使用您提供的初始值。

10

请参阅《使用OpenCV学习图像处理》第155页的示例代码。类似这样:

vector<CameraParams> cameras;
vector<MatchesInfo> pairwise_matches;
vector<ImageFeatures> features(num_images);

// initialize the above params here

Ptr<BundleAdjusterBase> adjuster;
adjuster = makePtr<BundleAdjusterReproj>();
if (!(*adjuster)(features, pairwise_matches, cameras)) {
    cout << "Camera parameters adjusting failed." << endl; 
    return -1;
}

如果您提供一个最小化完整可复制的示例(MCVE),则更容易提供帮助。

编辑: 假设您有5个相同K矩阵的估计值。最简单的方法是将这5个估计值平均,以获得更准确的K值。在一些温和的假设下,这将是一个最优的估计。如果再投影误差差异很大,则可以计算加权平均值。


我认为,在这个例子中,每个相机矩阵都被优化了。那么我该如何得到一个单一的最终相机矩阵呢? - Deepak
1
@user_12,看起来我误解了你的问题。请查看我的修改。 - fireant

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