【问题标题】:OpenCV - calibrate camera using static images in waterOpenCV - 使用水中的静态图像校准相机
【发布时间】:2013-07-22 10:50:22
【问题描述】:

我有一个相机垂直安装在水箱的水下,向下看。 水箱底部有一个扁平的网格(距离相机约 2m)。 我希望能够在底部放置标记,并使用计算机视觉来了解它们在现实生活中的确切位置。

所以,我需要从像素映射到毫米。 如果我没记错的话, cv::calibrateCamera(...) 就是这样做的,但取决于在相机前移动一个图案。 我只有场景的静态图片,相机从不相对于网格移动。因此,我只有一个“单一”图像来查找参数。 我怎样才能使用网格做到这一点?

谢谢。

【问题讨论】:

    标签: opencv computer-vision camera-calibration


    【解决方案1】:

    有趣的问题! “可爱”的部分是对水玻璃界面折射的内在参数的影响,即与空气中的相同镜头相比,增加焦距(或相反,减少视场)。理论上,您可以在空气中校准,然后校正折射率差异,但直接在水中校准可能会得到更准确的结果。

    知道您的精度要求吗?您是否已验证您的镜头/传感器组合足以满足它们(有足够的余量)?要回答您需要估计的问题(通过镜头和传感器规格计算,或使用分辨率图表进行实验),您是否可以在图像中解决应用程序所需的最小距离。

    从你问题的措辞我认为你只对单个平面上的测量感兴趣。因此,您只需要 (a) 消除非线性(桶形或枕形)镜头失真和 (b) 估计感兴趣平面和图像之间的homography。一旦你有了后者,你可以通过矩阵乘法直接将未失真的图像坐标转换为世界坐标。此外,如果(如我想象的那样)感兴趣的平面大致平行于图像平面,那么保持整个视场焦点在焦点上应该没有任何问题。

    当然,要使所有这些都按预期工作,您应该确保水箱底部确实是平的,在您的应用程序的测量公差范围内。否则,您实际上是在处理 3D 问题,需要相应地修改您的程序。

    实际程序在很大程度上取决于水箱的大小,您没有明确指出。如果它足够小,可以制作一个类似棋盘的可移动校准目标,那就去吧。您可能想查看this other answer 以获取建议。在下文中,我将讨论更有趣的情况,即您的水箱很大,例如游泳池的大小。

    我会在池底的规则网格中粘贴校准标记。我可能会选择像these 这样的类似棋盘格的标记,也许自己用一台好的激光打印机在塑料上打印它们,并带有粘合剂背衬(假设你可以永远将它们留在原处)。您应该计划使用其中的一些,例如 8x8 或 10x10 的网格,尽可能多地覆盖摄像机在其工作位置和姿势的视野。为了更好地排列网格,您可以使用合适的扇形角度的激光线投影仪,或连接到旋转支架的激光指示器。请注意,不必将它们固定在精确的 X-Y 网格中(这可能很复杂,具体取决于您的池的大小),只需知道它们相对于任意选择(但固定)其中三个的位置。换句话说,您可以将它们大致以网格的形式连接到底部,然后尽可能准确地测量三个极端角之间的距离,从而构建一个基础三角形,然后测量所有其他角到三角形的顶点,最后用一点三角函数重建它们的真实位置。这基本上是一个测量问题,根据您的精度要求和预算,您可能需要聘请当地友好的专业测量师(及其工具)来尽可能精确地完成它。

    一旦您有了网格,您就可以根据应用程序的需要填充池、获取相机、对焦和 f-stop 镜头。从现在开始,您可能再也不会触摸焦点和光圈,否则会受到校准错误的惩罚 - 曝光只能通过曝光时间来控制,因此请确保有足够的光线。禁用任何和所有自动对焦和自动光圈功能(如果有)。如果相机具有非刚性镜头座(例如 DLSR),您将需要某种机械装置来确保镜头-机身对保持刚性。考虑到可用的照明和传感器,F-stop 尽可能接近,以便有相当多的景深可用。然后拍几张网格的照片(~ 10),移动和旋转相机,然后离飞机的预期操作距离越来越远。您会希望在某些图像中“看到”网格的一些重要透视缩短 - 这是准确校准焦距所必需的。存储图像时避免使用 JPG 和任何其他有损压缩格式 - 使用无损 PNG 或 TIFF。

    获得图像后,您可以手动标记和识别图像中的棋盘格标记。对于像这样的一次性项目,我不会为自动识别而烦恼,只需手动进行(例如在 Matlab 中,甚至在 Photoshop 或 Gimp 中)。为了帮助识别标记,您可以,例如在它们旁边打印一个数字。一旦你有了手动标记,你可以自动将它们细化到亚像素精度,例如使用 cv::findCornerSubpix。

    你快完成了。将真实角落的“参考”测量位置以及所有图像中观察到的位置输入到您最喜欢的相机校准程序中,例如cv::calibrateCamera。您使用相机的标称焦距(转换为像素)进行初始估计,以及零失真。如果一切顺利,您将获得相机内参,您将保留,相机对所有图像的姿势,您将丢弃。

    现在您可以根据应用程序的需要在最终设置中安装相机,然后再拍摄一张网格图像。像以前一样标记和细化角位置。使用校准返回的失真参数对它们的图像位置进行不失真。最后计算真实标记的参考位置(以米为单位)与其未失真位置之间的单应性,就完成了。

    HTH

    【讨论】:

    • 感谢您提供非常全面的回答!对于没有说明所有相关信息,我深表歉意。水箱有游泳池那么大,实际上大到我无法校准然后装满它。这需要几天的时间。你是对的,测量值只有 2D(在水箱底部是平的)。我无法轻松返回并重复,所以如果我能以某种方式使用现有图像进行校准,那就太好了。我的底部网格几乎覆盖了整个视野,并且知道网格大小,我应该能够以某种方式纠正图像?
    【解决方案2】:

    要校准相机,您需要多张棋盘图像(或找到的其他图案之一here)。您可以做的是在水中校准相机或执行一次校准序列。

    获得这些信息(焦距、镜头中心、畸变等)后。您可以使用 solvePNP 函数来估计单个板的方向。此估算为您提供了从相机到电路板的距离。

    另一种完全不同的选择可能是找到相机使用的镜头类型并手动填写数据。我还没有尝试过,所以我不确定它的效果如何。

    【讨论】:

    • 是的,这是第二个选项,我将不胜感激。我知道诸如到目标的距离、所有方块的像素大小、传感器大小等参数。焦距是手动可调的,我不知道当时设置了什么,但我可以计算出来。我希望我可以通过提供一些已知距离(以毫米为单位)的点来校准相机。然后针对这个特定的静态环境进行校准。
    • 你可以“蛮力”焦距。尝试几个值,看看哪些值看起来效果最好。
    猜你喜欢
    • 2014-07-30
    • 2013-09-13
    • 2019-01-05
    • 1970-01-01
    • 1970-01-01
    • 2013-01-28
    • 2014-10-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多