AVDepthDataを使ってCVPixelBuffer形式からdepthを取った時に非線形データが取れた時のTips

September 08, 2024
Author(著者):
beaver
iOS
LiDAR

iOS15.4からLiDARの生データにアクセスできるようになりました。

https://developer.apple.com/documentation/avfoundation/additional_data_capture/capturing_depth_using_the_lidar_camera

それを使ってDepth情報を取る場合、画像データと共に取ることがケースとして多いと思うので、上記の

// Create an object to output video sample buffers.
videoDataOutput = AVCaptureVideoDataOutput()
captureSession.addOutput(videoDataOutput)


// Create an object to output depth data.
depthDataOutput = AVCaptureDepthDataOutput()
depthDataOutput.isFilteringEnabled = isFilteringEnabled
captureSession.addOutput(depthDataOutput)


// Create an object to synchronize the delivery of depth and video data.
outputVideoSync = AVCaptureDataOutputSynchronizer(dataOutputs: [depthDataOutput, videoDataOutput])
outputVideoSync.setDelegate(self, queue: videoQueue)

こんな感じでDelegateをセットしてあげて、

func dataOutputSynchronizer(_ synchronizer: AVCaptureDataOutputSynchronizer,
                                didOutput synchronizedDataCollection: AVCaptureSynchronizedDataCollection) 

で取得したイメージとdepthにアクセスできます。

そんな時に、取得したdepthに対して値を取ると非線形データになっている場合があると思います。(逆数の上に対数取ったみたいな形になっている)

そのような場合は、下記のようにtypeをdepth系のものに指定してあげる必要があります。

let depthMap = syncedDepthData.depthData.converting(toDepthDataType: kCVPixelFormatType_DepthFloat32).depthDataMap

こうすることで、データが線形のmeter単位のものとして取れるようになります。

まとめると、以下のようなDelegateで深度情報は取得できます。

func dataOutputSynchronizer(_ synchronizer: AVCaptureDataOutputSynchronizer,

                                didOutput synchronizedDataCollection: AVCaptureSynchronizedDataCollection) {

        // Retrieve the synchronized depth and sample buffer container objects.

        guard let syncedDepthData = synchronizedDataCollection.synchronizedData(for: depthDataOutput) as? AVCaptureSynchronizedDepthData,

              let syncedVideoData = synchronizedDataCollection.synchronizedData(for: videoOutput) as? AVCaptureSynchronizedSampleBufferData else { return }

        DispatchQueue.main.async {

            let rotatedImage = drawImage.rotate(radians: .pi / 2) // 90度戻す

            self.previewView.image = rotatedImage

            let depthPixelBuffer = syncedDepthData.depthData.converting(toDepthDataType: kCVPixelFormatType_DepthFloat32).depthDataMap

            // ピクセルバッファをロックしてアクセス

            CVPixelBufferLockBaseAddress(depthPixelBuffer, .readOnly)

            // 深度データにアクセス

            let baseAddress = CVPixelBufferGetBaseAddress(depthPixelBuffer)!

            let depthPointer = baseAddress.assumingMemoryBound(to: Float32.self)

            let point = CGPoint(x: 100,y: 50)

            let width = CVPixelBufferGetWidth(depthPixelBuffer)

            let depthValue = depthPointer[Int(point.y * CGFloat(width) + point.x)]

            // ピクセルバッファのロックを解除

            CVPixelBufferUnlockBaseAddress(depthPixelBuffer, .readOnly)

            print(depthValue)

        }

    }

 めっちゃ備忘録でした。


copyright © 2024 beavers-hive.com