58 votes

Conversion d'une vision VNTextObservation en chaîne

Je suis à la recherche par le biais de la Pomme de Vision documentation de l'API , et je vois un couple de classes qui se rapportent à la détection de textes en UIImages:

1) class VNDetectTextRectanglesRequest

2) class VNTextObservation

On dirait qu'ils peuvent détecter des personnages, mais je ne vois pas un moyen de faire quoi que ce soit avec les personnages. Une fois que vous avez caractères détecté, comment vous y prendriez-vous de les transformer en quelque chose qui peut être interprété par NSLinguisticTagger?

Voici un post qui est un bref aperçu de l' Vision.

Merci pour la lecture.

15voto

DrNeurosurg Points 101

Voici comment le faire ...

     //
//  ViewController.swift
//


import UIKit
import Vision
import CoreML

class ViewController: UIViewController {

    //HOLDS OUR INPUT
    var  inputImage:CIImage?

    //RESULT FROM OVERALL RECOGNITION
    var  recognizedWords:[String] = [String]()

    //RESULT FROM RECOGNITION
    var recognizedRegion:String = String()


    //OCR-REQUEST
    lazy var ocrRequest: VNCoreMLRequest = {
        do {
            //THIS MODEL IS TRAINED BY ME FOR FONT "Inconsolata" (Numbers 0...9 and UpperCase Characters A..Z)
            let model = try VNCoreMLModel(for:OCR().model)
            return VNCoreMLRequest(model: model, completionHandler: self.handleClassification)
        } catch {
            fatalError("cannot load model")
        }
    }()

    //OCR-HANDLER
    func handleClassification(request: VNRequest, error: Error?)
    {
        guard let observations = request.results as? [VNClassificationObservation]
            else {fatalError("unexpected result") }
        guard let best = observations.first
            else { fatalError("cant get best result")}

        self.recognizedRegion = self.recognizedRegion.appending(best.identifier)
    }

    //TEXT-DETECTION-REQUEST
    lazy var textDetectionRequest: VNDetectTextRectanglesRequest = {
        return VNDetectTextRectanglesRequest(completionHandler: self.handleDetection)
    }()

    //TEXT-DETECTION-HANDLER
    func handleDetection(request:VNRequest, error: Error?)
    {
        guard let observations = request.results as? [VNTextObservation]
            else {fatalError("unexpected result") }

       // EMPTY THE RESULTS
        self.recognizedWords = [String]()

        //NEEDED BECAUSE OF DIFFERENT SCALES
        let  transform = CGAffineTransform.identity.scaledBy(x: (self.inputImage?.extent.size.width)!, y:  (self.inputImage?.extent.size.height)!)

        //A REGION IS LIKE A "WORD"
        for region:VNTextObservation in observations
        {
            guard let boxesIn = region.characterBoxes else {
                continue
            }

            //EMPTY THE RESULT FOR REGION
            self.recognizedRegion = ""

            //A "BOX" IS THE POSITION IN THE ORIGINAL IMAGE (SCALED FROM 0... 1.0)
            for box in boxesIn
            {
                //SCALE THE BOUNDING BOX TO PIXELS
                let realBoundingBox = box.boundingBox.applying(transform)

                //TO BE SURE
                guard (inputImage?.extent.contains(realBoundingBox))!
                    else { print("invalid detected rectangle"); return}

                //SCALE THE POINTS TO PIXELS
                let topleft = box.topLeft.applying(transform)
                let topright = box.topRight.applying(transform)
                let bottomleft = box.bottomLeft.applying(transform)
                let bottomright = box.bottomRight.applying(transform)

                //LET'S CROP AND RECTIFY
                let charImage = inputImage?
                    .cropped(to: realBoundingBox)
                    .applyingFilter("CIPerspectiveCorrection", parameters: [
                        "inputTopLeft" : CIVector(cgPoint: topleft),
                        "inputTopRight" : CIVector(cgPoint: topright),
                        "inputBottomLeft" : CIVector(cgPoint: bottomleft),
                        "inputBottomRight" : CIVector(cgPoint: bottomright)
                        ])

                //PREPARE THE HANDLER
                let handler = VNImageRequestHandler(ciImage: charImage!, options: [:])

                //SOME OPTIONS (TO PLAY WITH..)
                self.ocrRequest.imageCropAndScaleOption = VNImageCropAndScaleOption.scaleFill

                //FEED THE CHAR-IMAGE TO OUR OCR-REQUEST - NO NEED TO SCALE IT - VISION WILL DO IT FOR US !!
                do {
                    try handler.perform([self.ocrRequest])
                }  catch { print("Error")}

            }

            //APPEND RECOGNIZED CHARS FOR THAT REGION
            self.recognizedWords.append(recognizedRegion)
        }

        //THATS WHAT WE WANT - PRINT WORDS TO CONSOLE
        DispatchQueue.main.async {
            self.PrintWords(words: self.recognizedWords)
        }
    }

