6

Project Tango C API 文档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 相机校准教程,它与 Project Tango 文档一致:

在此处输入图像描述

但另一方面,OpenCV API 文档指定映射采用另一种方式:

在此处输入图像描述

我对 OpenCV 的实验表明,它的 API 文档看起来是正确的,而教程是错误的。正数k1(所有其他失真参数设置为零)表示枕形失真,负数k1表示桶形失真。这与Wikipedia 关于 Brown-Conrady 模型的说法相吻合,并且与Tsai 模型相反。请注意,失真可以通过任何一种方式建模,具体取决于使数学更方便的方式。我针对这种不匹配打开了一个针对 OpenCV的错误。

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

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

在此处输入图像描述

以下是 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)

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

在此处输入图像描述

4

2 回答 2

6

Tango C-API Docs状态 (x_corr_px, y_corr_px)“更正的输出位置” 。然后,该校正后的输出位置需要按焦距缩放并按投影中心偏移,以对应于失真的像素坐标。

因此,要将点投影到图像上,您必须:

  1. 变换 3D 点,使其位于相机的框架中
  2. 将点转换为标准化的图像坐标 (x, y)
  3. 计算归一化图像坐标的 r2, r4, r6 ( r2 = x*x + y*y)
  4. (x_corr_px, y_corr_px)根据上述方程计算:

    x_corr_px = x (1 + k1 * r2 + k2 * r4 + k3 * r6)
    y_corr_px = y (1 + k1 * r2 + k2 * r4 + k3 * r6)
    
  5. 计算扭曲坐标

    x_dist_px = x_corr_px * fx + cx
    y_dist_px = y_corr_px * fy + cy
    
  6. (x_dist_px, y_dist_px)在原始的、扭曲的图像缓冲区上 绘制。

这也意味着校正后的坐标是由一化图像坐标的大小的幂级数缩放的归一化坐标。(这与问题所暗示的相反)

查看 OpenCV 中的实现cvProjectPoints2参见 [opencv]/modules/calib3d/src/calibation.cpp),OpenCV 中的“Poly3”失真与 Tango 中的应用方向相同。所有 3 个版本(Tango Docs、OpenCV 教程、OpenCV API)都是一致且正确的。

祝你好运,希望这会有所帮助!

(更新:仔细查看代码,看起来校正后的坐标和扭曲的坐标不一样。我已经删除了我的回复中不正确的部分,这个答案的其余部分仍然是正确的。)

于 2015-05-02T01:18:50.400 回答
0

也许这不是张贴的正确位置,但我真的很想分享 OpenCV 中使用的可读版本的代码来实际纠正失真。

我敢肯定,我不是唯一一个需要x_corrected并且y_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

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

于 2017-03-07T09:33:41.590 回答