1

我只需要每秒 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)
    }
}
4

2 回答 2

1

我知道的最简单的方法是使用运算符RxARKit并将其应用于. 我认为跳过这么多事件是不谨慎的,因为帧速率不能保证始终为 60fps,所以最好使用最多每隔这么多毫秒获取一帧,无论实际帧速率是多少。您可以将它的结果插入,这将确保该框架将被..throttle()session.rx.didUpdateFrame.throttle()RxVisionCoreML

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)
于 2018-12-03T07:33:37.430 回答
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()
于 2019-02-13T13:36:07.740 回答