我使用OpenCV计算了相机的内参和外参。现在,我想从屏幕坐标(u,v)计算世界坐标(x,y,z)。
请问如何实现呢?
注意:由于我使用Kinect,已知z坐标。
非常感谢您的帮助!谢谢!
我使用OpenCV计算了相机的内参和外参。现在,我想从屏幕坐标(u,v)计算世界坐标(x,y,z)。
请问如何实现呢?
注意:由于我使用Kinect,已知z坐标。
非常感谢您的帮助!谢谢!
我先解释一下如何计算,如果你读一些有关针孔相机模型和简单透视投影的东西,会对你有所帮助。想要快速了解,请查看这里。我将尝试提供更多信息。
因此,让我们从相反的角度开始描述相机的工作原理:将世界坐标系中的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 |
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(为什么上述内容对应世界坐标以及我们在校准过程中得到的外参是什么):
首先,请查看这篇文章,它很好地解释了各种坐标系统。
您的三维坐标系为:物体 ---> 世界 ---> 相机。有一个转换将您从物体坐标系转换到世界坐标系,另一个转换将您从世界坐标系转换到相机坐标系(您所说的外参)。通常情况下,您假设:
1. 在使用Kinect捕捉物体时
当你使用Kinect来捕捉一个物体时,传感器返回给你的是距离相机的距离。这意味着z坐标已经在相机坐标系中了。通过使用上面的方程式转换x和y,你可以得到相机坐标系中的点。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
,noOfCornersInHeight
和squareSize
取决于您的标定板。例如,如果noOfCornersInWidth
= 4,noOfCornersInHeight
= 3和squareSize
= 100,则我们可以得到三维点
(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)
编辑2(使用的坐标系):
这是一种惯例,我认为它也取决于你使用哪些驱动程序以及获取的数据类型。例如,检查那个, 那个 和 那个。编辑2(关于使用的坐标系):
这是一种约定俗成的方式,我认为它还取决于您使用的驱动程序和获取的数据类型。例如,请查看那个、那个和那个。
例如,如果您使用微软SDK:那么Z不是到相机的距离,而是到相机的“平面”距离。这可能会改变适当的公式。