1

我一直在我的 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来查找 chessboard。这也是错误的,因为现在我完全忽略了相机的内在特性......在此处输入图像描述

编辑2

我的意思是,无论我如何设置传递给 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
  • 640/480
  • fx/fy * 640/480
  • 校准矩阵值的输出 * 640/480

一切似乎都搞砸了宽度。请注意,在我的屏幕截图中,棋盘的原点是图像的最上角:它放置正确,图像中的最底角也是如此。这是一个缩放问题..

编辑3

这真的是非常非常愚蠢的事情。我正在为 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;

没有意识到viewportpixelheightandviewportpixelwidth是整数,所以我正在做整数除法,结果要么为 1,要么(交换它们时)为 0。

4

2 回答 2

1

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

我很抱歉造成混乱。我试图做的是区分捕获和显示图像。您是正确的,可以从焦距计算物理相机的纵横比。这些焦距和纵横比由相机的硬件固定。一旦您捕获了该图像,尽管您可以自由地以您使用 OpenGL 选择的任何纵横比显示它。您可以随意裁剪和拉伸图像,以更改显示内容的纵横比。相机的纵横比与屏幕的纵横比不匹配。OpenCV 使用来自物理相机的直接原始测量值来计算相机校准矩阵。如果我们假设它们是正确且恒定的(如果没有缩放,这两者似乎都是合理的),那么对纵横比的任何进一步更改都是 OpenGL 的责任。当我说 fx 和 fy 不确定纵横比时,我指的是显示的纵横比,这根本不是很清楚,对不起。

另外,我应该提到,您可以从焦距计算纵横比的原因是焦距以像素为单位表示,并且这些单位在 x 轴和 y 轴上可能不同。可以在这里找到一个简短的解释

我在相机矩阵中找到的焦距的最佳解释是在计算机视觉算法和应用的相机内在函数部分。在 pdf 中,它从本书的第 72 页、第 50 页开始。

于 2012-11-02T14:58:47.180 回答
1

1.0 的纵横比并不表示正方形图像,它表示正方形像素(这解释了为什么它几乎总是 1.0;非正方形像素相对罕见,除非在以变形格式拍摄的相机中)。相机矩阵不包含有关绝对图像尺寸物理相机尺寸的信息。

另一方面,gluPerspective 的纵横比确实代表图像尺寸。重要的是不要将一个纵横比与另一个混淆。

如果您想使用 gluPerspective,这是可能的,但您应该了解 gluPerspective 不会让您对所有固有的相机参数(即轴偏斜和主点偏移)进行建模。我将在本文中描述如何正确设置纵横比和 fovy 。

但是,我强烈建议使用 gluFrustum(允许非零主点偏移)或直接使用 glLoadMatrix(也允许非零轴倾斜)。本文解释了这两种方法。

于 2013-06-28T19:19:38.533 回答