16

有没有办法使用立体相机计算到特定物体的距离?是否有使用视差或角度来获得距离的方程式或其他东西?

4

3 回答 3

37

注意:这里描述的所有内容都可以在 Learning OpenCV 书中关于相机校准和立体视觉的章节中找到。您应该阅读这些章节以更好地理解以下步骤。

一种不需要您自己测量所有相机内在和外在的方法是使用 openCVs 校准函数。相机内在函数(镜头畸变/歪斜等)可以用 cv::calibrateCamera 计算,而外在参数(左右相机之间的关系)可以用 cv::stereoCalibrate 计算。这些函数采用像素坐标中的一些点,并尝试将它们映射到真实世界的对象坐标。CV 有一种巧妙的方法来获取这些点,打印出黑白棋盘并使用 cv::findChessboardCorners/cv::cornerSubPix 函数来提取它们。应该有大约 10-15 个图像对的棋盘。

校准函数计算的矩阵可以保存到光盘中,这样您就不必在每次启动应用程序时都重复此过程。您可以在这里获得一些简洁的矩阵,允许您创建一个校正图 (cv::stereoRectify/cv::initUndistortRectifyMap),以后可以使用 cv::remap 将其应用于您的图像。您还会得到一个称为 Q 的简洁矩阵,它是一个视差到深度矩阵。

校正图像的原因是,一旦完成一对图像的过程(假设您的校准正确),一个图像中的每个像素/对象都可以在另一个图像的同一行中找到。

您可以从这里开始使用几种方法,具体取决于您在图像中寻找的功能类型。一种方法是使用 CV 的立体对应函数,例如 Stereo Block Matching 或 Semi Global Block Matching。这将为您提供整个图像的视差图,可以使用 Q 矩阵 (cv::reprojectImageTo3D) 将其转换为 3D 点。

这样做的缺点是,除非图像中有很多纹理信息,否则 CV 在构建密集视差图方面并不是非常擅长(您会在其中出现无法找到给定像素的正确视差的间隙) ,所以另一种方法是找到自己想要匹配的点。假设您在左侧图像中的 x=40,y=110 和右侧图像中找到 x=22 中的特征/对象(由于图像经过校正,它们应该具有相同的 y 值)。视差计算为 d = 40 - 22 = 18。

构造一个 cv::Point3f(x,y,d),在我们的例子中是 (40,110,18)。以相同的方式找到其他有趣的点,然后将所有点发送到 cv::perspectiveTransform(以 Q 矩阵作为变换矩阵,本质上这个函数是 cv::reprojectImageTo3D 但对于稀疏视差图),输出将是点以左相机为中心的 XYZ 坐标系。

于 2011-06-06T01:28:18.213 回答
6

我仍在努力,所以我不会发布完整的源代码。但我会给你一个概念性的解决方案。

您将需要以下数据作为输入(对于两个相机):

  • 相机位置
  • 相机兴趣点(相机正在看的点)
  • 相机分辨率(水平和垂直)
  • 摄像机视场角(水平和垂直)

您可以自己测量最后一个,方法是将相机放在一张纸上并画两条线并测量这些线之间的角度。

相机不必以任何方式对齐,您只需要能够在两个相机中看到您的对象。

现在计算从每个相机到您的对象的向量。您有来自每个相机的对象的 (X,Y) 像素坐标,并且您需要计算一个向量 (X,Y,Z)。请注意,在简单的情况下,对象正好位于相机的中间,解决方案就是(camera.PointOfInterest - camera.Position)。

一旦两个向量都指向目标,由这些向量定义的线应该在理想世界中的一个点相交。在现实世界中,他们不会因为小的测量误差和相机的分辨率有限。所以使用下面的链接来计算两条线之间的距离向量。

两条线之间的距离

在该链接中:P0 是您的第一个凸轮位置,Q0 是您的第二个凸轮位置,u 和 v 是从相机位置开始并指向目标的向量。

您对实际距离不感兴趣,他们想计算。您需要向量 Wc - 我们可以假设对象位于 Wc 的中间。一旦你有了你的对象在 3D 空间中的位置,你也可以得到你喜欢的任何距离。

我将很快发布整个源代码。

于 2011-06-05T08:21:54.787 回答
2

我有用于检测人脸的源代码,它不仅返回深度,还返回以左相机(或右相机,我不记得)为原点的真实世界坐标。它改编自“Learning OpenCV”的源代码,并参考一些网站以使其正常工作。结果通常是相当准确的。

于 2011-06-13T07:20:54.310 回答