我在带有两个摄像头的多视图场景中使用 C++ 中的 open cv。我有两个相机的内在和外在参数。
我想将视图 1 中的 (X,Y) 点映射到第二个视图中的同一点。我有点不确定应该如何使用内在矩阵和外在矩阵,以便将点转换为 3D 世界,并最终得到视图 2 中的新 2D 点。
(通常)不可能在没有一些附加信息的情况下获取一张图像中的 2D 坐标并将其映射到另一个 2D 坐标。
主要问题是左图像中的单个点将映射到右图像中的一条线(极线)。因为深度是一个自由参数,所以有无限多个可能的对应位置。其次,完全有可能右图中的点不存在,即它被遮挡了。最后,可能很难准确确定哪个点是正确的对应关系,例如如果场景中没有纹理或者包含大量重复特征。
尽管基本矩阵(无论如何你都从
cv::StereoCalibrate
中得到)给了你每个相机中的点之间的约束:x'Fx = 0
,对于给定的 x'
将会有一个完整的 x
系列,它将满足方程。
一些可能的解决方案如下:
您知道一幅图像中 2D 点的 3D 位置。如果 3D 点位于公共坐标系中,您只需将
cv::projectPoints
与您想要投影到的其他相机的校准参数一起使用即可。您可以使用 SIFT 或 ORB 等进行一些稀疏特征检测和匹配。然后,您可以计算单应性以将点从一幅图像映射到另一幅图像。这对物体是飞机做出了一些假设。如果你谷歌全景单应性,有很多讲座幻灯片详细介绍了这一点。
您校准相机,执行极线校正(
cv::StereoRectify
、cv::initUndistortRectifyMap
、cv::remap
),然后通过立体匹配器运行它们。输出是一个视差图,它完全满足您的需求:从一个相机到另一个相机的每像素映射。也就是说,left[y,x] = right[y, x+disparity_map[y,x]]
。(1) 是迄今为止最简单的,但您不太可能已经掌握该信息。 (2) 通常是可行的并且可能是合适的,并且正如另一位评论者指出的那样,如果平面性假设失败,则效果会很差。 (3) 是一般(理想)解决方案,但有其自身的缺点,并且依赖于图像是否适合密集匹配。