Bagaimana cara menangkap data kedalaman dari kamera di iOS 11 dan Swift 4?

Saya mencoba mendapatkan data kedalaman dari kamera di iOS 11 dengan AVDepthData, ketika saya mengatur photoOutput dengan AVCapturePhotoCaptureDelegate, photo. depthData nihil.

Jadi saya mencoba mengatur AVCaptureDepthDataOutputDelegate dengan AVCaptureDepthDataOutput, tapi saya tidak tahu cara mengambil foto kedalaman?

Adakah yang pernah mendapatkan gambar dari AVDepthData?

Sunting:

Inilah kode yang saya coba:

// 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()

}

Saya mencoba dua hal, satu di mana data kedalamannya nihil dan satu lagi di mana saya mencoba memanggil metode delegasi kedalaman.

Apakah ada yang tahu apa yang saya lewatkan?


person Heestand XYZ    schedule 12.06.2017    source sumber
comment
Bisakah Anda memberikan kode yang Anda coba?   -  person Coder-256    schedule 12.06.2017
comment
Tentu. Saya mencoba dua hal dalam satu, saya akan mencoba menjelaskannya lebih lanjut dengan kode.   -  person Heestand XYZ    schedule 13.06.2017
comment
Apakah Anda menggunakan iPhone 7? Saya pikir Anda memerlukan kamera ganda untuk mendapatkan kedalaman   -  person Guig    schedule 13.06.2017
comment
Yap punya dual kamera iPhone 7, tetap saja AVDepthData nihil.   -  person Heestand XYZ    schedule 14.06.2017
comment
adakah yang bisa membuat ini berhasil? @ Coder256 Perangkat keras apa yang Anda gunakan?   -  person eyeApps LLC    schedule 21.06.2017
comment
@eyeAppsLLC Saya tidak dapat mengujinya, saya hanya melihat dokumennya. Untuk peta kedalaman, Anda memerlukan iPhone 7+ (atau mungkin iPhone 8 atau 7s+? Anda memerlukan Mode Potret menurut Apple) yang menjalankan iOS 11 (yang saat ini hanya dalam Beta Pengembang , dan saya bukan anggota Program Pengembang Apple jadi saya tidak dapat mengunduhnya).   -  person Coder-256    schedule 21.06.2017


Jawaban (4)


Pertama, Anda perlu menggunakan kamera ganda, jika tidak, Anda tidak akan mendapatkan data kedalaman apa pun.

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

Dan simpan referensi ke antrean Anda

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

Anda mungkin juga ingin menyinkronkan video dan data kedalaman

var outputSynchronizer: AVCaptureDataOutputSynchronizer?

Kemudian Anda dapat menyinkronkan dua output dalam metode viewDidLoad() Anda seperti ini

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)
}

Saya akan merekomendasikan menonton sesi WWDC 507 - mereka juga menyediakan contoh aplikasi lengkap yang melakukan apa yang Anda inginkan.

https://developer.apple.com/videos/play/wwdc2017/507/

person klinger    schedule 14.07.2017

Ada dua cara untuk melakukan ini, dan Anda mencoba melakukan keduanya sekaligus:

  1. Tangkap data kedalaman bersama dengan gambar. Hal ini dilakukan dengan menggunakan objek photo.depthData dari photoOutput(_:didFinishProcessingPhoto:error:). Saya menjelaskan mengapa ini tidak berhasil untuk Anda di bawah.
  2. Gunakan AVCaptureDepthDataOutput dan terapkan depthDataOutput(_:didOutput:timestamp:connection:). Saya tidak yakin mengapa ini tidak berhasil untuk Anda, namun menerapkan depthDataOutput(_:didOutput:timestamp:connection:) mungkin membantu Anda mengetahui alasannya.

Menurut saya #1 adalah pilihan yang lebih baik, karena memasangkan data kedalaman dengan gambar. Inilah cara Anda melakukannya:

@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
    // ...
}

Maka, depth_map tidak seharusnya menjadi nil. Pastikan untuk membaca ini dan ini (halaman terpisah namun serupa) untuk informasi lebih lanjut tentang memperoleh data kedalaman.

Untuk #2, saya tidak begitu yakin mengapa depthDataOutput(_:didOutput:timestamp:connection:) tidak dipanggil, tetapi Anda harus menerapkan depthDataOutput(_:didDrop:timestamp:connection:reason:) untuk melihat apakah data kedalaman dihilangkan karena alasan tertentu.

person Coder-256    schedule 14.06.2017
comment
Terima kasih! Saya mengalami crash saat menyetel .isDepthDataDeliveryEnabled ke true: [AVCapturePhotoOutput setDepthDataDeliveryEnabled:] Pengiriman data kedalaman tidak didukung dalam konfigurasi saat ini', saya kemudian membaca dua tautan yang Anda posting dan coba: self.sessionOutput.isDepthDataDeliverySupported, ternyata salah untuk iPhone 7 Plus saya, tidak yakin kenapa, mungkin ini beberapa barang iPhone 8: macrumors.com/2017/06/14/apple-camera-lens-supplier-3d/ - person Heestand XYZ; 14.06.2017
comment
Senang aku dapat membantu! Meskipun masalahnya mungkin Anda menjalankan iOS 10, bukan iOS 11 di iPhone Anda. - person Coder-256; 15.06.2017
comment
bagaimana ini bisa berhasil? Bukankah ini memerlukan ponsel dengan perangkat keras khusus? - person eyeApps LLC; 21.06.2017

Untuk lebih detail jawaban @klinger, berikut yang perlu Anda lakukan untuk mendapatkan Data Kedalaman setiap piksel, saya tulis beberapa komentar, semoga membantu!

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

Cara Anda memulai perangkat pengambilan Anda salah.

Anda harus menggunakan mode kamera ganda.

adapun oc seperti berikut:

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