使用 OpenCV 的 solvePnP 函数进行外部相机校准

Extrinsic Camera Calibration Using OpenCV's solvePnP Function

我目前正在使用名为 3DSlicer 的医学成像程序开发增强现实应用程序。我的应用程序作为 Slicer 环境中的一个模块运行,旨在提供使用外部跟踪系统来增强 Slicer 中显示的相机源所需的工具。

目前,一切都已正确配置,所以我剩下要做的就是自动计算相机的外部矩阵,我决定使用 OpenCV 的 solvePnP() 函数来完成。不幸的是,这给我带来了一些困难,因为我没有获得正确的结果。

我的跟踪系统配置如下:

我得到了两组点,一组是2D的,一组是3D的。 2D 点是棋盘角在像素坐标中的坐标,而 3D 点是这些相同角相对于 M 的相应世界坐标。这些是使用 openCV 的 detectChessboardCorners() 函数记录的二维点和指针3维。然后我将 3D 点从 M space 乘以 C space 到 C space。这样做是因为 solvePnP() 函数要求相对于相机的世界坐标系描述 3D 点,在本例中是 C,而不是 M。

完成所有这些后,我将点集传递给 solvePnp()。不过,我得到的转换是完全不正确的。老实说,我对自己做错了什么感到茫然。让我更加困惑的是,OpenCV 使用与 OpenGL 不同的坐标格式,而 OpenGL 正是 3DSlicer 所基于的坐标格式。如果有人可以在这件事上提供一些帮助,我将非常感激。

此外,如果有任何不清楚的地方,请随时询问。这是一个相当大的项目,所以我很难将所有内容提炼成手头的问题。我完全预料到阅读本文的人可能会感到有些困惑。

谢谢!

更新 #1:原来我是个大白痴。我记录共线点只是因为我没有耐心记录整个棋盘。当然,这意味着最小二乘回归有几乎无限的解,因为我只将解锁定为二维!我的价值观现在更接近我的基本事实,事实上,旋转列看起来是正确的,只是它们完全乱序了。我不确定是什么原因造成的,但似乎我的旋转矩阵在中心列上进行了镜像。除此之外,我的翻译组件在应该为正时却为负,尽管它们的大小似乎是正确的。所以现在我基本上以错误的顺序获得了所有正确的值。

Mirror/rotational歧义。

您基本上需要通过施加以下约束来重新定向您的坐标系:(1) 场景在相机前面,(2) 棋盘轴的方向与您预期的方向一致。这归结为将您的校准变换乘以适当的 ("hand-built") 旋转 and/or 镜像。

基本问题是您使用的校准目标 - 即使看到所有角,也至少有 180^ 度的旋转模糊度,除非使用颜色信息。如果遗漏了一些角落,事情会变得更加奇怪。

您通常可以使用有关相机方向的先验信息 w.r.t。正如我在上面所建议的那样,解决这种歧义的场景。然而,在更动态的情况下,如果在目标可能仅部分可见的情况下需要更高程度的自动化,您最好使用可以单独识别每个小块角的目标。我最喜欢的是 Matsunaga 和 Kanatani 的“二维条形码”,它使用具有独特交叉比的方形长度序列。请参阅论文 here