machine learning kit googlenetplaces developer create apple ios machine-learning ocr nslinguistictagger apple-vision

ios - googlenetplaces - machine learning kit apple



Conversión de Vision VNTextObservation en una cadena (8)

Estoy revisando la documentación de la API Vision de Apple y veo un par de clases relacionadas con la detección de texto en UIImages :

1) class VNDetectTextRectanglesRequest

2) class VNTextObservation

Parece que pueden detectar personajes, pero no veo un medio para hacer nada con los personajes. Una vez que hayas detectado personajes, ¿cómo harías para convertirlos en algo que NSLinguisticTagger pueda interpretar?

Aquí hay una publicación que es una breve descripción de Vision .

Gracias por leer.


Agregando mi propio progreso en esto, si alguien tiene una mejor solución:

Dibujé con éxito el cuadro de región y los cuadros de caracteres en la pantalla. La visión API de Apple es realmente muy eficiente. Tienes que transformar cada fotograma de tu video en una imagen y alimentarlo al reconocedor. Es mucho más preciso que alimentar directamente el búfer de píxeles desde la cámara.

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]) } }

Ahora estoy tratando de reconciliar el texto. Apple no proporciona ningún modelo OCR integrado. Y quiero usar CoreML para hacer eso, así que estoy tratando de convertir un modelo de datos capacitados de Tesseract a CoreML.

Puede encontrar modelos de Tesseract aquí: https://github.com/tesseract-ocr/tessdata y creo que el siguiente paso es escribir un convertidor de coremltools que admita ese tipo de entrada y salida de un archivo .coreML.

O bien, puede vincular directamente a TesseractiOS e intentar alimentarlo con sus cuadros de región y cuadros de caracteres que obtiene de la API de Vision.


Apple finalmente actualizó Vision para hacer OCR. Abra un patio de juegos y descargue un par de imágenes de prueba en la carpeta Recursos. En mi caso, los llamé "demoDocument.jpg" y "demoLicensePlate.jpg".

La nueva clase se llama VNRecognizeTextRequest . Vuelca esto en un patio de juegos y dale un giro:

import Vision enum DemoImage: String { case document = "demoDocument" case licensePlate = "demoLicensePlate" } class OCRReader { func performOCR(on url: URL?, recognitionLevel: VNRequestTextRecognitionLevel) { guard let url = url else { return } let requestHandler = VNImageRequestHandler(url: url, options: [:]) let request = VNRecognizeTextRequest { (request, error) in if let error = error { print(error) return } guard let observations = request.results as? [VNRecognizedTextObservation] else { return } for currentObservation in observations { let topCandidate = currentObservation.topCandidates(1) if let recognizedText = topCandidate.first { print(recognizedText.string) } } } request.recognitionLevel = recognitionLevel try? requestHandler.perform([request]) } } func url(for image: DemoImage) -> URL? { return Bundle.main.url(forResource: image.rawValue, withExtension: "jpg") } let ocrReader = OCRReader() ocrReader.performOCR(on: url(for: .document), recognitionLevel: .fast)

Hay una discusión en profundidad de esto de WWDC19


Asi es como se hace ...

// // 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. } }

¡Encontrarás que el proyecto completo here incluido es el modelo entrenado!


Estoy usando el motor Tesseract OCR de Google para convertir las imágenes en cadenas reales. Tendrás que agregarlo a tu proyecto Xcode usando cocoapods. Aunque Tesseract realizará OCR incluso si simplemente le alimenta la imagen que contiene textos, la forma de hacerlo funcionar mejor / más rápido es usar los rectángulos de texto detectados para alimentar piezas de la imagen que realmente contienen texto, que es donde se encuentra el Marco de visión de Apple Viene muy bien. Aquí hay un enlace al motor: Tesseract OCR Y aquí hay un enlace a la etapa actual de mi proyecto que ya tiene implementada la detección de texto + OCR: Out Loud - Camera to Speech Espero que estos puedan ser de alguna utilidad. ¡Buena suerte!


Firebase ML Kit lo hace para iOS (y Android) con su API de visión en el dispositivo y supera a Tesseract y SwiftOCR.


Gracias a un usuario de GitHub, puede probar un ejemplo: 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 cuestión es que el resultado es una matriz de cuadros delimitadores para cada carácter detectado. Por lo que deduje de la sesión de Vision, creo que se supone que debes usar CoreML para detectar los caracteres reales.

Charla recomendada de WWDC 2017: Marco de visión: Construir en Core ML (tampoco he terminado de verlo), eche un vistazo a 25:50 para ver un ejemplo similar llamado MNISTVision

Aquí hay otra aplicación ingeniosa que demuestra el uso de Keras (Tensorflow) para la capacitación de un modelo MNIST para el reconocimiento de escritura a mano usando CoreML : Github


Para aquellos que todavía buscan una solución, escribí una library rápida para hacer esto. Utiliza tanto la API de Vision como Tesseract y puede usarse para lograr la tarea que la pregunta describe con un solo método:

func sliceaAndOCR(image: UIImage, charWhitelist: String, charBlackList: String = "", completion: @escaping ((_: String, _: UIImage) -> Void))

Este método buscará texto en su imagen, devolverá la cadena encontrada y una porción de la imagen original que muestra dónde se encontró el texto


SwiftOCR

Acabo de hacer que SwiftOCR trabaje con pequeños conjuntos de texto.

https://github.com/garnele007/SwiftOCR

usos

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

que usa el modelo NeuralNet-MNIST para el reconocimiento de texto.

TODO: VNTextObservation> SwiftOCR

Publicaré un ejemplo de esto usando VNTextObservation una vez que tenga uno conectado al otro.

OpenCV + Tesseract OCR

Intenté usar OpenCV + Tesseract pero obtuve errores de compilación y luego encontré SwiftOCR.

VEA TAMBIÉN: Google Vision iOS

Nota Reconocimiento de texto de Google Vision: el SDK de Android tiene detección de texto pero también tiene cocoapod iOS. Esté atento, ya que eventualmente debería agregar reconocimiento de texto al iOS.

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

// Corrección: lo probé pero solo la versión de Android del SDK admite la detección de texto.

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

Si se suscribe a lanzamientos: https://libraries.io/cocoapods/GoogleMobileVision

Haga clic en SUSCRIBIRSE A LOS LANZAMIENTOS que puede ver cuando TextDetection se agrega a la parte de iOS de Cocoapod