Как получить данные о глубине с камеры в iOS 11 и Swift 4?

Я пытаюсь получить данные о глубине с камеры в iOS 11 с помощью AVDepthData, хотя, когда я настраиваю photoOutput с помощью AVCapturePhotoCaptureDelegate, значение photo.depthData равно нулю.

Итак, я попытался настроить AVCaptureDepthDataOutputDelegate с помощью AVCaptureDepthDataOutput, хотя я не знаю, как сделать снимок глубины?

Кто-нибудь когда-нибудь получал изображение из AVDepthData?

Изменить:

Вот код, который я пробовал:

// delegates: AVCapturePhotoCaptureDelegate & AVCaptureDepthDataOutputDelegate

@IBOutlet var image_view: UIImageView!
@IBOutlet var capture_button: UIButton!

var captureSession: AVCaptureSession?
var sessionOutput: AVCapturePhotoOutput?
var depthOutput: AVCaptureDepthDataOutput?
var previewLayer: AVCaptureVideoPreviewLayer?

@IBAction func capture(_ sender: Any) {

    self.sessionOutput?.capturePhoto(with: AVCapturePhotoSettings(format: [AVVideoCodecKey: AVVideoCodecType.jpeg]), delegate: self)

}

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

    self.previewLayer?.removeFromSuperlayer()
    self.image_view.image = UIImage(data: photo.fileDataRepresentation()!)

    let depth_map = photo.depthData?.depthDataMap
    print("depth_map:", depth_map) // is nil

}

func depthDataOutput(_ output: AVCaptureDepthDataOutput, didOutput depthData: AVDepthData, timestamp: CMTime, connection: AVCaptureConnection) {

    print("depth data") // never called

}

override func viewDidLoad() {
    super.viewDidLoad()

    self.captureSession = AVCaptureSession()
    self.captureSession?.sessionPreset = .photo

    self.sessionOutput = AVCapturePhotoOutput()
    self.depthOutput = AVCaptureDepthDataOutput()
    self.depthOutput?.setDelegate(self, callbackQueue: DispatchQueue(label: "depth queue"))

    do {

        let device = AVCaptureDevice.default(for: .video)
        let input = try AVCaptureDeviceInput(device: device!)
        if(self.captureSession?.canAddInput(input))!{
            self.captureSession?.addInput(input)

            if(self.captureSession?.canAddOutput(self.sessionOutput!))!{
                self.captureSession?.addOutput(self.sessionOutput!)


                if(self.captureSession?.canAddOutput(self.depthOutput!))!{
                    self.captureSession?.addOutput(self.depthOutput!)

                    self.previewLayer = AVCaptureVideoPreviewLayer(session: self.captureSession!)
                    self.previewLayer?.frame = self.image_view.bounds
                    self.previewLayer?.videoGravity = AVLayerVideoGravity.resizeAspectFill
                    self.previewLayer?.connection?.videoOrientation = AVCaptureVideoOrientation.portrait
                    self.image_view.layer.addSublayer(self.previewLayer!)

                }

            }

        }

    } catch {}

    self.captureSession?.startRunning()

}

Я пробую две вещи: одну, где данные о глубине равны нулю, и другую, где я пытаюсь вызвать метод делегата глубины.

Кто-нибудь знает, что мне не хватает?


person Heestand XYZ    schedule 12.06.2017    source источник
comment
Не могли бы вы предоставить код, который вы пробовали?   -  person Coder-256    schedule 12.06.2017
comment
Конечно. Я пытаюсь сделать две вещи в одной, я попытаюсь объяснить это подробнее с помощью кода.   -  person Heestand XYZ    schedule 13.06.2017
comment
Вы используете iPhone 7? Я думаю, вам нужна двойная камера, чтобы получить глубину.   -  person Guig    schedule 13.06.2017
comment
Да, есть iPhone 7 с двойной камерой, но AVDepthData по-прежнему равен нулю.   -  person Heestand XYZ    schedule 14.06.2017
comment
кто-нибудь заставил это работать? @ Coder256 Какое оборудование вы используете?   -  person eyeApps LLC    schedule 21.06.2017
comment
@eyeAppsLLC Мне не удалось это проверить, я просто просмотрел документы. Для карт глубины вам понадобится iPhone 7+ (или, может быть, iPhone 8 или 7s+? Вам понадобится Портретный режим согласно Apple) под управлением iOS 11 (который в настоящее время находится только в бета-версии для разработчиков). , и я не являюсь участником программы Apple Developer Program, поэтому не могу ее загрузить).   -  person Coder-256    schedule 21.06.2017


Ответы (4)


Во-первых, вам нужно использовать двойную камеру, иначе вы не получите никаких данных о глубине.

let device = AVCaptureDevice.default(.builtInDualCamera, for: .video, position: .back)

И сохраните ссылку на свою очередь

let dataOutputQueue = DispatchQueue(label: "data queue", qos: .userInitiated, attributes: [], autoreleaseFrequency: .workItem)

Вы также, вероятно, захотите синхронизировать видео и данные о глубине.

