Riconoscimento del testo nelle immagini con ML Kit su iOS

Puoi utilizzare ML Kit per riconoscere il testo nelle immagini o nei video, ad esempio il testo di un segnale stradale. Le caratteristiche principali di questa funzionalità sono:

API Text Recognition v2
DescrizioneRiconoscimento del testo in immagini o video, supporto di alfabeti latini, cinesi, devanagari, giapponesi e coreani e di una vasta gamma di lingue.
Nomi SDKGoogleMLKit/TextRecognition
GoogleMLKit/TextRecognitionChinese
GoogleMLKit/TextRecognitionDevanagari
GoogleMLKit/TextRecognitionJapanese
GoogleMLKit/TextRecognitionKorean
ImplementazioneGli asset sono collegati in modo statico alla tua app in fase di compilazione
Impatto delle dimensioni dell'appCirca 38 MB per script SDK
PrestazioniIn tempo reale sulla maggior parte dei dispositivi per l'SDK con script latino, più lento per altri.

Prova

Prima di iniziare

  1. Includi i seguenti pod di ML Kit nel tuo Podfile:
    # To recognize Latin script
    pod 'GoogleMLKit/TextRecognition', '7.0.0'
    # To recognize Chinese script
    pod 'GoogleMLKit/TextRecognitionChinese', '7.0.0'
    # To recognize Devanagari script
    pod 'GoogleMLKit/TextRecognitionDevanagari', '7.0.0'
    # To recognize Japanese script
    pod 'GoogleMLKit/TextRecognitionJapanese', '7.0.0'
    # To recognize Korean script
    pod 'GoogleMLKit/TextRecognitionKorean', '7.0.0'
    
  2. Dopo aver installato o aggiornato i pod del progetto, apri il progetto Xcode utilizzando il relativo .xcworkspace. ML Kit è supportato in Xcode 12.4 o versioni successive.

1. Crea un'istanza di TextRecognizer

Crea un'istanza di TextRecognizer chiamando +textRecognizer(options:), passando le opzioni relative all'SDK dichiarato come dipendenza sopra:

Swift

// When using Latin script recognition SDK
let latinOptions = TextRecognizerOptions()
let latinTextRecognizer = TextRecognizer.textRecognizer(options:options)

// When using Chinese script recognition SDK
let chineseOptions = ChineseTextRecognizerOptions()
let chineseTextRecognizer = TextRecognizer.textRecognizer(options:options)

// When using Devanagari script recognition SDK
let devanagariOptions = DevanagariTextRecognizerOptions()
let devanagariTextRecognizer = TextRecognizer.textRecognizer(options:options)

// When using Japanese script recognition SDK
let japaneseOptions = JapaneseTextRecognizerOptions()
let japaneseTextRecognizer = TextRecognizer.textRecognizer(options:options)

// When using Korean script recognition SDK
let koreanOptions = KoreanTextRecognizerOptions()
let koreanTextRecognizer = TextRecognizer.textRecognizer(options:options)

Objective-C

// When using Latin script recognition SDK
MLKTextRecognizerOptions *latinOptions = [[MLKTextRecognizerOptions alloc] init];
MLKTextRecognizer *latinTextRecognizer = [MLKTextRecognizer textRecognizerWithOptions:options];

// When using Chinese script recognition SDK
MLKChineseTextRecognizerOptions *chineseOptions = [[MLKChineseTextRecognizerOptions alloc] init];
MLKTextRecognizer *chineseTextRecognizer = [MLKTextRecognizer textRecognizerWithOptions:options];

// When using Devanagari script recognition SDK
MLKDevanagariTextRecognizerOptions *devanagariOptions = [[MLKDevanagariTextRecognizerOptions alloc] init];
MLKTextRecognizer *devanagariTextRecognizer = [MLKTextRecognizer textRecognizerWithOptions:options];

// When using Japanese script recognition SDK
MLKJapaneseTextRecognizerOptions *japaneseOptions = [[MLKJapaneseTextRecognizerOptions alloc] init];
MLKTextRecognizer *japaneseTextRecognizer = [MLKTextRecognizer textRecognizerWithOptions:options];

// When using Korean script recognition SDK
MLKKoreanTextRecognizerOptions *koreanOptions = [[MLKKoreanTextRecognizerOptions alloc] init];
MLKTextRecognizer *koreanTextRecognizer = [MLKTextRecognizer textRecognizerWithOptions:options];

