CVPixelBuffer –如何捕获60 fps内的每个THIRD帧?

时间:2018-12-02 17:38:01

标签: swift augmented-reality arkit cvpixelbuffer apple-vision

每秒只需要处理60帧中的20帧(CVPixelBuffer

如何在ARKit会话中捕获每三个ARFrame ?我需要大约20 fps的速度进行捕捉(我知道可能会有丢帧)。

这是代码段:

func updateCoreML() {

    let pixelBuffer: CVPixelBuffer? = (sceneView.session.currentFrame?.capturedImage)

    if pixelBuffer == nil { return }
    let ciImage = CIImage(cvPixelBuffer: pixelBuffer!)
    let imageRequestHandler = VNImageRequestHandler(ciImage: ciImage, options: [:])

    do {
        try imageRequestHandler.perform(self.visionRequests)
    } catch {
        print(error)
    }
}

2 个答案:

答案 0 :(得分:1)

我所知道的最简单的方法是使用RxARKit并将.throttle()运算符应用于session.rx.didUpdateFrame。我认为跳过所有这么多的事件并不明智,因为帧速率不能始终保证为60fps,因此最好使用.throttle()来获取每隔这么多毫秒的帧,无论如何实际的帧速率是。您可以将其结果插入RxVision中,这将确保CoreML将使用该帧。

import RxSwift
import RxARKit
import RxVision


let disposeBag = DisposeBag()
let mlRequest: RxVNCoreMLRequest<CVPixelBuffer> = VNCoreMLRequest.rx.request(model: model, imageCropAndScaleOption: .scaleFit)

mlRequest
    .observable
    .subscribe { [unowned self] (event) in
        switch event {
            case .next(let completion):       
                let cvPixelBuffer = completion.value
                if let result = completion.request.results?[0] as? VNClassificationObservation {
                    os_log("results: %@", type: .debug, result.identifier)
                }
            default:
                break
        }
    }
    .disposed(by: disposeBag)

session
    .rx
    .didUpdateFrame
    .throttle(1/20)
    .subscribe { event in
        switch event {
        case .next(let didUpdateFrame):
        let frame: ARFrame = didUpdateFrame.frame        
        let imageRequestHandler = VNImageRequestHandler(cvPixelBuffer: frame.capturedImage, orientation: .up, options: requestOptions)
        do {
            try imageRequestHandler.rx.perform([mlRequest], with: frame.capturedImage) } catch {
            print(error)
        }            
        break
        default:
            break
        }
    }
    .disposed(by: disposeBag)

答案 1 :(得分:0)

您可以设置自定义帧速率,这样您将只获得20帧,或者可以接收所有帧,但是可以通过采用标志变量并将其递增来仅使用每三帧一次。

  func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
       totalFrameCount += 1
       if totalFrameCount % 3 != 0{ return }
}

或者您可以通过扩展AVCaptureDevice来设置自定义帧速率

 lockForConfiguration()
 activeVideoMinFrameDuration = CMTimeMake(1, 20)
 activeVideoMaxFrameDuration = CMTimeMake(1, 20)
 unlockForConfiguration()