9

我已经用 OpenCV 计算了相机的内在和外在参数。现在,我想根据屏幕坐标 (u,v) 计算世界坐标 (x,y,z)。

我该怎么做?

注意,当我使用 kinect 时,我已经知道 z 坐标。

任何帮助深表感谢。谢谢!

4

2 回答 2

30

首先要了解如何计算它,如果您阅读一些有关针孔相机模型和简单透视投影的内容,它将对您有所帮助。如需快速浏览,请查看。我会尝试更新更多。

因此,让我们从描述相机工作原理的相反开始:将世界坐标系中的 3d 点投影到图像中的 2d 点。根据相机型号:

P_screen = I * P_world

或(使用齐次坐标)

| x_screen | = I * | x_world |
| y_screen |       | y_world |
|    1     |       | z_world |
                   |    1    |

在哪里

I = | f_x    0    c_x    0 | 
    |  0    f_y   c_y    0 |
    |  0     0     1     0 |

是 3x4 内在矩阵,f 是焦点,c 是投影中心。

如果你解决了上面的系统,你会得到:

x_screen = (x_world/z_world)*f_x + c_x
y_screen = (y_world/z_world)*f_y + c_y

但是,你想做相反的事情,所以你的答案是:

x_world = (x_screen - c_x) * z_world / f_x
y_world = (y_screen - c_y) * z_world / f_y

z_world 是 Kinect 返回给您的深度,您从内在校准中知道 f 和 c,因此对于每个像素,您应用上述内容来获取实际的世界坐标。

编辑1(为什么上面对应于世界坐标以及我们在校准过程中得到的外在因素是什么):

首先,检查这个,它很好地解释了各种坐标系。

您的 3d 坐标系是:对象 ---> 世界 ---> 相机。有一个转换将您从对象坐标系带到世界,另一个将您从世界带到相机(您所指的外在因素)。通常你会假设:

  • 要么 Object 系统对应 World 系统,
  • 或者,Camera 系统对应 World 系统

1. 用 Kinect 捕捉物体时

当你使用 Kinect 捕捉物体时,传感器返回给你的是与摄像头的距离。这意味着 z 坐标已经在相机坐标中。通过使用上面的等式转换 x 和 y,您可以得到相机坐标中的点。

现在,世界坐标系由您定义。一种常见的方法是假设相机位于世界坐标系的 (0,0,0) 处。因此,在这种情况下,外部矩阵实际上对应于单位矩阵,而您找到的相机坐标对应于世界坐标

旁注:因为 Kinect 返回的是相机坐标中的 z,所以也不需要从物体坐标系转换到世界坐标系。例如,假设您有一个不同的相机来捕捉人脸,并且对于每个点,它都会返回与鼻子的距离(您认为它是对象坐标系的中心)。在这种情况下,由于返回的值将在对象坐标系中,我们确实需要一个旋转和平移矩阵来将它们带到相机坐标系中。

2. 校准相机时

我想您正在使用具有各种姿势的校准板使用 OpenCV 校准相机。通常的方法是假设棋盘实际上是稳定的,并且相机正在移动而不是相反(两种情况下的变换是相同的)。这意味着现在世界坐标系对应于对象坐标系。这样,对于每一帧,我们找到棋盘角并为其分配 3d 坐标,执行如下操作:

std::vector<cv::Point3f> objectCorners;

for (int i=0; i<noOfCornersInHeight; i++) 
{
    for (int j=0; j<noOfCornersInWidth; j++) 
    {
        objectCorners.push_back(cv::Point3f(float(i*squareSize),float(j*squareSize), 0.0f));
    }
} 

在哪里noOfCornersInWidth,取决于你的校准板noOfCornersInHeightsquareSize例如,如果 noOfCornersInWidth = 4、noOfCornersInHeight = 3 和 squareSize = 100,我们得到 3d 点

(0  ,0,0)  (0  ,100,0)  (0  ,200,0)    (0  ,300,0)
(100,0,0)  (100,100,0)  (100,200,0)    (100,300,0)
(200,0,0)  (200,100,0)  (200,200,0)    (200,300,0)

所以,这里我们的坐标实际上是在对象坐标系中。(我们任意假设棋盘的左上角为(0,0,0),其余角的坐标均以此为准)。所以这里我们确实需要旋转和变换矩阵来把我们从物体(世界)带到相机系统。这些是 OpenCV 为每一帧返回的外在参数。

总结一下Kinect案例:

  • 相机和世界坐标系统被认为是相同的,因此不需要外在。
  • 不需要对象到世界(相机)的转换,因为 Kinect 返回值已经在相机系统中。

编辑 2(在使用的坐标系上):

这是一个约定,我认为它还取决于您使用的驱动程序以及您返回的数据类型。例如,检查那个那个那个

旁注:如果您将点云可视化并对其进行一些操作,将会对您有很大帮助。您可以将您的点保存为 3d 对象格式(例如plyobj),然后只需将其导入Meshlab之类的程序(非常易于使用)。

于 2012-08-17T18:56:13.667 回答
0

编辑 2(在使用的坐标系上):

这是一个约定,我认为它还取决于您使用的驱动程序以及您返回的数据类型。例如,检查那个,那个和那个。

例如,如果您使用 microsoft sdk: 那么 Z 不是到相机的距离,而是到相机的“平面”距离。这可能会更改适当的公式。

于 2013-02-18T16:08:37.477 回答