使用opencv计算外部矩阵

extrinsic matrix computation with opencv

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

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

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

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

相机有 "attached" 刚性参考系 (Xc,Yc,Zc)。您成功执行的 intrinsic 校准允许您将一个点 (Xc,Yc,Zc) 转换为它在图像上的投影 (u,v),以及一个点 (u,v)将图像中的光线转换为 (Xc,Yc,Zc) 中的光线(您只能将其调整为比例因子)。

实际上,您希望将相机放置在外部 "world" 参考系中,我们称之为 (X,Y,Z)。然后是刚性变换,由旋转矩阵 R 和平移向量 T 表示,这样:

|Xc|    |X|
|Yc|= R |Y| + T
|Zc|    |Z|

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

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

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

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

  3. 拍照并得到对应的二维图像坐标

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

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

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

并且,非常重要:对于内在校准,您使用了具有一定大小正方形的国际象棋图案,但是您告诉算法(它为每个pattern),即每个正方形的大小为 1。这不是明确的,而是在示例代码的第 10 行完成的,其中网格是用坐标 0,1,2,...:[=​​16=] 构建的

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

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

  1. 使用相同的比例,例如使用相同的网格或以相同的比例测量 "world" 平面的坐标。在这种情况下,您 "world" 的比例不正确。

  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 Lfx和Lfy