Как мы делаем прямолинейное преобразование изображений с Swift и iOS 11+ - PullRequest
3 голосов
/ 04 мая 2019

Как мы используем функцию, предоставляемую яблоком (ниже), для выполнения прямолинейного преобразования?

Apple предоставляет справочную реализацию в 'AVCameraCalibrationData.h' о том, как исправить изображения для искажения объектива. Т.е. переход от изображений, снятых широкоугольным или телеобъективом, к прямолинейному изображению «реального мира». Иллюстрированное изображение здесь:

enter image description here

Чтобы создать прямолинейное изображение, мы должны начать с пустого целевого буфера и перебирать его построчно, вызывая приведенную ниже примерную реализацию для каждой точки в выходном изображении, передавая 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))
}

Кроме того, состояния Apple: параметры "point", "opticalCenter" и "imageSize" ниже должны находиться в одной системе координат.

Имея это в виду, какие значения мы передаем opticalCenter и imageSize и почему? Что именно делает «применение радиального увеличения»?

1 Ответ

3 голосов
/ 08 мая 2019
  1. opticalCenter фактически называется distortionOpticalCenter.Таким образом, вы можете предоставить lensDistortionCenter от AVCameraCalibrationData.

  2. Размер изображения - это высота и ширина изображения, которое требуется прямолинейно.

  3. «Применение радиального увеличения».Она изменяет координаты заданной точки до точки, в которой она будет находиться с идеальной линзой без искажений.

  4. «Как мы используем функцию ...».Мы должны создать пустой буфер того же размера, что и искаженное изображение.Для каждого пикселя пустого буфера мы должны применить функцию lensDistortionPointForPoint.И возьмите пиксель с исправленными координатами из искаженного изображения в пустой буфер.После заполнения всего буферного пространства вы должны получить неискаженное изображение.

...