You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从AVCapturePhoto对象将AVDepthData写入照片文件并正确读取?

解决iPhone LiDAR深度数据写入与读取问题

一、正确写入嵌入深度数据的关键步骤

1. 确保捕获会话启用深度数据交付

在配置AVCaptureSession时,必须开启深度数据交付,并设置合适的深度格式:

let session = AVCaptureSession()
session.beginConfiguration()

// 选择支持深度的后置相机(LiDAR/TrueDepth)
guard let cameraDevice = AVCaptureDevice.default(.builtInTrueDepthCamera, for: .photo, position: .back) else {
    fatalError("设备不支持深度相机")
}
guard let input = try? AVCaptureDeviceInput(device: cameraDevice) else { return }
if session.canAddInput(input) {
    session.addInput(input)
}

// 配置照片输出并启用深度数据
let photoOutput = AVCapturePhotoOutput()
if session.canAddOutput(photoOutput) {
    session.addOutput(photoOutput)
}

if photoOutput.isDepthDataDeliverySupported {
    photoOutput.isDepthDataDeliveryEnabled = true
    // 优先选择Float16格式的深度数据(兼容性更优)
    let preferredDepthFormat = photoOutput.availableDepthDataFormats.first(where: {
        $0.formatDescription.mediaSubType == .depthDataTypeFloat16
    }) ?? photoOutput.availableDepthDataFormats.first!
    photoOutput.setPreferredDepthDataFormat(preferredDepthFormat)
}

session.commitConfiguration()

2. 配置照片捕获设置

捕获照片时,必须开启embedsDepthDataInPhoto:

let captureSettings = AVCapturePhotoSettings()
captureSettings.embedsDepthDataInPhoto = true
// 若需要视差数据,确保设备支持并开启对应配置
captureSettings.isDisparityDeliveryEnabled = photoOutput.isDisparityDeliverySupported

photoOutput.capturePhoto(with: captureSettings, delegate: self)

3. 正确保存照片数据

禁止二次编码:必须直接使用AVCapturePhoto的fileDataRepresentation()获取包含深度数据的原始文件数据,再写入磁盘。不要通过UIImage转码保存(会丢失深度信息):

func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
    guard error == nil, let imageData = photo.fileDataRepresentation() else {
        print(error?.localizedDescription ?? "无法获取照片数据")
        return
    }
    
    let saveURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
        .appendingPathComponent("depth_photo.heic")
    
    do {
        try imageData.write(to: saveURL)
        print("带深度的照片已保存至: \(saveURL)")
    } catch {
        print("保存失败: \(error.localizedDescription)")
    }
}

推荐使用HEIC格式保存,它对深度数据的支持更完善;JPEG也支持,但部分场景下可能丢失辅助数据。

二、正确读取嵌入的深度/视差数据

使用CGImageSource读取时,需指定对应的辅助数据类型:

func extractDepthAndDisparity(from fileURL: URL) {
    guard let imageSource = CGImageSourceCreateWithURL(fileURL as CFURL, nil) else {
        print("无法创建CGImageSource")
        return
    }
    
    // 读取深度数据(kCGImageAuxiliaryDataTypeDepth)
    let depthOptions = [kCGImageSourceAuxiliaryDataType: kCGImageAuxiliaryDataTypeDepth] as CFDictionary
    if let depthAuxInfo = CGImageSourceCopyAuxiliaryDataInfoAtIndex(imageSource, 0, depthOptions) as? [String: Any] {
        if let depthData = depthAuxInfo[kCGImageAuxiliaryDataInfoData] as? Data,
           let depthCGImage = CGImageCreateWithJPEGDataProvider(
            CGDataProvider(data: depthData as CFData),
            nil,
            true,
            .intentDefault
        ) {
            // 成功获取深度图像,可转换为UIImage使用
            let depthImage = UIImage(cgImage: depthCGImage)
            print("深度数据读取成功")
        }
    }
    
    // 读取视差数据(kCGImageAuxiliaryDataTypeDisparity)
    let disparityOptions = [kCGImageSourceAuxiliaryDataType: kCGImageAuxiliaryDataTypeDisparity] as CFDictionary
    if let disparityAuxInfo = CGImageSourceCopyAuxiliaryDataInfoAtIndex(imageSource, 0, disparityOptions) as? [String: Any] {
        if let disparityData = disparityAuxInfo[kCGImageAuxiliaryDataInfoData] as? Data,
           let disparityCGImage = CGImageCreateWithJPEGDataProvider(
            CGDataProvider(data: disparityData as CFData),
            nil,
            true,
            .intentDefault
        ) {
            let disparityImage = UIImage(cgImage: disparityCGImage)
            print("视差数据读取成功")
        }
    }
}

三、常见排查要点

  • 设备兼容性:仅配备TrueDepth相机(iPhone X及以后)或LiDAR扫描仪(iPhone 12 Pro及以后)的机型支持深度数据嵌入,确保测试设备符合要求。
  • 避免二次编码:任何对AVCapturePhoto的CGImage进行重新编码的操作(比如用UIImageJPEGRepresentation)都会丢失深度数据,必须直接保存fileDataRepresentation()的原始数据。
  • 检查文件索引:如果是Live Photo等包含多帧的文件,需遍历CGImageSource的所有索引,而不只是索引0。
  • 验证深度数据存在:在保存前可通过photo.depthData != nil确认捕获到了深度数据,排除捕获阶段的问题。

内容的提问来源于stack exchange,提问作者Matej Ukmar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 15:53:09