有没有一种方法可以使用立体相机计算到特定对象的距离?有没有一个方程或什么东西可以用视差或角度来获得距离?
注意:这里描述的一切都可以在Learning OpenCV一书中的相机校准和立体视觉章节中找到。你应该阅读这些章节来更好地理解下面的步骤。
一种不需要您自己测量所有相机内部和外部的方法是使用openCV校准功能。相机内部(镜头失真/偏斜等)可以用cv::calibrateCamera计算,而外部(左右相机之间的关系)可以用cv::stereoCalibrate计算。这些函数获取像素坐标中的多个点,并尝试将它们映射到真实世界的对象坐标。CV有一种很好的方法来获得这些点,打印出一个黑白棋盘,并使用CV::findChesboardCorners/CV::cornerSubPix函数来提取它们。大约10-15个图像对的棋盘就可以了。
校准函数计算的矩阵可以保存到光盘中,这样您就不必每次启动应用程序时都重复这个过程。这里有一些简洁的矩阵,可以创建一个校正图(cv::stereoRectify/cv::initUnstortRectifyMap),稍后可以使用cv::remap将其应用于图像。你还得到了一个称为Q的整洁矩阵,这是一个视差到深度的矩阵。
校正图像的原因是,一旦一对图像的过程完成(假设校准正确),一张图像中的每个像素/对象都可以在另一张图像的同一行上找到。
根据你在图像中寻找的功能类型,你可以从这里选择几种方法。一种方法是使用CV立体对应函数,例如立体块匹配或半全局块匹配。这将为您提供整个图像的视差图,可以使用Q矩阵(cv::reprojectImageTo3D)将其转换为3D点。
这种情况的缺点是,除非图像中有很多纹理信息,否则CV并不擅长构建密集的视差图(在它找不到给定像素的正确视差的地方,你会发现其中的间隙),所以另一种方法是找到你想要匹配的点。假设您在x=40、y=110的左图像和x=22的右图像中找到特征/对象(由于图像经过校正,因此它们应该具有相同的y值)。视差计算为d=40-22=18。
构造一个cv::Point3f(x,y,d),在我们的例子中(40110,18)。以同样的方式找到其他感兴趣的点,然后将所有点发送到cv::perspectiveTransform(以Q矩阵作为变换矩阵,本质上这个函数是cv::reprojectImageTo3D,但对于稀疏视差图),输出将是XYZ坐标系中的点,左相机位于中心。
我仍在研究它,所以我还不会发布整个源代码。但我会给你一个概念性的解决方案。
您将需要以下数据作为输入(对于两台相机):
- 摄像机位置
- 摄像机关注点(摄像机正在观察的点)
- 相机分辨率(水平和垂直)
- 摄像机视场角(水平和垂直)
你可以自己测量最后一个,方法是把相机放在一张纸上,画两条线,并测量这两条线之间的角度。
相机不必以任何方式对齐,您只需要能够在两个相机中看到您的对象。
现在计算从每个摄影机到对象的矢量。每个摄影机都有对象的(X,Y)像素坐标,需要计算向量(X,Y,Z)。请注意,在简单的情况下,当物体位于相机的正中间时,解决方案只是(camera.PointOfInterest-camera.Position)
一旦两个矢量都指向目标,这些矢量定义的直线就应该在理想世界中的一个点上相交。在现实世界中,由于测量误差小和相机分辨率有限,他们不会这样做。因此,使用下面的链接来计算两条直线之间的距离向量。
两条线之间的距离
在这个链接中:P0是你的第一个凸轮位置,Q0是你的第二个凸轮位置。u和v是从相机位置开始指向目标的矢量。
你对实际距离不感兴趣,他们想计算。您需要向量Wc-我们可以假设对象位于Wc的中间。一旦你确定了物体在三维空间中的位置,你也可以获得你喜欢的任何距离。
我将很快发布整个源代码。
我有检测人脸的源代码,不仅返回深度,还返回真实世界坐标,左摄像头(或右摄像头,我记不清了)是原点。它改编自"Learning OpenCV"的源代码,并参考了一些网站以使其发挥作用。结果通常是相当准确的。