如何在iOS上获取相机校准数据?又名AVCameraCalibrationData

ogq8wdun  于 12个月前  发布在  iOS
关注(0)|答案(5)|浏览(127)

据我所知,AVCameraCalibrationData仅可通过AVCaptureDepthDataOutput获得。是这样吗?
另一方面,AVCaptureDepthDataOutput只能通过iPhone X前置摄像头或iPhone Plus后置摄像头访问,还是我搞错了?
我试图做的是得到一个AVCaptureVideoDataOutput SampleBuffer的FOV。特别是,它应该匹配选定的预设(全高清,照片等)。

epggiuax

epggiuax1#

背景:当被问及相机校准时,许多这些堆栈溢出响应都引用了内部数据,包括这篇文章的可接受答案,但校准数据通常包括内部数据,外部数据,透镜失真等。全部都是here in the iOS documentation。作者提到他们只是在寻找FOV,它在样本缓冲区中,而不是在相机校准数据中。所以最终,我认为他的问题得到了回答。但如果你发现这个问题寻找实际的相机校准数据,这将把你赶走。正如答案所说,你只能在特定条件下获得校准数据,我在下面详细介绍。
在我回答剩下的问题之前,我只想说,如果你只是在寻找内在矩阵,那么这里公认的答案是很好的,这可以更容易地获得(即。不像环境那样严格)通过上面概述的方法比这些值中的其余值更高。如果你把它用于计算机视觉,这就是我用它的目的,有时候这就是所需要的。但对于真正酷的东西,你会想要它的一切!接下来,我将解释如何实现这一点:
我假设你已经有了通用的相机应用程序代码。在这段代码中,当拍摄照片时,你可能会调用photoOutput函数,它看起来像这样:

func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {...

输出参数将有一个值,您可以引用该值来查看是否支持相机校准,称为isCameraCalibrationDataDeliverySupported,因此,例如,要将其打印出来,请使用如下内容:

print("isCameraCalibrationDataDeliverySupported: \(output.isCameraCalibrationDataDeliverySupported)")

注意,在我链接的文档中,它只在特定场景中支持:
“只有当isDualCameraDualPhotoDeliveryEnabled属性为true时,此属性的值才为true。要启用相机校准传递,请在照片设置对象中设置isCameraCalibrationDataDeliveryEnabled属性。”
所以这很重要,要注意这一点,以避免不必要的压力。使用实际值进行调试,并确保启用了正确的环境。
所有这些都到位后,您应该从以下位置获取实际的相机校准数据:

photo.cameraCalibrationData

只需从该对象中拉出以获取您正在查找的特定值,例如:

photo.cameraCalibrationData?.extrinsicMatrix
photo.cameraCalibrationData?.intrinsicMatrix
photo.cameraCalibrationData?.lensDistortionCenter
etc.

基本上所有的东西都列在我上面链接的文档中。

gudnpqoy

gudnpqoy2#

您只能从深度数据输出或照片输出中获取AVCameraCalibrationData
但是,如果您所需要的只是FOV,那么您只需要类提供的部分信息-camera intrinsics matrix-并且您可以从AVCaptureVideoDataOutput获得它本身。
1.在AVCaptureConnection上设置cameraIntrinsicMatrixDeliveryEnabled,将相机设备连接到捕获会话。(注意你应该先检查cameraIntrinsicMatrixDeliverySupported;并非所有捕获格式都支持intrinsic。
1.当视频输出提供采样缓冲器时,检查每个采样缓冲器的附件中是否有kCMSampleBufferAttachmentKey_CameraIntrinsicMatrix键。正如CMSampleBuffer.h中所指出的(有人应该file a radar将此信息纳入在线文档),该附件的值是CFData编码matrix_float3x3,该矩阵的(0,0)和(1,1)元素是以像素为单位的水平和垂直焦距。

zbwhf8kr

zbwhf8kr3#

这里是一个更完整/更新的swift 5代码示例,它是从以前的答案中收集起来的。这就得到了iPhone的相机内部矩阵。
基于:

// session setup
captureSession = AVCaptureSession()

let captureVideoDataOutput = AVCaptureVideoDataOutput()

captureSession?.addOutput(captureVideoDataOutput)

// enable the flag
if #available(iOS 11.0, *) {
    captureVideoDataOutput.connection(with: .video)?.isCameraIntrinsicMatrixDeliveryEnabled = true
} else {
    // ...
}

// `isCameraIntrinsicMatrixDeliveryEnabled` should be set before this
captureSession?.startRunning()

现在在AVCaptureVideoDataOutputSampleBufferDelegate.captureOutput(...)内部

if #available(iOS 11.0, *) {
    if let camData = CMGetAttachment(sampleBuffer, key:kCMSampleBufferAttachmentKey_CameraIntrinsicMatrix, attachmentModeOut:nil) as? Data {
        let matrix: matrix_float3x3 = camData.withUnsafeBytes { pointer in
                if let baseAddress = pointer.baseAddress {
                    return baseAddress.assumingMemoryBound(to: matrix_float3x3.self).pointee
                } else {
                    return matrix_float3x3()
                }
            }
        print(matrix)
        // > simd_float3x3(columns: (SIMD3<Float>(1599.8231, 0.0, 0.0), SIMD3<Float>(0.0, 1599.8231, 0.0), SIMD3<Float>(539.5, 959.5, 1.0)))
    }
} else {
    // ...
}
z9smfwbn

