2

While running ARKit on iPhone XS (with iOS 12.1.2 and Xcode 10.1), I'm getting errors and crashes/hangs while running Vision code to detect face bounds.

Errors I'm getting are:

2019-01-04 03:03:03.155867-0800 ARKit Vision Demo[12969:3307770] Execution of the command buffer was aborted due to an error during execution. Caused GPU Timeout Error (IOAF code 2)
2019-01-04 03:03:03.155786-0800 ARKit Vision Demo[12969:3307850] Execution of the command buffer was aborted due to an error during execution. Discarded (victim of GPU error/recovery) (IOAF code 5)
[SceneKit] Error: display link thread seems stuck

This happens on iPhone XS while running the following proof of concept code to reproduce the error (always happens within a few seconds of running the app) - https://github.com/xta/ARKit-Vision-Demo

The relevant ViewController.swift contains the problematic methods:

func classifyCurrentImage() {
    guard let buffer = currentBuffer else { return }

    let image = CIImage(cvPixelBuffer: buffer)
    let options: [VNImageOption: Any] = [:]
    let imageRequestHandler = VNImageRequestHandler(ciImage: image, orientation: self.imageOrientation, options: options)

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

func handleFaces(request: VNRequest, error: Error?) {
    DispatchQueue.main.async {
        guard let results = request.results as? [VNFaceObservation] else { return }
        // TODO - something here with results
        print(results)

        self.currentBuffer = nil
    }
}

What is the correct way to use Apple's ARKit + Vision with VNDetectFaceRectanglesRequest? Getting mysterious IOAF code errors is not correct.

Ideally, I'd also like to use VNTrackObjectRequest & VNSequenceRequestHandler to track requests.

There is decent online documentation for using VNDetectFaceRectanglesRequest with Vision (and without ARKit). Apple has a page here (https://developer.apple.com/documentation/arkit/using_vision_in_real_time_with_arkit) which I've followed, but I'm still getting the errors/crashes.

Andy Jazz
  • 49,178
  • 17
  • 136
  • 220
xta
  • 729
  • 2
  • 8
  • 29

3 Answers3

1

For anyone else who goes through the pain I just did trying to fix this exact error for VNDetectRectanglesRequest, here was my solution:

It seems that using a CIImage:

let imageRequestHandler = VNImageRequestHandler(ciImage: image, orientation: self.imageOrientation, options: options)

caused Metal to retain a large amount Internal Functions in my memory graph.

I noticed that Apple's example projects all use this instead:

let handler: VNImageRequestHandler! = VNImageRequestHandler(cvPixelBuffer: pixelBuffer,
                                                                    orientation: orientation,
                                                                    options: requestHandlerOptions)

Switching to use cvPixelBuffer instead of a CIImage fixed all of my random GPU timeout errors!

I used these functions to get the orientation (I'm using the back camera. I think you may have to mirror for the front camera depending on what you're trying to do):

func exifOrientationForDeviceOrientation(_ deviceOrientation: UIDeviceOrientation) -> CGImagePropertyOrientation {

    switch deviceOrientation {
    case .portraitUpsideDown:
        return .right

    case .landscapeLeft:
        return .down

    case .landscapeRight:
        return .up

    default:
        return .left
    }
}

func exifOrientationForCurrentDeviceOrientation() -> CGImagePropertyOrientation {
    return exifOrientationForDeviceOrientation(UIDevice.current.orientation)
}

and the following as the options:

var requestHandlerOptions: [VNImageOption: AnyObject] = [:]
let cameraIntrinsicData = CMGetAttachment(pixelBuffer, key: kCMSampleBufferAttachmentKey_CameraIntrinsicMatrix, attachmentModeOut: nil)
if cameraIntrinsicData != nil {
            requestHandlerOptions[VNImageOption.cameraIntrinsics] = cameraIntrinsicData
}

Hopefully this saves someone the week that I lost!

Steven
  • 11
  • 1
0

You need to call perform method async, just as it is done in the link you've shared. Try below code:

func classifyCurrentImage() {
    guard let buffer = currentBuffer else { return }

    let image = CIImage(cvPixelBuffer: buffer)
    let options: [VNImageOption: Any] = [:]
    let imageRequestHandler = VNImageRequestHandler(ciImage: image, orientation: self.imageOrientation, options: options)

    DispatchQueue.global(qos: .userInteractive).async {
        do {
            try imageRequestHandler.perform(self.requests)
        } catch {
            print(error)
        }
    }
}
M Reza
  • 18,350
  • 14
  • 66
  • 71
  • 1
    I have tried your code (previously I have tried using a serialQueue as per Apple's code), but the app does not work. Using your code above, I'm still getting errors/hangs: `ARKit Vision Demo[13245:3429200] Execution of the command buffer was aborted due to an error during execution. Discarded (victim of GPU error/recovery) (IOAF code 5) ARKit Vision Demo[13245:3429144] Execution of the command buffer was aborted due to an error during execution. Caused GPU Timeout Error (IOAF code 2)` – xta Jan 05 '19 at 01:10
  • @xta That's strange, I ran the sample project and had no issues on an iPhone 7 device. – M Reza Jan 05 '19 at 03:05
  • I agree since I can run the code on iPhone 7 fine, but will get the errors immediately with iPhone XS. Very frustrating since 7 = OK, XS = errors galore. – xta Jan 05 '19 at 06:28
0

Update: from what I can tell, the issue was retain cycles (or the lack of [weak self]) in my demo repo. In Apple's sample project, they properly use [weak self] to avoid retain cycles and ARKit + Vision app runs on the iPhone XS.

xta
  • 729
  • 2
  • 8
  • 29
  • how did you modify the code above to properly use `[weak self]` – codingViking Jan 27 '19 at 00:12
  • 1
    I didn't modify the code above, I started over using the Apple project as a baseline https://developer.apple.com/documentation/arkit/using_vision_in_real_time_with_arkit – xta Jan 31 '19 at 08:57