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)
}
}
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)
Вы можете либо установить пользовательскую частоту кадров, чтобы получить только 20 кадров, либо получить все кадры, но использовать только каждый третий кадр, взяв переменную flag и увеличивая ее.
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()