首页 > 解决方案 > 我们如何使用 swift 和 iOS 11+ 进行直线图像转换

问题描述

我们如何使用苹果提供的函数(下)进行直线转换?

Apple 在“AVCameraCalibrationData.h”中提供了关于如何校正镜头失真图像的参考实现。即从用广角或远摄镜头拍摄的图像到直线的“真实世界”图像。一个图形表示在这里:

在此处输入图像描述

要创建一个直线图像,我们必须从一个空的目标缓冲区开始并逐行遍历它,为输出图像中的每个点调用下面的示例实现,传递 lensDistortionLookupTable 以在失真图像中找到相应的值,并将其写入到您的输出缓冲区。

func lensDistortionPoint(for point: CGPoint, lookupTable: Data, distortionOpticalCenter opticalCenter: CGPoint, imageSize: CGSize) -> CGPoint {
    // The lookup table holds the relative radial magnification for n linearly spaced radii.
    // The first position corresponds to radius = 0
    // The last position corresponds to the largest radius found in the image.

    // Determine the maximum radius.
    let delta_ocx_max = Float(max(opticalCenter.x, imageSize.width  - opticalCenter.x))
    let delta_ocy_max = Float(max(opticalCenter.y, imageSize.height - opticalCenter.y))
    let r_max = sqrt(delta_ocx_max * delta_ocx_max + delta_ocy_max * delta_ocy_max)

    // Determine the vector from the optical center to the given point.
    let v_point_x = Float(point.x - opticalCenter.x)
    let v_point_y = Float(point.y - opticalCenter.y)

    // Determine the radius of the given point.
    let r_point = sqrt(v_point_x * v_point_x + v_point_y * v_point_y)

    // Look up the relative radial magnification to apply in the provided lookup table
    let magnification: Float = lookupTable.withUnsafeBytes { (lookupTableValues: UnsafePointer<Float>) in
        let lookupTableCount = lookupTable.count / MemoryLayout<Float>.size

        if r_point < r_max {
            // Linear interpolation
            let val   = r_point * Float(lookupTableCount - 1) / r_max
            let idx   = Int(val)
            let frac  = val - Float(idx)

            let mag_1 = lookupTableValues[idx]
            let mag_2 = lookupTableValues[idx + 1]

            return (1.0 - frac) * mag_1 + frac * mag_2
        } else {
            return lookupTableValues[lookupTableCount - 1]
        }
    }

    // Apply radial magnification
    let new_v_point_x = v_point_x + magnification * v_point_x
    let new_v_point_y = v_point_y + magnification * v_point_y

    // Construct output
    return CGPoint(x: opticalCenter.x + CGFloat(new_v_point_x), y: opticalCenter.y + CGFloat(new_v_point_y))
}

另外苹果声明:下面的“point”、“opticalCenter”和“imageSize”参数必须在同一个坐标系中。

考虑到这一点,我们传递什么价值观opticalCenterimageSize为什么?“应用径向放大”到底是做什么的?

标签: iosswiftiphonecomputer-visioncamera-calibration

解决方案


  1. opticalCenter实际distortionOpticalCenter名为. 所以你可以lensDistortionCenter从 AVCameraCalibrationData 提供。

  2. 图像大小是您想要直线的图像的高度和宽度。

  3. “应用径向放大”。它将给定点的坐标更改为理想镜头不失真的点。

  4. “我们如何使用该功能......”。我们应该创建一个与失真图像大小相同的空缓冲区。对于空缓冲区的每个像素,我们应该应用 lensDistortionPointForPoint 函数。并将具有校正坐标的像素从失真图像中取出到空缓冲区。填充所有缓冲区空间后,您应该得到一个不失真的图像。


推荐阅读