使用opencv进行外在矩阵计算

Luc*_*uca 6 opencv camera-calibration coordinate-transformation

我正在使用 opencv 来校准我的网络摄像头。所以,我所做的是将我的网络摄像头固定到一个装备上,使其保持静止,我使用了棋盘校准模式并将其移动到相机前,并使用检测到的点来计算校准。所以,这是我们可以在许多 opencv 示例中找到的(https://docs.opencv.org/3.1.0/dc/dbb/tutorial_py_calibration.html)

现在,这为我提供了相机内在矩阵和旋转和平移组件,用于将这些棋盘视图中的每一个从棋盘空间映射到世界空间。

然而,我感兴趣的是全局外部矩阵,即一旦我移除了棋盘格,我希望能够在图像场景中指定一个点,即 x、y 及其高度,它给我在世界空间中的位置. 据我了解,为此我需要内在和外在矩阵。应该如何从这里开始计算外部矩阵?我是否也可以使用从棋盘校准步骤中收集到的测量值来计算外部矩阵?

Mil*_*ilo 6

让我提供一些背景信息。考虑下图,(来自https://docs.opencv.org/2.4/modules/calib3d/doc/camera_calibration_and_3d_reconstruction.html):

在此处输入图片说明

相机“附加”了一个刚性参考系 (Xc,Yc,Zc)。您成功执行的内在校准允许您将点 (Xc,Yc,Zc) 转换为其在图像 (u,v) 上的投影,并将图像中的点 (u,v) 转换为 (Xc, Yc,Zc)(您只能将其提高到一个比例因子)。

在实践中,您希望将相机放置在外部“世界”参考系中,我们称之为 (X,Y,Z)。然后是刚性变换,由旋转矩阵R和平移向量T 表示,使得:

|Xc|    |X|
|Yc|= R |Y| + T
|Zc|    |Z|
Run Code Online (Sandbox Code Playgroud)

这就是外在校准(也可以写成 4x4 矩阵,这就是您所说的外在矩阵)。

现在,答案。要获得R和T,您可以执行以下操作:

  1. 修复您的世界参考系,例如地面可以是 (x,y) 平面,并为其选择一个原点。

  2. 在此参考系中设置一些已知坐标的点,例如,地板中方形网格中的点。

  3. 拍照并获取相应的2D图像坐标。

  4. 使用solvePnP获取旋转和平移,参数如下:

    • objectPoints:世界参考系中的 3D 点。
    • imagePoints:图像中对应的2D点,与objectPoints的顺序相同。
    • cameraMatris:你已经拥有的内在矩阵。
    • distCoeffs:您已有的失真系数。
    • rvec , tvec:这些将是输出。
    • useExtrinsicGuess: 假
    • 标志:您可以使用 CV_ITERATIVE
  5. 最后,使用Rodrigues函数从rvec得到R。

您将需要至少 3 个具有相应 3D-2D 坐标的非共线点才能使 solvePnP 工作(链接),但越多越好。为了获得高质量的点,您可以打印一个大棋盘图案,将其平放在地板上,并将其用作网格。重要的是图像中的图案不能太小(越大,校准越稳定)。

而且,非常重要:对于内在校准,您使用了具有特定大小方块的国际象棋模式,但您告诉算法(它为每个模式执行某种 solvePnPs),每个方块的大小为1。这不是明确的,而是在示例代码的第 10 行中完成的,其中网格是用坐标 0,1,2,... 构建的:

objp[:,:2] = np.mgrid[0:7,0:6].T.reshape(-1,2)

外部校准的世界规模必须与此匹配,因此您有几种可能性:

  1. 使用相同的比例,例如使用相同的网格或以相同的比例测量“世界”平面的坐标。在这种情况下,您的“世界”不会处于正确的规模。

  2. 推荐:使用正确的刻度重做内在校准,例如:

    objp[:,:2] = (size_of_a_square*np.mgrid[0:7,0:6]).T.reshape(-1,2)

    其中 size_of_a_square 是正方形的实际大小。

  3. (没做过,但理论上可行,做不到就做 2)通过缩放 fx 和 fy 重用内在校准。这是可能的,因为相机可以看到比例因子内的所有内容,并且正方形的声明大小仅更改 fx 和 fy (以及每个正方形的姿势中的T,但那是另一回事)。如果正方形的实际大小为L,则在调用 solvePnP 之前替换 fx 和 fy L fx 和 L fy。