CVPixelBuffer - Как захватить каждый ТРЕТИЙ кадр из 60 кадров в секунду?

Мне для обработки нужно всего 20 кадров из 60 кадров в секунду (CVPixelBuffer).

Как захватить каждый третий ARFrame в сеансе ARKit? Мне нужно примерно 20 кадров в секунду для захвата (я понимаю, что может быть пропущенный кадр).

Вот фрагмент кода:

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

person Andy Fedoroff    schedule 02.12.2018    source источник


Ответы (2)


Самый простой способ, который мне известен, - использовать RxARKit и применить оператор .throttle() к session.rx.didUpdateFrame. Я считаю, что неразумно пропускать каждое такое количество событий, потому что частота кадров не всегда гарантирована на уровне 60 кадров в секунду, поэтому лучше всего использовать .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)
person Maxim Volgin    schedule 03.12.2018
comment
Это весь Карфаген, а не стручки. - person Maxim Volgin; 03.12.2018
comment
Я использую RxVision в своем приложении, которое опубликовано в AppStore, вероятно, RxARKit тоже не проблема. - person Maxim Volgin; 03.12.2018
comment
Добавлен фрагмент. - person Maxim Volgin; 03.12.2018

Вы можете либо установить собственную частоту кадров, чтобы получить только 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()
person Tahir Iqbal    schedule 13.02.2019
comment
Тахир, спасибо за ответ. Но этот вопрос касается исключительно ARKit, а не AVFoundation. Я знаю, что умеет AVFoundation и каким образом. - person Andy Fedoroff; 13.02.2019