CVPixelBuffer – 如何以每秒 60 帧的速度捕获每第三帧?
CVPixelBuffer – How to capture every THIRD frame out of 60 fps?
我只需要处理每秒 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)
}
}
我所知道的最简单的方法是使用 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)
您可以设置自定义帧速率,这样您将只能获得 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()
我只需要处理每秒 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)
}
}
我所知道的最简单的方法是使用 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)
您可以设置自定义帧速率,这样您将只能获得 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()