0

I'd like to capture the progress value in a VNRecognizeTextRequest session. So I inclueded it in a closure. The problem is it is passed when the closure is completed. I can capture the value and print it but not pass it to the main thread to update my progress bar. So I pass from 0% to 100% in the main thread. Can anybody give me a hand please? Thanks a lot. Here's my code.

private func readImage(image:UIImage, completionHandler:@escaping(([VNRecognizedText]?,Error?)->Void), comp:@escaping((Double?,Error?)->())) {

var recognizedTexts = [VNRecognizedText]()
let requestHandler = VNImageRequestHandler(cgImage: (image.cgImage)!, options: [:])
let textRequest = VNRecognizeTextRequest { (request, error) in
guard let observations = request.results as? [VNRecognizedTextObservation] else { completionHandler(nil,error)
    return
    }
    for currentObservation in observations {
        let topCandidate = currentObservation.topCandidates(1)
        if let recognizedText = topCandidate.first {
            recognizedTexts.append(recognizedText)
        }
    }
    completionHandler(recognizedTexts,nil)
}

textRequest.recognitionLevel = .accurate
textRequest.recognitionLanguages = ["es"]
textRequest.usesLanguageCorrection = true

textRequest.progressHandler = {(request, value, error) in
    print(value)
    comp(value,nil)
}
try? requestHandler.perform([textRequest])
}

This is how I call my function from the content view.

struct ContentView: View {


@State var ima = drawPDFfromURL(url: dalai)
@State private var stepperCounter = 0
@State private var observations = [VNRecognizedText]()
@State private var progressValue: Float = 0.0
private var originaImage = drawPDFfromURL(url: dalai)

var body: some View {

        VStack { Button(action: {
                //self.observations = readText(image: self.ima!)
                DispatchQueue.main.async {
                    readImage(image: self.ima!, completionHandler: { (texts, error) in
                        self.observations = texts!
                    }) { (value, err) in
                        self.progressValue = Float(value!)
                    }
                }
                })
                {
                    Text("Read invoice")
                }
                ProgressBar(value: $progressValue).frame(height: 20)
            }.padding()


  }
}

This is my ProgressBar object

struct ProgressBar: View {

@Binding var value: Float

var body: some View {
    GeometryReader { geometry in
        ZStack(alignment: .leading) {
            Rectangle().frame(width: geometry.size.width , height: geometry.size.height)
                .opacity(0.3)
                .foregroundColor(Color(UIColor.systemTeal))

            Rectangle().frame(width: min(CGFloat(self.value)*geometry.size.width, geometry.size.width), height: geometry.size.height)
            .foregroundColor(Color(UIColor.systemBlue))
                .animation(.linear)

        }.cornerRadius(45)
    }
}

}

Andy Jazz
  • 49,178
  • 17
  • 136
  • 220
  • Can you try to pass the `ProgressBar` object to the `readImage` function, and call `DispatchQueue.main.async` to update the progress bar in the ML request closure. –  Dec 15 '19 at 17:17
  • @ShunzheM I cannot do that, because it is a swiftui struct. Besides the value is printed in the print statement in the closure, but I cannot update the progressbar. It executes all in the end. – Carlos Maria Caraccia Dec 15 '19 at 18:17

1 Answers1

0

I believe that you need to put your request in a async Thread.

DispatchQueue.global(qos: .default).async {
    // Run request
    perform(...)
}
vomi
  • 993
  • 8
  • 18