如何使用opencv bundle调整

时间:2016-07-13 18:17:12

标签: opencv camera mathematical-optimization camera-calibration

我计算了5个相机矩阵(c1, ... c5),通过将3D物体放置在5个不同位置来计算相机矩阵,并且对于每个位置我计算出相机矩阵(并且相机是恒定的)。相机矩阵使用SVD方法计算。

现在我想在opencv中使用束调整来获得一个最佳的相机矩阵。 我找到了文档here

但是文档不清楚,我也找不到任何示例代码。 任何人都可以解释我如何使用opencv bundle调整来获取optimal camera matrix

2 个答案:

答案 0 :(得分:9)

我的回答是假设您使用特定的3D对象,其尺寸已知准确,以从多个图像中估算一个摄像头的内在参数。根据你对@fireant的回答的评论,我认为这适用于你的问题。

关于'相机矩阵'

含义的快速说明

术语“相机矩阵”非常模糊,可以通过多种方式理解:

  • 相机姿势T = [R | t],也表示外部相机参数。
  • 内在相机矩阵K = [fx,s,cx; 0,fy,cy; 0,0,1]。
  • 相机投影矩阵P = K. [R | t]。

正如你所说,你有多个图像,但你想要一个相机矩阵,我认为你在谈论内在的相机矩阵K.

为什么不应该使用Bundle Adjustment

束调整是一种用于解决比相机校准更普遍的问题的技术,其中外部相机参数(即3D方向和位置)和3D地标(例如3D点)都是未知的。正如@fireant所指出的,在全局联合优化中也可以包含内在的相机参数。另一方面,相机校准假设3D地标已知并由多个图像中的单个相机观察,因此它优化了一组固有相机参数和每个图像的一个相机姿势。

要理解的是,更一般的优化问题涉及更多要优化的变量,因此更难以使它们受到良好约束。如果它们没有很好的约束,它们将以确实减少全局误差的方式优化变量,但这并不符合您真正问题的解决方案。这就是为什么在使用联合优化算法时,应该总是尝试减少要优化的变量数量。

在捆绑调整VS摄像机校准的情况下,如果您对<3D>地标的位置没有准确的想法,则应该仅使用捆绑调整。即便如此,尝试解耦问题可能是更好的主意,例如事先校准3D对象。如果您确切了解3D地标的位置,则不应将它们视为要优化的变量,因此您应该使用相机校准技术。

优化的初步估算

您说您对相机矩阵K有多个不准确的估计值,并希望执行联合优化以获得更准确的一个。问题在于,由于您想要估算单个相机矩阵,因此您需要为联合优化算法提供仅一个初始估计

为了仍然使用多个近似估计,您可以做的是尝试选择最接近真实解决方案的优化算法的初始估计。为此,您可以使用多个启发式标准。例如,您可以选择与最小重投影误差相关联的那个,或者您可以使用与校准对象最大的图像相关联的那个,等等。

然而,它可能不会对相机矩阵的最终估计产生很大的影响。

如何使用'calibrateCamera'完成此任务

假设您有一个带有特征点的校准对象。它可以是标准的2D棋盘或不对称圆网格,或任何校准的3D对象。并且假设您已经开发出一种在图像中检测该校准对象的方法(例如,自定义特征检测器或手动确定对象位置的工具)。然后,您可以定义向量allObjectPoints,其中包含可以检测到的对象上的3D点。然后,对于每个图像i,您可以确定检测到的2D点的向量imagePoints_i是对某些对象的3D点的观察(请注意,某些对象点可能被遮挡,因此可能会有更少的项目而不是allObjectPoints)。然后,由于所有对象点都是可识别的(直接或通过推理),您可以确定向量objectPoints_i,其中包含在图像i中实际观察到的对象3D点,并与{{1}一致地排序}。

然后将所有imagePoints_i向量堆叠在向量objectPoints_i的一个大向量中。类似地,您将所有objectPoints向量堆叠在向量imagePoints_i的一个大向量中。然后,您可以使用标记imagePoints拨打calibrateCamera,以表明您希望优化算法使用您提供的初始值。

答案 1 :(得分:8)

请参阅Learning Image Processing with 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.在一些温和的假设下,这将是一个最佳估计。如果重投影错误差异很大,那么您可以计算加权平均值。