2. Prepara l'immagine di input

Passa l'immagine come UIImage o CMSampleBufferRef al metodo process(_:completion:) di TextRecognizer:

Crea un oggetto VisionImage utilizzando un UIImage o un CMSampleBuffer.

Se utilizzi un UIImage, segui questi passaggi:

  • Crea un oggetto VisionImage con UIImage. Assicurati di specificare il valore .orientation corretto.

    Swift

    let image = VisionImage(image: UIImage)
    visionImage.orientation = image.imageOrientation

    Objective-C

    MLKVisionImage *visionImage = [[MLKVisionImage alloc] initWithImage:image];
    visionImage.orientation = image.imageOrientation;

Se utilizzi un CMSampleBuffer, segui questi passaggi:

  • Specifica l'orientamento dei dati dell'immagine contenuti in CMSampleBuffer.

    Per ottenere l'orientamento dell'immagine:

    Swift

    func imageOrientation(
      deviceOrientation: UIDeviceOrientation,
      cameraPosition: AVCaptureDevice.Position
    ) -> UIImage.Orientation {
      switch deviceOrientation {
      case .portrait:
        return cameraPosition == .front ? .leftMirrored : .right
      case .landscapeLeft:
        return cameraPosition == .front ? .downMirrored : .up
      case .portraitUpsideDown:
        return cameraPosition == .front ? .rightMirrored : .left
      case .landscapeRight:
        return cameraPosition == .front ? .upMirrored : .down
      case .faceDown, .faceUp, .unknown:
        return .up
      }
    }
          

    Objective-C

    - (UIImageOrientation)
      imageOrientationFromDeviceOrientation:(UIDeviceOrientation)deviceOrientation
                             cameraPosition:(AVCaptureDevicePosition)cameraPosition {
      switch (deviceOrientation) {
        case UIDeviceOrientationPortrait:
          return cameraPosition == AVCaptureDevicePositionFront ? UIImageOrientationLeftMirrored
                                                                : UIImageOrientationRight;
    
        case UIDeviceOrientationLandscapeLeft:
          return cameraPosition == AVCaptureDevicePositionFront ? UIImageOrientationDownMirrored
                                                                : UIImageOrientationUp;
        case UIDeviceOrientationPortraitUpsideDown:
          return cameraPosition == AVCaptureDevicePositionFront ? UIImageOrientationRightMirrored
                                                                : UIImageOrientationLeft;
        case UIDeviceOrientationLandscapeRight:
          return cameraPosition == AVCaptureDevicePositionFront ? UIImageOrientationUpMirrored
                                                                : UIImageOrientationDown;
        case UIDeviceOrientationUnknown:
        case UIDeviceOrientationFaceUp:
        case UIDeviceOrientationFaceDown:
          return UIImageOrientationUp;
      }
    }
          
  • Crea un oggetto VisionImage utilizzando l'orientamento e l'oggetto CMSampleBuffer:

    Swift

    let image = VisionImage(buffer: sampleBuffer)
    image.orientation = imageOrientation(
      deviceOrientation: UIDevice.current.orientation,
      cameraPosition: cameraPosition)

    Objective-C

     MLKVisionImage *image = [[MLKVisionImage alloc] initWithBuffer:sampleBuffer];
     image.orientation =
       [self imageOrientationFromDeviceOrientation:UIDevice.currentDevice.orientation
                                    cameraPosition:cameraPosition];

3. Elabora l'immagine

Quindi, passa l'immagine al metodo process(_:completion:):

Swift

textRecognizer.process(visionImage) { result, error in
  guard error == nil, let result = result else {
    // Error handling
    return
  }
  // Recognized text
}

Objective-C

[textRecognizer processImage:image
                  completion:^(MLKText *_Nullable result,
                               NSError *_Nullable error) {
  if (error != nil || result == nil) {
    // Error handling
    return;
  }
  // Recognized text
}];

4. Estrarre il testo da blocchi di testo riconosciuto

Se l'operazione di riconoscimento del testo va a buon fine, viene restituito un oggetto Text. Un oggetto Text contiene il testo completo riconosciuto nell'immagine e zero o più oggetti TextBlock.

Ogni TextBlock rappresenta un blocco di testo rettangolare che contiene zero o più oggetti TextLine. Ogni oggetto TextLine contiene zero o più oggetti TextElement, che rappresentano parole ed entità simili a parole come date e numeri.

