每帧多个视觉请求

时间:2017-12-30 02:35:24

标签: ios swift multithreading computer-vision

我正在使用VisionCoreML框架。我有一个实时视频输入。对于每一帧,我首先使用VNDetectRectanglesRequest检测矩形。对于我检测到的每个矩形,我裁剪出图像的那一部分并执行VNCoreMLRequest来对图像的那一部分进行分类。对对象进行分类后,如果它是我要查找的对象类型,我绘制矩形。这就像我没有数据来训练实际的神经网络进行检测时构建了物体探测器。

通常,我会检测大约1到3个矩形。不是很多。因此,对于每个VNDetectRectanglesRequest,我每帧需要增加1到3个VNCoreMLRequest来执行。但是,执行所有这些请求会使我的视频流非常滞后。当我将相机对准矩形物体时,它非常引人注目。我想我应该补充说,这段视频片段来自ARKit,因此无论背景操作ARKit正在执行,都可能会使延迟变得更糟。

我尝试使用DispatchQueue优化代码。下面是我的伪代码。我很满意代码正在做什么,但我需要摆脱滞后。

 DispatchQueue.global(qos: .background).async {
        let request = VNDetectRectanglesRequest(completionHandler: { (request, error) in
             // ...
             for observation in request.results {
                  let mlRequest = VNCoreMLRequest(model: model){ (request, error) in
                       // classify ... if is object I want then jump back to main queue and draw
                       DispatchQueue.main.async {
                           // draw rectangles
                       }
                   })
              }
         })
 }

2 个答案:

答案 0 :(得分:0)

我认为您的代码没有任何问题,只是为每个帧提出所有这些请求对设备的负载来说太高了。

尝试降低请求的频率,并在首先发出请求之前添加一些条件进行检查。只需添加一个检查以确定您是否已经在等待其他请求完成,这可能会显着减少负载。您还可以检查用户是否保持设备稳定,框架是否清晰,光线充足等等。

答案 1 :(得分:0)

延迟可能是由创建新的请求对象引起的(最好在Instruments / Time Profiler中进行检查,但通常首先想到的是对象创建)。

在类似的情况下(我需要在整个图像上运行一个请求,然后在其部分上运行其他请求),我使用的是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)
}