    func PrintWords(words:[String])
    {
        // VOILA'
        print(recognizedWords)

    }

    func doOCR(ciImage:CIImage)
    {
        //PREPARE THE HANDLER
        let handler = VNImageRequestHandler(ciImage: ciImage, options:[:])

        //WE NEED A BOX FOR EACH DETECTED CHARACTER
        self.textDetectionRequest.reportCharacterBoxes = true
        self.textDetectionRequest.preferBackgroundProcessing = false

        //FEED IT TO THE QUEUE FOR TEXT-DETECTION
        DispatchQueue.global(qos: .userInteractive).async {
            do {
                try  handler.perform([self.textDetectionRequest])
            } catch {
                print ("Error")
            }
        }

    }

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        //LETS LOAD AN IMAGE FROM RESOURCE
        let loadedImage:UIImage = UIImage(named: "Sample1.png")! //TRY Sample2, Sample3 too

        //WE NEED A CIIMAGE - NOT NEEDED TO SCALE
        inputImage = CIImage(image:loadedImage)!

        //LET'S DO IT
        self.doOCR(ciImage: inputImage!)


    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}
 

Vous trouverez le projet complet ici inclus est le modèle formé!

13voto

brian.clear Points 2424

SwiftOCR

Je viens de recevoir SwiftOCR de travailler avec de petits ensembles de texte.

https://github.com/garnele007/SwiftOCR

utilise

https://github.com/Swift-AI/Swift-AI

qui utilise NeuralNet-MNIST modèle pour la reconnaissance de texte.

TODO : VNTextObservation > SwiftOCR

Afficherons exemple de l'aide VNTextObservation une fois que je l'ai connecté à l'autre.

OpenCV + Tesseract OCR

J'ai essayé d'utiliser OpenCV + Tesseract, mais a eu des erreurs de compilation alors trouvé SwiftOCR.

VOIR AUSSI : Google Vision iOS

Remarque: Google Vision de Reconnaissance de Texte - Android sdk a la détection de textes, mais aussi a iOS cocoapod. Afin de garder un œil sur ce que devrait ajouter du texte sur la reconnaissance de l'iOS finalement.

https://developers.google.com/vision/text-overview

//Correction: juste essayé, mais seulement Android version du sdk prend en charge la détection de textes.

https://developers.google.com/vision/text-overview

Si vous vous abonnez à des communiqués de: https://libraries.io/cocoapods/GoogleMobileVision

Cliquez sur s'ABONNER AUX COMMUNIQUÉS de vous pouvez voir quand TextDetection est ajouté à iOS partie de la Cocoapod

10voto

Dimillian77 Points 816

Ajouter mes propres progrès sur ce, si quelqu'un a une meilleure solution:

