获取在 VNDetectTextRectanglesRequest 完成处理程序上的 VNImageRequestHandler 中使用的 cvPixelBuffer

Get the cvPixelBuffer used in a VNImageRequestHandler on the VNDetectTextRectanglesRequest completion handler

我正在使用以下代码创建我的请求:

let textRequest = VNDetectTextRectanglesRequest(completionHandler: 
self.detectTextHandler)
textRequest.reportCharacterBoxes = true
self.requests = [textRequest]

在我的 AVCaptureVideoDataOutputSampleBufferDelegate 中,我正在创建一个 VNImageRequestHandler 并执行它:

let imageRequestHandler = VNImageRequestHandler(cvPixelBuffer: pixelBuffer, orientation: CGImagePropertyOrientation(rawValue: 6)!, options: requestOptions)

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

这为我提供了具有以下签名的处理程序内部的检测结果:

func detectTextHandler(request: VNRequest, error: Error?)

我的问题是,如何获取此请求用于进一步处理的 "cvPixelBuffer"?我应该存储它的临时版本吗?

我找不到任何方法或属性来从 VNRequest 检索 CVPixelBuffer

因此,在 completionHandler 的闭包中捕获它是一种简单的方法:

AVCaptureVideoDataOutputSampleBufferDelegate的方法中:

    let pixelBuffer = ...
    let requestOptions: [VNImageOption: Any] = ...

    let textRequest = VNDetectTextRectanglesRequest {request, error in
        //### Capture `pixelBuffer` inside this closure.
        self.detectText(from: pixelBuffer, request: request, error: error)
    }
    textRequest.reportCharacterBoxes = true

    let imageRequestHandler = VNImageRequestHandler(cvPixelBuffer: pixelBuffer, orientation: CGImagePropertyOrientation(rawValue: 6)!, options: requestOptions)

    do {
        try imageRequestHandler.perform([textRequest])
    } catch {
        print(error)
    }

并将其用作:

func detectText(from buffer: CVPixelBuffer, request: VNRequest, error: Error?) {
    //### Use `buffer` passed from the closure.
    //...
}

这是个好问题。

我的应用 (https://github.com/snakajima/MobileNet-iOS) 遇到了类似的问题,它需要保留对 CMSampleBuffer 对象的引用,直到调用完成处理程序(这样关联的 pixelBuffer 才不会被重用通过视频捕获会话)。

我通过将其存储为视图控制器 (self.sampleBuffer) 的 属性 来解决它。因此,它一次只能处理一个 pixelBuffer——这对我的应用程序来说很好,但不是最优的。

如果你需要做双缓冲(或更多),你需要引入一个队列(pixelBuffers),假设完成的顺序与请求相同——考虑到底层架构,这是合理的假设。

https://github.com/maxvol/RxVision 无需为每张图片重新创建请求(如已接受的答案)。

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

mlRequest
    .observable
    .subscribe { [unowned self] (event) in
        switch event {
            case .next(let completion):       
                let cgImage = completion.value // NB you can easily pass the value along to the completion handler 
                if let result = completion.request.results?[0] as? VNClassificationObservation {
                    os_log("results: %@", type: .debug, result.identifier)
                }
            default:
                break
        }
    }
    .disposed(by: disposeBag)

let imageRequestHandler = VNImageRequestHandler(cgImage: cgImage, orientation: .up, options: requestOptions)
do {
    try imageRequestHandler.rx.perform([mlRequest], with: cgImage) // NB you can easily pass the value along to the completion handler
} catch {
    print(error)
}