我正在使用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({$0 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)
}
}
我可以保留一本字典并查找它,但它并不真正优雅,并且容易出现错误和泄漏。我宁愿在请求文本检测的地方传递相关的框架。
有什么想法吗?
答案 0 :(得分:1)
您为什么不在完成处理程序中使用会话的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 )
...
}
您也可以使用currentFrame
在session(_:didUpdate:)
中创建图像请求处理程序:
let pixelBuffer = sceneView.currentFrame.capturedImage
还要注意,在perform()
中触发VNImageRequestHandler
的{{1}}方法效率不高,而且由于它一直在运行,因此需要花费大量的时间,您可以使用session(_:didUpdate:)
相反,为了减少执行图像检测过程的时间。
编辑:由于图像检测是异步的,可能需要一些时间才能完成,因此您可以在发出请求时将帧存储在另一个实例中,并在完成处理程序中使用该实例:
Timer