J'ai été attiré la région de la boîte et le caractère cases à l'écran. La vision de l'API d'Apple est en fait très performant. Vous avez à transformer chaque image de votre vidéo sur une image et de le nourrir pour le logiciel de reconnaissance. C'est beaucoup plus précis que de se nourrir directement les pixels de la mémoire tampon de l'appareil photo.

 if #available(iOS 11.0, *) {
            guard let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else {return}

            var requestOptions:[VNImageOption : Any] = [:]

            if let camData = CMGetAttachment(sampleBuffer, kCMSampleBufferAttachmentKey_CameraIntrinsicMatrix, nil) {
                requestOptions = [.cameraIntrinsics:camData]
            }

            let imageRequestHandler = VNImageRequestHandler(cvPixelBuffer: pixelBuffer,
                                                            orientation: 6,
                                                            options: requestOptions)

            let request = VNDetectTextRectanglesRequest(completionHandler: { (request, _) in
                guard let observations = request.results else {print("no result"); return}
                let result = observations.map({$0 as? VNTextObservation})
                DispatchQueue.main.async {
                    self.previewLayer.sublayers?.removeSubrange(1...)
                    for region in result {
                        guard let rg = region else {continue}
                        self.drawRegionBox(box: rg)
                        if let boxes = region?.characterBoxes {
                            for characterBox in boxes {
                                self.drawTextBox(box: characterBox)
                            }
                        }
                    }
                }
            })
            request.reportCharacterBoxes = true
            try? imageRequestHandler.perform([request])
        }
    }

Maintenant, je suis en train de réellement reconize le texte. Apple ne fournit pas construit dans le ROC modèle. Et je veux utiliser CoreML à le faire, donc je suis en train de convertir un Tesseract formés modèle de données pour CoreML.

Vous pouvez trouver Tesseract modèles ici: https://github.com/tesseract-ocr/tessdata et je pense que la prochaine étape est d'écrire un coremltools convertisseur qui prennent en charge ce type d'entrée et de sortie d'une .coreML fichier.

Ou, vous pouvez faire un lien vers TesseractiOS directement et essayer de l'alimenter avec votre région de boîtes et de caractère cases que vous obtenez à partir de la Vision de l'API.

3voto

nathan Points 5502

Grâce à un GitHub de l'utilisateur, vous pouvez tester un exemple: https://gist.github.com/Koze/e59fa3098388265e578dee6b3ce89dd8

- (void)detectWithImageURL:(NSURL *)URL
{
    VNImageRequestHandler *handler = [[VNImageRequestHandler alloc] initWithURL:URL options:@{}];
    VNDetectTextRectanglesRequest *request = [[VNDetectTextRectanglesRequest alloc] initWithCompletionHandler:^(VNRequest * _Nonnull request, NSError * _Nullable error) {
        if (error) {
            NSLog(@"%@", error);
        }
        else {
            for (VNTextObservation *textObservation in request.results) {
//                NSLog(@"%@", textObservation);
//                NSLog(@"%@", textObservation.characterBoxes);
                NSLog(@"%@", NSStringFromCGRect(textObservation.boundingBox));
                for (VNRectangleObservation *rectangleObservation in textObservation.characterBoxes) {
                    NSLog(@" |-%@", NSStringFromCGRect(rectangleObservation.boundingBox));
                }
            }
        }
    }];
    request.reportCharacterBoxes = YES;
    NSError *error;
    [handler performRequests:@[request] error:&error];
    if (error) {
        NSLog(@"%@", error);
    }
}

La chose est, le résultat est un tableau de cases pour chaque détecté caractère. De ce que j'ai recueillies à partir de la Vision de la session, je pense que vous êtes supposé utiliser CoreML pour détecter les caractères.

Recommandé WWDC 2017 parler: la Vision du Cadre: Construction sur la Base ML (n'ont pas fini de regarder il soit), ont un oeil à 25:50 pour un exemple similaire appelé MNISTVision

Voici un autre chouette app démontrant l'utilisation de Keras (Tensorflow) pour la formation d'un MNIST modèle pour la reconnaissance de l'écriture manuscrite à l'aide de CoreML: Github

2voto

Foti Dim Points 714

Firebase ML Kit le fait pour iOS (et Android) avec leur API Vision sur périphérique et surpasse Tesseract et SwiftOCR.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X