P Star
P Star

Reputation: 67

ARKit add reference images from url

I want to add ARReferenceImages from a server. For this I get an array with the URL's to the images. T tried with the following function, that iterates the url's and adds the new created ARImages to the set. But it does not work.

    func addReferences(media: NSArray){
    var customReferenceSet = Set<ARReferenceImage>()
    for medium in media{
        let type = (medium as AnyObject).value(forKey: "type");
        let t = type as! String

        let reference = (medium as AnyObject).value(forKey: "reference");
        let ref = reference as! String


        let ide = (medium as AnyObject).value(forKey: "id");
        let id = ide as! String


        let url = URL(string: ref)
        let session = URLSession(configuration: .default)


        let downloadPicTask = session.dataTask(with: url!) { (data, response, error) in

            if let e = error {
                print("Error downloading picture: \(e)")
            } else {

                if let res = response as? HTTPURLResponse {
                    print("Downloaded picture with response code \(res.statusCode)")
                    if let imageData = data {
                        let image = UIImage(data: imageData)!
                        let imageToCIImage = CIImage(image: image)
                        let cgImage = self.convertCIImageToCGImage(inputImage: imageToCIImage!)
                        let arImage = ARReferenceImage(cgImage!, orientation: CGImagePropertyOrientation.up, physicalWidth: 0.2)
                        arImage.name = id
                        customReferenceSet.insert(arImage)
                    } else {
                        print("Couldn't get image: Image is nil")
                    }
                } else {
                    print("Couldn't get response code for some reason")
                }
            }
        }

        downloadPicTask.resume()
    }

    self.configuration = ARWorldTrackingConfiguration()
    self.configuration?.detectionImages = customReferenceSet
    sceneView.session.run(configuration!)
}

Sometimes, but not everytime, I get the following output:

[boringssl_session_read] SSL_ERROR_ZERO_RETURN(6): operation failed because the connection was cleanly shut down with a close_notify alert

Some ideas?

Upvotes: 1

Views: 1282

Answers (1)

David Pasztor
David Pasztor

Reputation: 54775

The issue is that you set detectionImages before the async network requests could actually fetch the images, meaning that you actually assign the empty set to detectionImages.

You need to make sure that you only set detectionImages once all images were fetched from the server, which you can achieve by using a DispatchGroup.

func addReferences(media: NSArray){
    var customReferenceSet = Set<ARReferenceImage>()
    let imageFetchingGroup = DispatchGroup()
    for medium in media { 
        let type = (medium as AnyObject).value(forKey: "type");
        let t = type as! String

        let reference = (medium as AnyObject).value(forKey: "reference");
        let ref = reference as! String

        let ide = (medium as AnyObject).value(forKey: "id");
        let id = ide as! String

        let url = URL(string: ref)
        let session = URLSession(configuration: .default)

        imageFetchingGroup.enter()
        let downloadPicTask = session.dataTask(with: url!) { (data, response, error) in
            if let e = error {
                print("Error downloading picture: \(e)")
                imageFetchingGroup.leave()
            } else {
                if let res = response as? HTTPURLResponse {
                    print("Downloaded picture with response code \(res.statusCode)")
                    if let imageData = data {
                        let image = UIImage(data: imageData)!
                        let arImage = ARReferenceImage(image.cgImage!, orientation: CGImagePropertyOrientation.up, physicalWidth: 0.2)
                        arImage.name = id
                        customReferenceSet.insert(arImage)
                        imageFetchingGroup.leave()
                    } else {
                        print("Couldn't get image: Image is nil")
                        imageFetchingGroup.leave()
                    }
                } else {
                    print("Couldn't get response code for some reason")
                    imageFetchingGroup.leave()
                }
            }
        }

        downloadPicTask.resume()
    }

    self.configuration = ARWorldTrackingConfiguration()
    imageFetchingGroup.notify(queue: .main) {
        self.configuration?.detectionImages = customReferenceSet
        sceneView.session.run(configuration!)
    }
}

You also shouldn't use NSArray in Swift and especially shouldn't cast types with known properties to AnyObject just to the dynamically retrieve their properties using value(forKey:) with static keys. Simply use Array with the concrete type and access the properties using the dot syntax.

There's also no need for the custom conversion from UIImage to CIImage and then to CGImage, UIImage has a built in property, cgImage that you can use for the conversion.

Upvotes: 2

Related Questions