什么是Project Tango镜头失真模型?

时间:2015-04-26 22:24:04

标签: opencv google-project-tango

Project Tango C API documentation表示TANGO_CALIBRATION_POLYNOMIAL_3_PARAMETERS镜头失真被建模为:

  

x_corr_px = x_px(1 + k1 * r2 + k2 * r4 + k3 * r6)y_corr_px = y_px(1   + k1 * r2 + k2 * r4 + k3 * r6)

也就是说,未失真的坐标是失真坐标的幂级数函数。 Java API中还有另一个定义,但该描述的详细程度不足以说明函数映射的方向。

我在正确注册时遇到了很多麻烦,我怀疑映射实际上可能是相反的方向,即失真的坐标是未失真的坐标。如果摄像机校准是使用OpenCV生成的,那么问题的原因可能是OpenCV文档与自身相矛盾。查找和理解的最简单描述是OpenCV camera calibration tutorial,它与Project Tango文档一致:

  

enter image description here

但另一方面,OpenCV API documentation指定映射的另一种方式:

  

enter image description here

我使用OpenCV进行的实验表明,其API文档显示正确且教程错误。正k1(所有其他失真参数设置为零)表示枕形失真,负k1表示桶形失真。这与Wikipedia says about the Brown-Conrady model相匹配,与Tsai model相反。请注意,失真可以是modeled either way,具体取决于使数学更方便的原因。我针对这种不匹配对OpenCV开了一个bug

所以我的问题是:Project Tango镜头失真模型是否与OpenCV中实现的相同(尽管文档)?

这是我从彩色相机拍摄的图像(可以看到轻微的枕形):

enter image description here

以下是Tango服务部门报告的相机校准:

distortion = {double[5]@3402}
[0] = 0.23019999265670776
[1] = -0.6723999977111816
[2] = 0.6520439982414246
[3] = 0.0
[4] = 0.0
calibrationType = 3
cx = 638.603
cy = 354.906
fx = 1043.08
fy = 1043.1
cameraId = 0
height = 720
width = 1280

以下是如何在python中使用OpenCV解压缩:

>>> import cv2
>>> src = cv2.imread('tango00042.png')
>>> d = numpy.array([0.2302, -0.6724, 0, 0, 0.652044])
>>> m = numpy.array([[1043.08, 0, 638.603], [0, 1043.1, 354.906], [0, 0, 1]])
>>> h,w = src.shape[:2]
>>> mDst, roi = cv2.getOptimalNewCameraMatrix(m, d, (w,h), 1, (w,h))
>>> dst = cv2.undistort(src, m, d, None, mDst)
>>> cv2.imwrite('foo.png', dst)

这产生了这个,这可能在顶部边缘有点过度修正,但比我对反向模型的尝试要好得多:

enter image description here

1 个答案:

答案 0 :(得分:0)

也许它不适合发布,但我真的想分享OpenCV中使用的可读代码版本,以实际纠正失真。

我确信我不是唯一一个需要x_correctedy_corrected且未能找到一个简单易懂的公式的人。

我在Python中重写了cv2.undistortPoints的基本部分,您可能会注意到纠正是迭代执行的。这很重要,因为9次幂的多项式解不存在,我们所能做的就是多次应用它的尊重版本来得到数值解。

def myUndistortPoint((x0, y0), CM, DC):
    [[k1, k2, p1, p2, k3, k4, k5, k6]] = DC
    fx, _, cx = CM[0]
    _, fy, cy = CM[1]

    x = x_src = (x0 - cx) / fx
    y = y_src = (y0 - cy) / fy

    for _ in range(5):
        r2 = x**2 + y**2
        r4 = r2**2
        r6 = r2 * r4

        rad_dist = (1 + k4*r2 + k5*r4 + k6*r6) / (1 + k1*r2 + k2*r4 + k3*r6)
        tang_dist_x = 2*p1 * x*y + p2*(r2 + 2*x**2)
        tang_dist_y = 2*p2 * x*y + p1*(r2 + 2*y**2)

        x = (x_src - tang_dist_x) * rad_dist
        y = (y_src - tang_dist_y) * rad_dist

    x = x * fx + cx
    y = y * fy + cy

    return x, y

为了加快速度,您只能使用三次迭代,在大多数相机上,这将提供足够的精度来适应像素。