Per ogni oggetto TextBlock, TextLine e TextElement, puoi ottenere il testo riconosciuto nella regione e le coordinate di confine della regione.

Ad esempio:

Swift

let resultText = result.text
for block in result.blocks {
    let blockText = block.text
    let blockLanguages = block.recognizedLanguages
    let blockCornerPoints = block.cornerPoints
    let blockFrame = block.frame
    for line in block.lines {
        let lineText = line.text
        let lineLanguages = line.recognizedLanguages
        let lineCornerPoints = line.cornerPoints
        let lineFrame = line.frame
        for element in line.elements {
            let elementText = element.text
            let elementCornerPoints = element.cornerPoints
            let elementFrame = element.frame
        }
    }
}

Objective-C

NSString *resultText = result.text;
for (MLKTextBlock *block in result.blocks) {
  NSString *blockText = block.text;
  NSArray<MLKTextRecognizedLanguage *> *blockLanguages = block.recognizedLanguages;
  NSArray<NSValue *> *blockCornerPoints = block.cornerPoints;
  CGRect blockFrame = block.frame;
  for (MLKTextLine *line in block.lines) {
    NSString *lineText = line.text;
    NSArray<MLKTextRecognizedLanguage *> *lineLanguages = line.recognizedLanguages;
    NSArray<NSValue *> *lineCornerPoints = line.cornerPoints;
    CGRect lineFrame = line.frame;
    for (MLKTextElement *element in line.elements) {
      NSString *elementText = element.text;
      NSArray<NSValue *> *elementCornerPoints = element.cornerPoints;
      CGRect elementFrame = element.frame;
    }
  }
}

Linee guida per le immagini di input

  • Affinché ML Kit riconosca con precisione il testo, le immagini di input devono contenere testo rappresentato da dati di pixel sufficienti. Idealmente, ogni carattere deve essere di almeno 16 x 16 pixel. In genere, non c'è alcun vantaggio in termini di accuratezza se i caratteri sono più grandi di 24 x 24 pixel.

    Ad esempio, un'immagine di 640 x 480 potrebbe essere adatta per la scansione di un biglietto da visita che occupa l'intera larghezza dell'immagine. Per eseguire la scansione di un documento stampato su carta in formato lettera, potrebbe essere necessaria un'immagine di 720 x 1280 pixel.

  • La scarsa messa a fuoco delle immagini può influire sull'accuratezza del riconoscimento del testo. Se non ottieni risultati accettabili, prova a chiedere all'utente di acquisire di nuovo l'immagine.

  • Se stai riconoscendo il testo in un'applicazione in tempo reale, devi prendere in considerazione le dimensioni complessive delle immagini di input. Le immagini più piccole possono essere elaborate più velocemente. Per ridurre la latenza, assicurati che il testo occupi il maggior spazio possibile dell'immagine e acquisisci le immagini a risoluzioni inferiori (tenendo presente i requisiti di accuratezza sopra indicati). Per ulteriori informazioni, consulta Suggerimenti per migliorare il rendimento.

Suggerimenti per migliorare il rendimento

  • Per l'elaborazione dei frame video, utilizza l'API sincrona results(in:) del rilevatore. Chiama questo metodo dalla funzione captureOutput(_, didOutput:from:) di AVCaptureVideoDataOutputSampleBufferDelegate per ottenere in modo sincrono i risultati dal frame video fornito. Mantieni alwaysDiscardsLateVideoFrames di AVCaptureVideoDataOutput come true per limitare le chiamate al rilevatore. Se un nuovo frame video diventa disponibile durante l'esecuzione del rilevatore, verrà eliminato.
  • Se utilizzi l'output del rilevatore per sovrapporre la grafica all'immagine di input, ottieni prima il risultato da ML Kit, poi esegui il rendering dell'immagine e la sovrapposizione in un unico passaggio. In questo modo, esegui il rendering sulla superficie di visualizzazione solo una volta per ogni frame di input elaborato. Per un esempio, consulta updatePreviewOverlayViewWithLastFrame nell'esempio di avvio rapido di ML Kit.
  • Valuta la possibilità di acquisire le immagini a una risoluzione inferiore. Tuttavia, tieni presente anche i requisiti relativi alle dimensioni delle immagini di questa API.
  • Per evitare un potenziale calo delle prestazioni, non eseguire contemporaneamente più istanze di TextRecognizer con opzioni di script diverse.