了解openCV不失真

时间:2014-02-22 18:27:05

标签: matlab opencv camera-calibration

我通过tof camera收到了MATLAB的深度图片。用于计算深度图像中x,y,z坐标的tof相机的交付驱动程序正在使用openCV函数,该函数通过mex文件在MATLAB中实现。

但是后来我不能再使用这些驱动程序,也不能使用openCV函数,因此我需要自己实现2d到3d的映射,包括径向失真的补偿。我已经掌握了相机参数,并且深度图像的每个像素的x,y,z坐标的计算正在工作。到目前为止,我正在通过牛顿法解决非正畸的隐式方程(这不是很快......)。但我想实现openCV函数的不失真。

...我的问题是:我真的不明白它,我希望你能帮助我。它是如何实际工作的?我试图在论坛中搜索,但没有找到任何有关此案例的有用线索。

问候!

2 个答案:

答案 0 :(得分:8)

documentation page related to camera calibration上提供了3D点[X; Y; Z]投影到2D图像点[u; v]的方程式:

opencv projection equations http://docs.opencv.org/_images/math/dbe76ed3ef28b501c3933a74618c2c94889d38fa.png

在镜头失真的情况下,方程是非线性的并且取决于3到8个参数(k1到k6,p1和p2)。因此,通常需要非线性求解算法(例如Newton方法,Levenberg-Marquardt算法等)来反演这样的模型并估计来自失真的未失真坐标。这就是函数undistortPoints背后的用法,调整参数使得优化速度快但有点不准确。

然而,在图像镜头校正的特定情况下(与点校正相反),基于众所周知的图像重新采样技巧,存在更有效的方法。这个技巧是,为了获得目标图像的每个像素的有效强度,您必须将目标图像中的坐标转换为源图像中的坐标,而不是直观地期望的相反。在镜头失真校正的情况下,这意味着您实际上不必反转非线性模型,而只是应用它。

基本上,函数undistort背后的算法如下。对于目标镜头校正图像的每个像素,请执行以下操作:

  • 使用校准矩阵的倒数(u_dst, v_dst)将像素坐标(x', y')转换为标准化坐标K
  • 应用镜头扭曲模型,如上所示,以获得扭曲的标准化坐标(x'', y'')
  • 使用校准矩阵(x'', y'')(u_src, v_src)转换为失真像素坐标K
  • 使用您选择的插值方法查找与源图像中的像素坐标(u_src, v_src)关联的强度/深度,并将此强度/深度指定给当前目标像素。

请注意,如果您对深度图图像失真感兴趣,则应使用最近邻插值,否则几乎可以肯定在对象边界处插入深度值,从而产生不必要的伪像。

答案 1 :(得分:0)

以上答案是正确的,但请注意,UV坐标位于屏幕空间中,并且以(0,0)为中心,而不是“实际” UV坐标。

来源:使用Python / OpenGL自己重新实现。代码:

def correct_pt(uv, K, Kinv, ds):
   uv_3=np.stack((uv[:,0],uv[:,1],np.ones(uv.shape[0]),),axis=-1)
   xy_=uv_3@Kinv.T
   r=np.linalg.norm(xy_,axis=-1)
   coeff=(1+ds[0]*(r**2)+ds[1]*(r**4)+ds[4]*(r**6));
   xy__=xy_*coeff[:,np.newaxis]
   return (xy__@K.T)[:,0:2]