How to build AVDepthData manually

953 views Asked by At

I want to build my own depth map and save image like portrait photo with depth info. So first of all I need generate AVDepthData. After dig how it builded, I try to reproduce it:

func buildDepth() {
    // ...
    let info: [AnyHashable: Any] = [kCGImagePropertyPixelFormat: kCVPixelFormatType_DisparityFloat32,
                                    kCGImagePropertyWidth: width,
                                    kCGImagePropertyHeight: height,
                                    kCGImagePropertyBytesPerRow: bytesPerRow]
    let metadata = generateMetadata(photo: photo)
    let dic: [AnyHashable: Any] = [kCGImageAuxiliaryDataInfoDataDescription: info,
                                   kCGImageAuxiliaryDataInfoData: data,
                                   kCGImageAuxiliaryDataInfoMetadata: metadata]
    guard let depthData = try? AVDepthData(fromDictionaryRepresentation: dic) else {
        return false
    }
    print(depthData.cameraCalibrationData) // <----- prints nil
}

private static func generateMetadata(photo: Photo) -> CGImageMetadata {
    let metadata = CGImageMetadataCreateMutable()

    let fxy = max(photo.orig.size.width, photo.orig.size.height)
    let cx = photo.orig.size.width/2
    let cy = photo.orig.size.height/2

    addMetadataTag(metadata, key: "Filtered", value: true)
    addMetadataTag(metadata, key: "Quality", value: "high")
    addMetadataTag(metadata, key: "Accuracy", value: "relative")
    addMetadataTag(metadata, key: "DepthDataVersion", value: 65538)
    addMetadataTag(metadata, key: "PixelSize", value: 0.001000)


    addMetadataTag(metadata, key: "LensDistortionCoefficients", value: [0,0,0,0,0,0,0,0])
    addMetadataTag(metadata, key: "InverseLensDistortionCoefficients", value: [0,0,0,0,0,0,0,0])


    addMetadataTag(metadata, key: "IntrinsicMatrixReferenceWidth", value: photo.orig.size.width)
    addMetadataTag(metadata, key: "IntrinsicMatrixReferenceHeight", value: photo.orig.size.height)
    addMetadataTag(metadata, key: "LensDistortionCenterOffsetX", value: cx)
    addMetadataTag(metadata, key: "LensDistortionCenterOffsetY", value: cy)
    addMetadataTag(metadata, key: "ExtrinsicMatrix", value: [1,0,0,
                                                                  0,1,0,
                                                                  0,0,1,
                                                                  0,0,0])

    addMetadataTag(metadata, key: "IntrinsicMatrix", value: [fxy,0,0,
                                                                  0,fxy,0,
                                                                  cx,cy,1])

    addMetadataTag(metadata, type: .depthBlur, key: "SimulatedAperture", value: 4.5)
    addMetadataTag(metadata, type: .depthBlur, key: "RenderingParameters", value: "UkVORAEAAAAwAAAAAgAAAJqZmT4K1yM8F0iSOTVeuj0zM7M/DdXOOwAAAD+amRk+")
    print(metadata)
    return metadata
}

enum MetadataType {
    case depth, depthBlur
}

@discardableResult private static func addMetadataTag(_ metadata: CGMutableImageMetadata, type: MetadataType = .depth, key: String, value: Any) -> Bool {
    let namespace: String
    let prefix: String
    switch type {
    case .depth:
        namespace = "http://ns.apple.com/depthData/1.0/"
        prefix = "depthData"
    case .depthBlur:
        namespace = "http://ns.apple.com/depthBlurEffect/1.0/"
        prefix = "depthBlurEffect"
    }
    guard let metadataTag = CGImageMetadataTagCreate(namespace as CFString, prefix as CFString, key as CFString, .default, value as CFTypeRef)
        else { return false }

    print("type", CGImageMetadataTagGetType(metadataTag).rawValue)
    return CGImageMetadataSetTagWithPath(metadata, nil, ("xmp:"+key) as CFString, metadataTag)
}

After this I get AVDepthData witch I can save into image. But this data not contains any additional info like cameraCalibrationData. Dictionary generated by system looks similar to my dictionary.

0

There are 0 answers