web-dev-qa-db-ja.com

iOS 11およびSwift 4でカメラから深度データをキャプチャする方法は?

AVDepthDataを使用してiOS 11のカメラから深度データを取得しようとしています。AVCapturePhotoCaptureDelegateでphotoOutputを設定すると、photo.depthDataはnilになります。

それで、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()

}

私は2つのことを試みています。1つは深度データがnilであり、もう1つは深度デリゲートメソッドを呼び出そうとしています。

誰かが私が欠けているものを知っていますか?

8
Hexagons

まず、デュアルカメラを使用する必要があります。そうしないと、深度データを取得できません。

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

そして、キューへの参照を保持します

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

また、おそらくビデオと深度データを同期する必要があります

var outputSynchronizer: AVCaptureDataOutputSynchronizer?

次に、このようにviewDidLoad()メソッドで2つの出力を同期できます。

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

私はWWDCセッション507を視聴することをお勧めします-彼らはまたあなたが望むものを正確に行う完全なサンプルアプリを提供します。

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

6
klinger

@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)]

}
2
Oscar

これには2つの方法があり、同時に両方を実行しようとしています。

  1. 画像とともに深度データをキャプチャします。これは、photoOutput(_:didFinishProcessingPhoto:error:)の_photo.depthData_オブジェクトを使用して行われます。これがうまくいかなかった理由を以下で説明します。
  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にしないでください。深度データの取得の詳細については、必ず thisthis (別々だが類似したページ)の両方を読んでください。

#2の場合、depthDataOutput(_:didOutput:timestamp:connection:)が呼び出されない理由はよくわかりませんが、depthDataOutput(_:didDrop:timestamp:connection:reason:)を実装して、何らかの理由で深度データがドロップされているかどうかを確認する必要があります。

2
Coder-256

キャプチャデバイスを初期化する方法が正しくありません。

デュアルカメラモードを使用する必要があります。

ocは次のように:

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