BlinkID / blinkid-ios

Everything you need to add AI-driven ID scanning into your native iOS app.
https://microblink.com/products/blinkid
385 stars 89 forks source link

FIXME: INTERNAL BUG DETECTED #108

Closed 0awful closed 7 years ago

0awful commented 7 years ago

I am getting this error:

[WTF] processDetection [BlinkOcrRecognizer.cpp:255] 2017-09-17 19:42:39.676256-0700 blinkPackages[4470:5419114] FIXME: Internal bug detected. Detector returned 0 location names for 4 locations!

I have parsers with group names that match 4 locations, despite what the error code states.

Context: I am using a PPBlinkOCRRecognizer to perform TemplateOCR. Previously all my locations were missing their targets on the template, but everything was working. I used geometry to derive the rects as a fraction from my template. Now, whenever I point my camera at an object that matches the aspect ratio of the item that I'm trying to OCR I get this fatal error.

Code for the ViewController is included below, all you need to do is attach a button and it will "work"

I have verified that the names do indeed match, I have renamed the parsers to match their location names, I have increased and decreased the dewarped height. This problem began to occur upon changing the rects to a location that arrives at a match on a 4/6 aspect ratio item.

import UIKit
import MicroBlink
import MobileCoreServices

class ViewController: UIViewController, PPScanningDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    func templateScanningSetup(error: NSErrorPointer) -> PPCameraCoordinator? {

        // 0. Check for scanning:

        if (PPCameraCoordinator.isScanningUnsupported(for: PPCameraType.back, error: error)) {
            // TODO: ADD MEANINGFUL ALERT
            return nil
        }

        // 1. Initialize scanning settings:

        let settings = PPSettings()

        // 2. Add license key:

        settings.licenseSettings.licenseKey = "GEPCIHXA-CDPIQMWZ-PQYMC5WR-GNFQ7IMI-GKM6I5GP-LOZ3BL3M-RHXBUFLI-SS7VANMY"

        // 3. Set up what is going to be scanned:

        let ocrSettings = PPBlinkOcrRecognizerSettings()

        // Then watch shit become bananas...

        // This is our OCR engine
        let textParser = PPRawOcrParserFactory()

        // TODO: ADD CHARCTER WHITELIST
        let _ = PPOcrEngineOptions()

        // Add parser to the recognizer settings we must do this for each region we will eventually OCR, right now this is the same module for all of them, but once we have everything working, we can tune our OCR for each purpose. Convieniently this unifies these settings accross all shipping labels. Which should minimize repition in the long run.
        ocrSettings.addOcrParser(textParser, name: "RecipientAddress", group: "RecipientAddress")
        ocrSettings.addOcrParser(textParser, name: "textParser", group: "SenderAddress")
        ocrSettings.addOcrParser(textParser, name: "textParser", group: "Weight")
        ocrSettings.addOcrParser(textParser, name: "textParser", group: "Tracking")

        // Here we define the location of the objects of interest on our shipping label
        let recipientAddressLocation = CGRect.init(x: 85/600, y: 100/900, width: 365/600, height: 85/900)
        let senderAddressLocation = CGRect.init(x: 10/600, y: 30/900, width: 260/600, height: 65/900)
        let weightLocation = CGRect.init(x: 510/600, y: 30/900, width: 80/600, height: 75/900)
        let trackingLocation = CGRect.init(x: 10/600, y: 430/900, width: 370/600, height: 30/900)

        // We then convert them into an object that the OCR module will understand and give it a keyname that is meaningful. This should be heavily refactored
        let recipientAddressDecodingInfo = PPDecodingInfo.init(location: recipientAddressLocation, dewarpedHeight: 85, uniqueId: "RecipientAddress")
        let senderAddressDecodingInfo = PPDecodingInfo.init(location: senderAddressLocation, dewarpedHeight: 65, uniqueId: "SenderAddress")
        let weightDecodingInfo = PPDecodingInfo.init(location: weightLocation, dewarpedHeight: 75, uniqueId: "Weight")
        let trackingDecodingInfo = PPDecodingInfo.init(location: trackingLocation, dewarpedHeight: 30, uniqueId: "Tracking")