z9smfwbn4#

不是回答,而是...
自从我开始编写代码来制作一个具有深度能力的flutter插件以来,已经有三个星期了,这是一个痛苦的试验和错误的快速回顾,它把我带到了一个工作环境:
(my我为代码质量道歉,这也是我第一次使用Objective-C)

  • iOS有大量的摄像头(硬件的组合),只有一个子集支持深度数据。当您发现您的设备时:
AVCaptureDeviceDiscoverySession *discoverySession = [AVCaptureDeviceDiscoverySession
          discoverySessionWithDeviceTypes:deviceTypes
                                mediaType:AVMediaTypeVideo
                                 position:AVCaptureDevicePositionUnspecified];

你可以询问他们的深度能力:

for (AVCaptureDevice *device in devices) {
        BOOL depthDataCapable;
        if (@available(iOS 11.0, *)) {
          AVCaptureDeviceFormat *activeDepthDataFormat = [device activeDepthDataFormat];
          depthDataCapable = (activeDepthDataFormat != nil);
          NSLog(@" -- %@ supports DepthData: %s", [device localizedName],
        } else {
          depthDataCapable = false;
        }
}

在iPhone 12上:

-- Front TrueDepth Camera supports DepthData: true
 -- Back Dual Wide Camera supports DepthData: true
 -- Back Ultra Wide Camera supports DepthData: false
 -- Back Camera supports DepthData: false
 -- Front Camera supports DepthData: false

p.s.从历史上看,前置摄像头往往比后置摄像头质量更差,但对于深度捕捉,您无法击败使用红外投影仪/扫描仪的TrueDepth相机。
现在您知道哪些相机可以完成这项工作,您需要选择功能强大的相机并启用深度:
(空行是代码遗漏,这不是一个完整的例子)

// this is in your 'post-select-camera' initialization
  _captureSession = [[AVCaptureSession alloc] init];
  // cameraName is not the localizedName
  _captureDevice = [AVCaptureDevice deviceWithUniqueID:cameraName];

  // this is in your camera controller initialization
  // enable depth delivery in AVCapturePhotoOutput
  _capturePhotoOutput = [AVCapturePhotoOutput new];
  [_captureSession addOutput:_capturePhotoOutput];

  // BOOL depthDataSupported is a property of the controller
  _depthDataSupported = [_capturePhotoOutput isDepthDataDeliverySupported];
  if (_depthDataSupported) {
    [_capturePhotoOutput setDepthDataDeliveryEnabled:YES];
  }
  [_captureSession addOutput:_capturePhotoOutput];

  // this is in your capture method
  // enable depth delivery in AVCapturePhotoSettings
  AVCapturePhotoSettings *settings = [AVCapturePhotoSettings photoSettings];
  
  if (@available(iOS 11.0, *) && _depthDataSupported) {
    [settings setDepthDataDeliveryEnabled:YES];
  }

  // Here I use a try/catch because even depth capable and enabled cameras can crash if settings are not correct. 
  // For example a very high picture resolution seems to throw an exception, and this might be a different limit for different phone models.
  // I am sure this information is somewhere I haven't looked yet. 
  @try {
    [_capturePhotoOutput capturePhotoWithSettings:settings delegate:photoDelegate];
  } @catch (NSException *e) {
    [settings setDepthDataDeliveryEnabled:NO];
    [_capturePhotoOutput capturePhotoWithSettings:settings delegate:photoDelegate];
  }

  // after you took a photo and
  // didFinishProcessingPhoto:(AVCapturePhoto *)photo was invoked

  AVDepthData *depthData = [photo depthData];
  if (depthData != nil) {
    AVCameraCalibrationData *calibrationData = [depthData cameraCalibrationData];
    CGFloat pixelSize = [calibrationData pixelSize];
    matrix_float3x3 intrinsicMatrix = [calibrationData intrinsicMatrix];
    CGSize referenceDimensions = [calibrationData intrinsicMatrixReferenceDimensions];
    // now do what you need to do - I need to transform that to 16bit, Grayscale, Tiff, and it starts like this... 

    if (depthData.depthDataType != kCVPixelFormatType_DepthFloat16) {
      depthData = [depthData depthDataByConvertingToDepthDataType:kCVPixelFormatType_DepthFloat16];
    }

  // DON'T FORGET HIT LIKE AND SUBSCRIBE FOR MORE BAD CODE!!! :P

  }
cld4siwp

cld4siwp5#

苹果实际上有一个体面的安装说明在这里:https://developer.apple.com/documentation/avfoundation/cameras_and_media_capture/capturing_photos_with_depth
一个重要的注意事项,我没有看到任何其他地方除了苹果文档:
要捕获深度图,您需要首先选择builtInDualCamera或builtInTrueDepthCamera捕获设备作为会话的视频输入。即使iOS设备具有双摄像头或TrueDepth摄像头,选择默认的后置或前置摄像头也无法启用深度捕捉。

相关问题