var outputSynchronizer: AVCaptureDataOutputSynchronizer?

Затем вы можете синхронизировать два вывода в своем методе viewDidLoad() следующим образом.

if sessionOutput?.isDepthDataDeliverySupported {
    sessionOutput?.isDepthDataDeliveryEnabled = true
    depthDataOutput?.connection(with: .depthData)!.isEnabled = true
    depthDataOutput?.isFilteringEnabled = true
    outputSynchronizer = AVCaptureDataOutputSynchronizer(dataOutputs: [sessionOutput!, depthDataOutput!])
    outputSynchronizer!.setDelegate(self, queue: self.dataOutputQueue)
}

Я бы порекомендовал посмотреть сеанс 507 WWDC — они также предоставляют полный пример приложения, которое делает именно то, что вы хотите.

https://developer.apple.com/videos/play/wwdc2017/507/< /а>

person klinger    schedule 14.07.2017

Есть два способа сделать это, и вы пытаетесь сделать оба сразу:

  1. Захватите данные о глубине вместе с изображением. Это делается с помощью объекта photo.depthData из photoOutput(_:didFinishProcessingPhoto:error:). Я объясню, почему это не сработало для вас ниже.
  2. Используйте AVCaptureDepthDataOutput и реализуйте depthDataOutput(_:didOutput:timestamp:connection:). Я не уверен, почему это не сработало для вас, но реализация depthDataOutput(_:didOutput:timestamp:connection:) может помочь вам понять, почему.

Я думаю, что вариант №1 — лучший вариант, потому что он связывает данные о глубине с изображением. Вот как вы это сделаете:

@IBAction func capture(_ sender: Any) {

    let settings = AVCapturePhotoSettings(format: [AVVideoCodecKey: AVVideoCodecType.jpeg])
    settings.isDepthDataDeliveryEnabled = true
    self.sessionOutput?.capturePhoto(with: settings, delegate: self)

}

// ...

override func viewDidLoad() {
    // ...
    self.sessionOutput = AVCapturePhotoOutput()
    self.sessionOutput.isDepthDataDeliveryEnabled = true
    // ...
}

Тогда depth_map не должно быть nil. Обязательно прочтите это и это (отдельные, но похожие страницы) для получения дополнительной информации о получении данных о глубине.

Что касается № 2, я не совсем уверен, почему depthDataOutput(_:didOutput:timestamp:connection:) не вызывается, но вы должны реализовать depthDataOutput(_:didDrop:timestamp:connection:reason:), чтобы увидеть, не удаляются ли данные о глубине по какой-либо причине.

person Coder-256    schedule 14.06.2017
comment
Спасибо! Хотя у меня произошел сбой при установке для .isDepthDataDeliveryEnabled значения true: [AVCapturePhotoOutput setDepthDataDeliveryEnabled:] Доставка данных о глубине не поддерживается в текущей конфигурации», затем я прочитал две опубликованные вами ссылки и попробовал: для моего iPhone 7 Plus, не знаю почему, может быть, это что-то из iPhone 8: macrumors.com/2017/06/14/apple-camera-lens-supplier-3d/ - person Heestand XYZ; 14.06.2017
comment
Рад, что смог помочь! Хотя проблема, вероятно, в том, что вы используете iOS 10 вместо iOS 11 на своем iPhone. - person Coder-256; 15.06.2017
comment
как это может работать? Разве для этого не требуется телефон со специальным оборудованием? - person eyeApps LLC; 21.06.2017

Чтобы дать более подробную информацию ответу @klinger, вот что вам нужно сделать, чтобы получить данные о глубине для каждого пикселя, я написал несколько комментариев, надеюсь, это поможет!

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

    //## Convert Disparity to Depth ##

    let depthData = (photo.depthData as AVDepthData!).converting(toDepthDataType: kCVPixelFormatType_DepthFloat32)
    let depthDataMap = depthData.depthDataMap //AVDepthData -> CVPixelBuffer

    //## Data Analysis ##

    // Useful data
    let width = CVPixelBufferGetWidth(depthDataMap) //768 on an iPhone 7+
    let height = CVPixelBufferGetHeight(depthDataMap) //576 on an iPhone 7+
    CVPixelBufferLockBaseAddress(depthDataMap, CVPixelBufferLockFlags(rawValue: 0))

    // Convert the base address to a safe pointer of the appropriate type
    let floatBuffer = unsafeBitCast(CVPixelBufferGetBaseAddress(depthDataMap), to: UnsafeMutablePointer<Float32>.self)

    // Read the data (returns value of type Float)
    // Accessible values : (width-1) * (height-1) = 767 * 575

    let distanceAtXYPoint = floatBuffer[Int(x * y)]

}
person Oscar Falmer    schedule 20.10.2017

То, как вы инициализируете свое устройство захвата, неверно.

Вы должны использовать режим двойной камеры.

что касается oc следующим образом:

AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithDeviceType:AVCaptureDeviceTypeBuiltInDualCamera mediaType:AVMediaTypeVideo position:AVCaptureDevicePositionBack];
person 周景锦    schedule 26.06.2017