        // We then toss that into the an array of all info for a label.
        let UPSLabelInfo: [PPDecodingInfo] = [recipientAddressDecodingInfo, senderAddressDecodingInfo, weightDecodingInfo, trackingDecodingInfo]

        // We've gotta create the specification of the document, its width/height for aspect ratio
        let labelSettings = PPDocumentSpecification.init(aspectRatio: 4/6, decodingInfo: UPSLabelInfo)
        labelSettings.portraitScale = PPScale.init(scale: 0.9, tolerance: 0.1)

        // Then we create a wrapper type
        let detectorSettings = PPDocumentDetectorSettings.init(numStableDetectionsThreshold: 3)

        // append our data to it.
        detectorSettings.setDocumentSpecifications([labelSettings])

        // add that to our settings
        ocrSettings.detectorSettings = detectorSettings

        // TODO: APPLY A CLASSIFIER
        // look at line 239 for roughly no help at all,
        // look at lines 243 and 244 for more help
        // In general you make some code that does some things

        settings.scanSettings.add(ocrSettings)

        let coordinator = PPCameraCoordinator.init(settings: settings)
        return coordinator
    }

    @IBAction func pressedButton(_ sender: Any) {
        /** Instantiate the scanning coordinator */
        let error: NSErrorPointer = nil
        let coordinator = self.templateScanningSetup(error: error)

        /** If scanning isn't supported, present an error */
        if coordinator == nil {
            if error != nil {
                print(error!)
            } else {
                print("No error, but a fuckup, weird")
            }
            return
        }

        /** Allocate and present the scanning view controller */
        let scanningViewController: UIViewController = PPViewControllerFactory.cameraViewController(with: self, coordinator: coordinator!, error: nil)

        /** You can use other presentation methods as well */
        self.present(scanningViewController, animated: true, completion: nil)
    }

    func scanningViewControllerUnauthorizedCamera(_ scanningViewController: UIViewController) {
        // Add any logic which handles UI when app user doesn't allow usage of the phone's camera
    }

    func scanningViewController(_ scanningViewController: UIViewController, didFindError error: Error) {
        // Can be ignored. See description of the method
    }

    func scanningViewControllerDidClose(_ scanningViewController: UIViewController) {
        // As scanning view controller is presented full screen and modally, dismiss it
        self.dismiss(animated: true, completion: nil)
    }

    func scanningViewController(_ scanningViewController: UIViewController?, didOutputResults results: [PPRecognizerResult]) {

        let scanController : PPScanningViewController = scanningViewController as! PPScanningViewController

        // Here you process scanning results. Scanning results are given in the array of PPRecognizerResult objects.

        // first, pause scanning until we process all the results
        scanController.pauseScanning()

        print("Found something!")

        //present the alert view with scanned results
        let alertView = UIAlertController.init(title: "We found it!", message: "nil", preferredStyle: .alert)
        alertView.show(alertView, sender: self)

    }

    func alertView(alertView: UIAlertView, clickedButtonAtIndex buttonIndex: Int) {
        self.dismiss(animated: true, completion: nil)
    }
}
0awful commented 7 years ago

Fixed it, but figured I would post for other's information.

The fix was to stop coding the rect in terms of a fraction, which yields a fatal error if you do so.

ghost commented 7 years ago

Hi @imizaac, you can still use fractions, but since the values you use are interpreted as integers, the result of the fractions is still an integer thus all values are 0. They need to be floating-points, so your code with fractions should look like this:

let recipientAddressLocation = CGRect.init(x: 85.0/600.0, y: 100.0/900.0, width: 365.0/600.0, height: 85.0/900.0)
let senderAddressLocation = CGRect.init(x: 10.0/600.0, y: 30.0/900.0, width: 260.0/600.0, height: 65.0/900.0)
let weightLocation = CGRect.init(x: 510.0/600.0, y: 30.0/900.0, width: 80.0/600.0, height: 75.0/900.0)
let trackingLocation = CGRect.init(x: 10.0/600.0, y: 430.0/900.0, width: 370.0/600.0, height: 30.0/900.0)

Same thing goes for aspect ratio:

let labelSettings = PPDocumentSpecification.init(aspectRatio: 4.0/6.0, decodingInfo: UPSLabelInfo)

Regards, Jure

0awful commented 7 years ago

Thanks! Marking as closed