ARSession 中用于文本检测的完成处理程序中的帧信息

Frame information in completion handler for text detection in ARSession

我正在使用 Core Vision 来检测 ARKit 会话中的文本框,我的问题是在检测到文本框后访问 frame 以执行命中测试。

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

func detectTextHandler(request: VNRequest, error: Error?) {
    guard let observations = request.results else {
        print("no result")
        return
    }

    let result = observations.map({[=10=] as? VNTextObservation})
    for box in result {
        let hit = frame.hitTest(box?.topRight - box?.bottomLeft, types: ARHitTestResult.ResultType.featurePoint )
        let anchor = ARAnchor(transform:hit.worldTransform)
        sceneView.session.add(anchor:anchor)
    }
    //DispatchQueue.main.async() {

    //}
}

理想情况下,我会将它从 ARSession 委托方法传递给完成处理程序,但尽管文档说我可以在此处传递完成处理程序,但我还没有找到实现它的方法。

func session(_ session: ARSession, didUpdate frame: ARFrame) {
    // Retain the image buffer for Vision processing.
    let pixelBuffer = frame.capturedImage
    let requestOptions:[VNImageOption : Any] = [:]

    let imageRequestHandler = VNImageRequestHandler(cvPixelBuffer: pixelBuffer, orientation: CGImagePropertyOrientation.up, options: requestOptions)

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

我可以保留一本字典并查找它,但它不是很优雅,而且容易出现错误和泄漏。我宁愿通过我请求文本检测的相关框架。

有什么想法吗?

为什么不在完成处理程序中使用会话的 currentFrame 属性?它包含会话的当前帧。另外,您不再需要将任何 frame 实例传递给完成处理程序。使用您的 sceneView 实例可以轻松访问它。

因此您可以像下面这样更改完成处理程序:

func detectTextHandler(request: VNRequest, error: Error?) {
    guard let currentFrame = sceneView.session.currentFrame else { return }
    ...
    // perform hit test using currentFrame
    let hit = currentFrame.hitTest(box?.topRight - box?.bottomLeft, types: ARHitTestResult.ResultType.featurePoint ) 
    ...
}

您也可以使用 currentFramesession(_:didUpdate:) 中创建图像请求处理程序:

let pixelBuffer = sceneView.currentFrame.capturedImage

此外,请注意,在 session(_:didUpdate:) 中触发 VNImageRequestHandlerperform() 方法效率不高,并且需要很多过程,因为它一直是 运行,您可以使用a Timer 而不是减少执行图像检测过程的时间。


编辑:由于图像检测是异步的并且可能需要一些时间才能完成,因此您可以在发出请求时将帧存储在另一个实例中,并在完成处理程序中使用该实例:

var detectionFrame: ARFrame?

// Timer block
detectionFrame = sceneView.session.currentFrame
let pixelBuffer = detectionFrame.capturedImage
// image detection request code


func detectTextHandler(request: VNRequest, error: Error?) {
    guard let frame = detectionFrame else { return }
    ...
    let hit = frame.hitTest(box?.topRight - box?.bottomLeft, types: ARHitTestResult.ResultType.featurePoint ) 
    ...
}