使用OpenCV从屏幕坐标计算世界坐标

时间:2012-08-17 14:32:54

标签: opencv kinect camera-calibration calibration

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

我是怎么做到的?

N.B。当我使用kinect时,我已经知道了z坐标。

非常感谢任何帮助。谢谢!

2 个答案:

答案 0 :(得分:25)

首先要了解你如何计算它,如果你读了一些关于针孔相机模型和简单透视投影的东西,它会对你有所帮助。如需快速了解,请查看this。我会尝试更新更新。

所以,让我们从描述相机如何工作的相反方向开始:将世界坐标系中的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(为什么以上对应于世界坐标以及我们在校准期间得到的外在因素):

首先,检查this one,它可以很好地解释各种坐标系统。

您的三维坐标系是:对象--->世界--->相机。有一个转换将你从对象坐标系带到世界,另一个带你从世界到相机(你引用的外在因素)。通常你会认为:

  • 对象系统与World系统对应,
  • 或者,Camera系统对应于World系统

<强> 1。使用Kinect

捕获对象时

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

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

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

<强> 2。校准相机时

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

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));
    }
} 

其中noOfCornersInWidthnoOfCornersInHeightsquareSize取决于您的校准板。如果例如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 案例:

  • Camera和World coodinate系统被认为是相同的,所以不需要那里的extrinsics。
  • 不需要对象世界(相机)转换,因为Kinect返回值已经在相机系统中。

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

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

旁注:如果您对点云进行可视化并对其进行了一些操作,那将对您有所帮助。您可以将点数保存为三维对象格式(例如plyobj),然后将其导入类似Meshlab的程序(非常易于使用)。

答案 1 :(得分:0)

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

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

  
    

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