我正在与OpenCV 3.0.0.dev中使用的鱼眼相机模型搏斗。我已多次阅读此链接中的文档 ,尤其是“详细说明”部分和鱼眼失真建模公式。到目前为止,我有两个担忧:
基于此处列出的投影模型及其在Hughes的“鱼眼镜头模型的准确性”中的概念解释,我无法弄清楚OpenCV 实现中使用了哪种投影模型。
由于描述如此简洁,我需要了解OpenCV 开发人员用于实现鱼眼命名空间的主要参考论文,以便我能够掌握并了解更多细节。PS 我检查了 OpenCV 3.0.0-dev 文档并没有发现任何有用的东西。
OpenCV 3.0.0 Fisheye 相机模型不使用 Brown 模型或 OP 从 Panotools 引用的任何模型,它使用 Juho Kannala 和 Sami S. Brandt 的通用相机模型。
正如Cfr在他的回答中指出的那样,来自 Ilya Krylov(他在 OpenCV 中实现了鱼眼模型)的评论说,他们为 Jean-Yves Bouguet 的 Matlab 移植了相机校准工具箱:
Jean-Yves Bouguet 网站(链接)反过来提到了论文A Generic Camera Model and Calibration Method for Conventional, Wide-Angle, and Fish-Eye Lenses,并说:
校准工具箱中包含的“未记录的”鱼眼模型遵循这篇非常好的论文中等式(3)描述的等距离投影模型。失真模型遵循等式(6),除了 k1=1(否则与 f 无法区分)。
在我看来,这是一种误导性陈述或明显的误解,因为等式(3)和等式(6)对应于不同的模型:等式(6)是本文中介绍的实际模型,作者将其称为通用相机模型(因此论文名称)。更准确地说,等式 (6) 旨在用作相机模型,而等式 (8) 和 (9) 则用作该模型的“失真”或偏差。
但奥德赛还没有结束。OpenCV 的实现(根据其文档)首先计算针孔投影以找到视场角(3D 点、投影中心和光轴之间的角度)。这意味着您不能使用他们的鱼眼模型以 90º(或者您将除以 0)或接近 90º(数值稳定性问题,例如如果 z 足够小可能会发生溢出)投射光线。此外,我不确定它是否适用于超过 90º 的光线。这一切让我真的很想知道他们的鱼眼镜头模型对于鱼眼镜头或广角镜头的“有用性”。
如果您对此持怀疑态度,可以查看 OpenCV 的源代码,具体位于sources\modules\calib3d\src\fisheye.cpp(我添加了一些评论)
void cv::fisheye::projectPoints(InputArray objectPoints, OutputArray imagePoints, InputArray _rvec,
InputArray _tvec, InputArray _K, InputArray _D, double alpha, OutputArray jacobian)
{
...
Rodrigues(om, R, dRdom);
Affine3d aff(om, T);
...
Vec3d Xi = objectPoints.depth() == CV_32F ? (Vec3d)Xf[i] : Xd[i];
Vec3d Y = aff*Xi; /* To transform to camera reference frame*/
Vec2d x(Y[0]/Y[2], Y[1]/Y[2]); /* <- The root of all evil (division by z) */
double r2 = x.dot(x);
double r = std::sqrt(r2);
// Angle of the incoming ray:
double theta = atan(r);
double theta2 = theta*theta, theta3 = theta2*theta, theta4 = theta2*theta2, theta5 = theta4*theta,
theta6 = theta3*theta3, theta7 = theta6*theta, theta8 = theta4*theta4, theta9 = theta8*theta;
double theta_d = theta + k[0]*theta3 + k[1]*theta5 + k[2]*theta7 + k[3]*theta9;
double inv_r = r > 1e-8 ? 1.0/r : 1;
double cdist = r > 1e-8 ? theta_d * inv_r : 1;
Vec2d xd1 = x * cdist;
Vec2d xd3(xd1[0] + alpha*xd1[1], xd1[1]);
Vec2d final_point(xd3[0] * f[0] + c[0], xd3[1] * f[1] + c[1]);
...
}
更新:此拉取请求修复了角度 ≥ 90º 的光线问题。截至 2018 年 4 月,它尚未合并到 master 中,但正在考虑用于 OpenCV 4.x Calibration Module(也检查校准模块讨论)
经过数小时的阅读,我发现 OpenCV 鱼眼文档中的公式 θ=atan(r) 是与针孔投影有关的 r=f*tanθ 的归一化倒数,因此,没有提到任何鱼眼投影模型以上链接在 OpenCV 中使用。
另外,关于畸变模型,我猜测是使用了 Fitzgibbon 在他 2001 年的论文《多视角几何和镜头畸变的同时线性估计》中的 Division Model。根据 Hughes 在他 2008 年的论文“鱼眼相机中几何失真补偿的回顾”中,其他替代方案包括“奇数多项式模型”和“多项式鱼眼变换”。在他的论文第 2 页,他写道:
” (1)(指奇数多项式模型)和(3)(指除法模型,我猜这是 OpenCV 使用的模型)可用于描述标准非鱼眼镜头中的失真。但是,它一般认为这些多项式模型不足以描述鱼眼镜头引入的失真水平。Shah 和 Aggarwal 在 [9] (Intrinsic Parameter Calibration Procedure For A High-Distortion Fish-Eye Lens Camera With Distortion Model And准确度估计),即使使用(1)的7阶版本来模拟鱼眼径向失真,仍然存在相当大的失真,以至于他们不得不使用具有更大自由度的模型。因此,可以使用同时使用奇数和偶数系数(而不是简单地使用一个或另一个)的多项式来模拟鱼眼镜头引入的径向失真"
毕竟,我的结论是 OpenCV 中的鱼眼模型的适用性非常有限,在失真模型和投影模型方面可以得到更多的加强。我想再次强调,我仍然需要知道 OpenCV 开发人员使用了哪些论文来实现鱼眼命名空间。
我非常感谢任何人对此的评论。
根据 Bouguet 的 calib_tool 代码“project_points_fisheye.m”
%Definitions:
%Let P be a point in 3D of coordinates X in the world reference frame (stored in the matrix X)
%The coordinate vector of P in the camera reference frame is: Xc = R*X + T
%where R is the rotation matrix corresponding to the rotation vector om: R = rodrigues(om);
%call x, y and z the 3 coordinates of Xc: x = Xc(1); y = Xc(2); z = Xc(3);
%The pinehole projection coordinates of P is [a;b] where a=x/z and b=y/z.
%call r^2 = a^2 + b^2,
%call theta = atan(r),
%Fisheye distortion -> theta_d = theta * (1 + k(1)*theta^2 + k(2)*theta^4 + k(3)*theta^6 + k(4)*theta^8)
%
%The distorted point coordinates are: xd = [xx;yy] where:
%
%xx = (theta_d / r) * x
%yy = (theta_d / r) * y
%
%Finally, convertion into pixel coordinates: The final pixel coordinates vector xp=[xxp;yyp] where:
%
%xxp = f(1)*(xx + alpha*yy) + c(1)
%yyp = f(2)*yy + c(2)
它是Brown-Conrady 模型,在用于 Matlab 参考的 Camera Calibration Toolbox 中提到。本文讨论:DC Brown“近距离相机校准”。
此外,当前的 OpenCV 模型似乎忽略了切向失真(P(r)
)。
看到这个评论。