相机校准:宽高比与图像宽高比不同。怎么纠正?

时间:2012-11-02 14:11:40

标签: opengl opencv camera-calibration

我一直在我的OpenCV和OpenGL组件之间来回走动,我不确定这两者中哪一个应该更正。

使用OpenCV相机校准产生fx,fy,纵横比约为1,这对应于方形尺寸的图像。我的校准输出:

...
image_width: 640
image_height: 480
board_width: 6
board_height: 9
square_size: 5.
flags: 0
camera_matrix: !!opencv-matrix
   rows: 3
   cols: 3
   dt: d
   data: [ 6.6244874649105122e+02, 0., 3.4060477796553954e+02, 
        0., 6.4821741696313484e+02, 2.5815418044786418e+02, 
        0., 0., 1. ]
distortion_coefficients: !!opencv-matrix
   rows: 5
   cols: 1
   dt: d
   data: [ -1.1832005538154940e-01, 1.2254891816651683e+00, 3.8133468645674677e-02, 1.3073747832019200e-02, -3.9497162757084490e+00 ]

但是,我的图像宽度为640x480,您可以在校准输出中看到。

当我在框架中检测到棋盘并用OpenGL绘制棋盘时,OpenGL在高度上渲染得很好但在宽度方向上拉伸,因此它不适合棋盘所在的位置。当然解决这个问题的是将校准的fx分量乘以480/640,但我不知道这是否可行。

我该如何纠正?使用图像大小缩放校准值,还是在OpenGL中执行某些操作来修复它?

修改

捕获和显示之间存在区别。我使用经过校准的智能手机捕获图像,智能手机会喷出640x480的图像。

为了找到棋盘,我使用了如上所示的内在函数,它已被校准。

然后,无论我给OpenGL哪个宽高比,让它为fx / fy,640/480或fx / fy * 640/480,都是错误的。以OpenGL投影的方式投射回OpenGL的棋盘在宽度方向上拉伸。

在OpenGL中看起来完全正确的唯一方法是,如果我使用fx = 640,fy = 480 来查找棋盘。这也是错误的,因为现在我完全无视相机内在函数...... enter image description here

EDIT2

我的意思是无论我如何设置我传递给gluPerspective的宽高比,它都不对。

gluPerspective( /* field of view in degree */ m_fovy,
   /* aspect ratio */ 1.0/m_aspect_ratio,
   /* Z near */ 1.0, /* Z far */ 1000.0);

我为m_aspect_ratio的值尝试了什么:

  • OpenCV的calibrationMatrixValues
  • 的输出宽高比
  • FX / FY
  • 四百八十零分之六百四十○
  • fx / fy * 640/480
  • calibrationMatrixValues * 640/480
  • 的输出

所有人似乎都在宽度。请注意,棋盘的原点在我的屏幕截图中是图像中最顶部的内角:它被正确放置,图像中最下面的内角也是如此。这是一个缩放问题..

EDIT3

这真的非常愚蠢......我正在设置OpenGL的宽高比,如下所示:

gluPerspective( /* field of view in degree */ m_fovy,
    /* aspect ratio */ 1.0/m_aspect_ratio,
    /* Z near */ 1.0, /* Z far */ 1000.0);

并设置

m_aspect_ratio = viewportpixelheight / viewportpixelwidth;

没有意识到viewportpixelheightviewportpixelwidth是整数,所以我正在进行整数除法,这得分为1或(当交换它们时)在0中。

2 个答案:

答案 0 :(得分:1)

相机校准矩阵将世界坐标映射到图像坐标。 OpenGL将图像坐标映射到屏幕坐标。如果你的问题在于图像的显示方式,你应该在OpenGL中处理它。

我很抱歉这个混乱。我想要做的是区分捕获和显示图像。你是正确的,可以从焦距计算物理相机的纵横比。这些焦距和纵横比由相机的硬件固定。捕获该图像后,您可以使用OpenGL以任何宽高比自由显示该图像。您可以裁剪和拉伸图像,以更改显示的宽高比。没有给出相机的宽高比与屏幕的宽高比相匹配。 OpenCV使用物理相机的直接原始测量值计算相机校准矩阵。如果我们假设它们是正确且恒定的(如果没有缩放,这两者似乎都是合理的)那么对宽高比的任何进一步改变都是OpenGL的责任。当我说fx和fy没有确定纵横比时,我指的是显示的宽高比,这对我来说并不是很清楚。

另外,我应该提一下,你可以从焦距计算纵横比的原因是焦距以像素为单位表示,这些单位在x和y轴上可以不同。可以找到简要说明here

我在相机矩阵中发现焦距的最佳解释是在Computer Vision Algorithms and Applications的相机内在函数部分。在pdf中,它从书的第72页,第50页开始。

答案 1 :(得分:0)

纵横比为1.0并不表示方形图像,它表示方形像素(这解释了为什么它几乎总是1.0;非方形像素相对较少,除了在{ {3}})。相机矩阵不包含有关绝对图像尺寸物理相机尺寸的信息。

另一方面,gluPerspective的宽高比 表示图像尺寸。重要的是不要将一个纵横比混淆为另一个。

如果你想使用gluPerspective,它是可能的,但你应该明白gluPerspective不允许你模拟所有内在的相机参数(即轴偏斜和主点偏移)。我描述了如何正确设置宽高比和fovy anamorphic format

但是,我强烈建议使用gluFrustum(允许非零主点偏移)或直接glLoadMatrix(也允许非零轴偏斜)。这两种方法都在in this article中解释。