我试图在世界空间中找到相机的焦距、位置和方向。
因为我需要它与分辨率无关,所以我将我的图像坐标标准化为 [-1, 1]
的 x
范围,以及 y
的较小范围(取决于纵横比)。所以 (0, 0)
是图像的中心。我已经校正了镜头失真(使用 k1
和 k2
系数),所以这不会进入图片,除非有时将 x
或 y
稍微超出 [-1, 1]
范围。
作为给定,我在已知尺寸(以毫米为单位)的世界空间中有一个平面固定矩形。矩形的四个角保证可见,并在图像中手动标记。例如:
std::vector<cv::Point3f> worldPoints = {
cv::Point3f(0, 0, 0),
cv::Point3f(2000, 0, 0),
cv::Point3f(0, 3000, 0),
cv::Point3f(2000, 3000, 0),
};
std::vector<cv::Point2f> imagePoints = {
cv::Point2f(-0.958707, -0.219624),
cv::Point2f(-1.22234, 0.577061),
cv::Point2f(0.0837469, -0.1783),
cv::Point2f(0.205473, 0.428184),
};
实际上,我想我要解决的方程是(参见 equivalent in the OpenCV documentation ):
/ xi \ / fx 0 \ / tx \ / Xi \
s | yi | = | fy 0 | | Rxyz ty | | Yi |
\ 1 / \ 1 / \ tz / | Zi |
\ 1 /
在哪里:
i
是 1, 2, 3, 4
xi, yi
是图像中点 i
的位置(-1 和 1 之间) fx, fy
是相机在 x 和 y 方向的焦距 Rxyz
是相机的 3x3 旋转矩阵(只有 3 个自由度) tx, ty, tz
是相机 Xi, Yi, Zi
是点 i
在世界空间中的位置(毫米) 所以我有 8 个方程(每个方程 4 个点,2 个坐标),我有 8 个未知数(
fx, fy
、 Rxyz
、 tx, ty, tz
)。因此,我得出结论(除了病理情况)必须存在一个独特的解决方案。但是,我似乎无法弄清楚如何使用 OpenCV 计算此解决方案。
我看过 imgproc 模块:
getPerspectiveTransform
工作,但只给我一个 3x3 矩阵(从 2D 点到 2D 点)。如果我能以某种方式从这个矩阵中提取所需的参数,那就太好了。 我还查看了 calib3d 模块,其中包含一些很有前途的函数,它们几乎但不完全是我需要的:
initCameraMatrix2D
听起来几乎完美,但是当我通过它时,我的四点是这样的:cv::Mat cameraMatrix = cv::initCameraMatrix2D(
std::vector<std::vector<cv::Point3f>>({worldPoints}),
std::vector<std::vector<cv::Point2f>>({imagePoints}),
cv::Size2f(2, 2), -1);
它返回一个相机矩阵,其中
fx, fy
设置为 -inf, inf
。 calibrateCamera
似乎使用复杂的求解器来处理超定系统和异常值。无论如何我都试过了,但我能从中得到的是像这样的断言失败:OpenCV(3.4.1) Error: Assertion failed (0 <= i && i < (int)vv.size()) in getMat_, file /build/opencv/src/opencv-3.4.1/modules/core/src/matrix_wrap.cpp, line 79
有没有办法吸引 OpenCV 做我需要的事情?如果没有,我怎么能手工做呢?
最佳答案
3x3 旋转矩阵有 9 个元素,但正如您所说,只有 3 个自由度。一个微妙之处在于,利用 的这一特性会使方程在您想要估计的角度中非线性 ,并且非线性方程比线性方程更难求解。
这类方程通常用以下方法求解:
但是,您的情况有点特殊,因为 您没有足够的点匹配来可靠地解决线性公式 (即步骤 1)。这意味着,正如您所说,您无法初始化迭代优化算法来获得问题的准确解决方案。
以下是一些您可以尝试的变通方法:
cv::getPerspectiveTransform
估计的整流单应性中提取近似值。 关于最后一个要点,显然可能与您想要的相反。事实上,知道你想估计的参数,整流单应性可以通过分析来表达。参见例如 this post 和 this post 。 Hartley & Zisserman 的书(第 13 章)中也有关于此的完整章节。
在您的情况下,您想反过来,即从单应性中提取内在和外在参数。 OpenCV 中有一个相关的函数( cv::decomposeHomographyMat ),但它假设 K 矩阵是已知的,并输出 4 个候选解。
在一般情况下,这会很棘手。但也许在您的情况下,您可以猜测焦距的合理估计值,因此对于 K,并使用点对应关系为您的问题选择好的解决方案。您还可以实现自定义优化算法,测试许多焦距值并保持解决方案导致最低的重投影误差。
关于c++ - 给定四个点如何校准相机焦距,平移和旋转?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/50640832/