Riconoscere il testo nelle immagini con ML Kit su iOS

Puoi utilizzare ML Kit per riconoscere il testo nelle immagini. ML Kit dispone di un'API di uso generale adatta al riconoscimento del testo nelle immagini, ad esempio il testo di un segnale stradale, e di un'API ottimizzata per il riconoscimento del testo dei documenti. L'API per uso generico dispone di modelli basati su cloud e sul dispositivo. Il riconoscimento del testo del documento è disponibile solo come modello basato sul cloud. Consulta la panoramica per un confronto tra i modelli cloud e on-device.

Prima di iniziare

  1. Se non hai ancora aggiunto Firebase alla tua app, fallo seguendo i passaggi della guida introduttiva.
  2. Includi le librerie ML Kit nel tuo Podfile:
    pod 'Firebase/MLVision', '6.25.0'
    # If using an on-device API:
    pod 'Firebase/MLVisionTextModel', '6.25.0'
    
    Dopo aver installato o aggiornato i pod del progetto, assicurati di aprire il progetto Xcode utilizzando il relativo .xcworkspace.
  3. Nella tua app, importa Firebase:

    Swift

    import Firebase

    Objective-C

    @import Firebase;
  4. Se vuoi utilizzare il modello basato su cloud e non hai ancora abilitato le API basate su cloud per il tuo progetto, fallo ora:

    1. Apri la pagina delle API ML Kit della console Firebase.
    2. Se non hai ancora eseguito l'upgrade del tuo progetto a un piano tariffario Blaze, fai clic su Esegui upgrade. Ti verrà chiesto di eseguire l'upgrade solo se il tuo progetto non è incluso nel piano Blaze.

      Solo i progetti di livello Blaze possono utilizzare le API basate sul cloud.

    3. Se le API basate sul cloud non sono già abilitate, fai clic su Abilita API basate sul cloud.

    Se vuoi utilizzare solo il modello sul dispositivo, puoi saltare questo passaggio.

Ora puoi iniziare a riconoscere il testo nelle immagini.

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 dei pixel sufficienti. Idealmente, per il testo latino, ogni carattere dovrebbe essere di almeno 16 x 16 pixel. Per il testo in cinese, giapponese e coreano (supportato solo dalle API basate sul cloud), ogni carattere deve essere 24 x 24 pixel. Per tutte le lingue, in genere non è necessario che i caratteri siano più grandi di 24 x 24 pixel per una maggiore precisione.

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

  • Una messa a fuoco scadente dell'immagine può compromettere l'accuratezza del riconoscimento del testo. Se non ottieni risultati accettabili, chiedi all'utente di acquisire nuovamente l'immagine.

  • Se stai riconoscendo il testo in un'applicazione in tempo reale, potresti anche prendere in considerazione le dimensioni complessive delle immagini di input. Le immagini più piccole possono essere elaborate più velocemente, quindi per ridurre la latenza, acquisisci immagini a risoluzioni inferiori (tenendo presente i requisiti di precisione sopra indicati) e assicurati che il testo occupi la maggior parte dell'immagine possibile. Consulta anche Suggerimenti per migliorare le prestazioni in tempo reale.


Riconosce il testo nelle immagini

Per riconoscere il testo in un'immagine utilizzando un modello basato sul dispositivo o sul cloud, esegui il riconoscimento del testo come descritto di seguito.

1. Eseguire il riconoscimento del testo

Passa l'immagine come `UIImage` o `CMSampleBufferRef` al metodo `process(_:completion:)` di `VisionTextRecognizer`:
  1. Ottieni un'istanza di VisionTextRecognizer chiamando onDeviceTextRecognizer o cloudTextRecognizer:

    Swift

    Per utilizzare il modello sul dispositivo:

    let vision = Vision.vision()
    let textRecognizer = vision.onDeviceTextRecognizer()

    Per utilizzare il modello cloud:

    let vision = Vision.vision()
    let textRecognizer = vision.cloudTextRecognizer()
    
    // Or, to provide language hints to assist with language detection:
    // See https://cloud.google.com/vision/docs/languages for supported languages
    let options = VisionCloudTextRecognizerOptions()
    options.languageHints = ["en", "hi"]
    let textRecognizer = vision.cloudTextRecognizer(options: options)

    Objective-C

    Per utilizzare il modello sul dispositivo:

    FIRVision *vision = [FIRVision vision];
    FIRVisionTextRecognizer *textRecognizer = [vision onDeviceTextRecognizer];

    Per utilizzare il modello cloud:

    FIRVision *vision = [FIRVision vision];
    FIRVisionTextRecognizer *textRecognizer = [vision cloudTextRecognizer];
    
    // Or, to provide language hints to assist with language detection:
    // See https://cloud.google.com/vision/docs/languages for supported languages
    FIRVisionCloudTextRecognizerOptions *options =
            [[FIRVisionCloudTextRecognizerOptions alloc] init];
    options.languageHints = @[@"en", @"hi"];
    FIRVisionTextRecognizer *textRecognizer = [vision cloudTextRecognizerWithOptions:options];
  2. Crea un oggetto VisionImage utilizzando un UIImage o un CMSampleBufferRef.

    Per utilizzare un UIImage:

    1. Se necessario, ruota l'immagine in modo che la proprietà imageOrientation sia .up.
    2. Crea un oggetto VisionImage utilizzando UIImage ruotato correttamente. Non specificare metadati di rotazione. Deve essere utilizzato il valore predefinito .topLeft.

      Swift

      let image = VisionImage(image: uiImage)

      Objective-C

      FIRVisionImage *image = [[FIRVisionImage alloc] initWithImage:uiImage];

    Per utilizzare un CMSampleBufferRef:

    1. Crea un oggetto VisionImageMetadata che specifica l'orientamento dei dati immagine contenuti nel buffer CMSampleBufferRef.

      Per ottenere l'orientamento dell'immagine:

      Swift

      func imageOrientation(
          deviceOrientation: UIDeviceOrientation,
          cameraPosition: AVCaptureDevice.Position
          ) -> VisionDetectorImageOrientation {
          switch deviceOrientation {
          case .portrait:
              return cameraPosition == .front ? .leftTop : .rightTop
          case .landscapeLeft:
              return cameraPosition == .front ? .bottomLeft : .topLeft
          case .portraitUpsideDown:
              return cameraPosition == .front ? .rightBottom : .leftBottom
          case .landscapeRight:
              return cameraPosition == .front ? .topRight : .bottomRight
          case .faceDown, .faceUp, .unknown:
              return .leftTop
          }
      }

      Objective-C

      - (FIRVisionDetectorImageOrientation)
          imageOrientationFromDeviceOrientation:(UIDeviceOrientation)deviceOrientation
                                 cameraPosition:(AVCaptureDevicePosition)cameraPosition {
        switch (deviceOrientation) {
          case UIDeviceOrientationPortrait:
            if (cameraPosition == AVCaptureDevicePositionFront) {
              return FIRVisionDetectorImageOrientationLeftTop;
            } else {
              return FIRVisionDetectorImageOrientationRightTop;
            }
          case UIDeviceOrientationLandscapeLeft:
            if (cameraPosition == AVCaptureDevicePositionFront) {
              return FIRVisionDetectorImageOrientationBottomLeft;
            } else {
              return FIRVisionDetectorImageOrientationTopLeft;
            }
          case UIDeviceOrientationPortraitUpsideDown:
            if (cameraPosition == AVCaptureDevicePositionFront) {
              return FIRVisionDetectorImageOrientationRightBottom;
            } else {
              return FIRVisionDetectorImageOrientationLeftBottom;
            }
          case UIDeviceOrientationLandscapeRight:
            if (cameraPosition == AVCaptureDevicePositionFront) {
              return FIRVisionDetectorImageOrientationTopRight;
            } else {
              return FIRVisionDetectorImageOrientationBottomRight;
            }
          default:
            return FIRVisionDetectorImageOrientationTopLeft;
        }
      }

      Quindi, crea l'oggetto dei metadati:

      Swift

      let cameraPosition = AVCaptureDevice.Position.back  // Set to the capture device you used.
      let metadata = VisionImageMetadata()
      metadata.orientation = imageOrientation(
          deviceOrientation: UIDevice.current.orientation,
          cameraPosition: cameraPosition
      )

      Objective-C

      FIRVisionImageMetadata *metadata = [[FIRVisionImageMetadata alloc] init];
      AVCaptureDevicePosition cameraPosition =
          AVCaptureDevicePositionBack;  // Set to the capture device you used.
      metadata.orientation =
          [self imageOrientationFromDeviceOrientation:UIDevice.currentDevice.orientation
                                       cameraPosition:cameraPosition];
    2. Crea un oggetto VisionImage utilizzando l'oggetto CMSampleBufferRef e i metadati di rotazione:

      Swift

      let image = VisionImage(buffer: sampleBuffer)
      image.metadata = metadata

      Objective-C

      FIRVisionImage *image = [[FIRVisionImage alloc] initWithBuffer:sampleBuffer];
      image.metadata = metadata;
  3. Quindi, passa l'immagine al metodo process(_:completion:):

    Swift

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

    Objective-C

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

2. Estrarre testo da blocchi di testo riconosciuto

Se l'operazione di riconoscimento del testo va a buon fine, viene restituito un oggetto [`VisionText`][VisionText]. Un oggetto `VisionText` contiene il testo completo riconosciuto nell'immagine e zero o più oggetti [`VisionTextBlock`][VisionTextBlock]. Ogni `VisionTextBlock` rappresenta un blocco di testo rettangolare, che contiene zero o più oggetti [`VisionTextLine`][VisionTextLine]. Ogni oggetto `VisionTextLine` contiene zero o più oggetti [`VisionTextElement`][VisionTextElement], che rappresentano parole ed entità simili a parole (date, numeri e così via). Per ogni oggetto `VisionTextBlock`, `VisionTextLine` e `VisionTextElement`, puoi ottenere il testo riconosciuto nella regione e le coordinate del riquadro di selezione della regione. Ad esempio:

Swift

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

Objective-C

NSString *resultText = result.text;
for (FIRVisionTextBlock *block in result.blocks) {
  NSString *blockText = block.text;
  NSNumber *blockConfidence = block.confidence;
  NSArray<FIRVisionTextRecognizedLanguage *> *blockLanguages = block.recognizedLanguages;
  NSArray<NSValue *> *blockCornerPoints = block.cornerPoints;
  CGRect blockFrame = block.frame;
  for (FIRVisionTextLine *line in block.lines) {
    NSString *lineText = line.text;
    NSNumber *lineConfidence = line.confidence;
    NSArray<FIRVisionTextRecognizedLanguage *> *lineLanguages = line.recognizedLanguages;
    NSArray<NSValue *> *lineCornerPoints = line.cornerPoints;
    CGRect lineFrame = line.frame;
    for (FIRVisionTextElement *element in line.elements) {
      NSString *elementText = element.text;
      NSNumber *elementConfidence = element.confidence;
      NSArray<FIRVisionTextRecognizedLanguage *> *elementLanguages = element.recognizedLanguages;
      NSArray<NSValue *> *elementCornerPoints = element.cornerPoints;
      CGRect elementFrame = element.frame;
    }
  }
}

Suggerimenti per migliorare il rendimento in tempo reale

Se vuoi utilizzare il modello on-device per riconoscere il testo in un'applicazione in tempo reale, segui queste linee guida per ottenere i migliori frame rate:

  • Limita le chiamate al sistema di riconoscimento del testo. Se un nuovo frame video diventa disponibile mentre è in esecuzione il riconoscitore di testo, rilascia il frame.
  • Se utilizzi l'output del riconoscitore di testo per sovrapporre elementi grafici all'immagine di input, prima ottieni il risultato da ML Kit, poi esegui il rendering dell'immagine e la sovrapposizione in un unico passaggio. In questo modo, il rendering sulla superficie di visualizzazione viene eseguito una sola volta per ogni frame di input. Per un esempio, consulta le classi previewOverlayView e FIRDetectionOverlayView nell'app di esempio showcase.
  • Valuta la possibilità di acquisire immagini a una risoluzione inferiore. Tuttavia, tieni presente anche i requisiti di dimensione delle immagini di questa API.

Passaggi successivi


Riconoscere il testo nelle immagini dei documenti

Per riconoscere il testo di un documento, configura ed esegui il riconoscitore di testo dei documenti basato su cloud come descritto di seguito.

L'API di riconoscimento del testo del documento, descritta di seguito, fornisce un'interfaccia pensata per semplificare l'utilizzo delle immagini dei documenti. Tuttavia, se preferisci l'interfaccia fornita dall'API Sparse Text, puoi utilizzarla per scansionare i documenti configurando il riconoscitore di testo cloud in modo che utilizzi il modello di testo denso.

Per utilizzare l'API di riconoscimento del testo del documento:

1. Eseguire il riconoscimento del testo

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

  1. Ottieni un'istanza di VisionDocumentTextRecognizer chiamando cloudDocumentTextRecognizer:

    Swift

    let vision = Vision.vision()
    let textRecognizer = vision.cloudDocumentTextRecognizer()
    
    // Or, to provide language hints to assist with language detection:
    // See https://cloud.google.com/vision/docs/languages for supported languages
    let options = VisionCloudDocumentTextRecognizerOptions()
    options.languageHints = ["en", "hi"]
    let textRecognizer = vision.cloudDocumentTextRecognizer(options: options)

    Objective-C

    FIRVision *vision = [FIRVision vision];
    FIRVisionDocumentTextRecognizer *textRecognizer = [vision cloudDocumentTextRecognizer];
    
    // Or, to provide language hints to assist with language detection:
    // See https://cloud.google.com/vision/docs/languages for supported languages
    FIRVisionCloudDocumentTextRecognizerOptions *options =
            [[FIRVisionCloudDocumentTextRecognizerOptions alloc] init];
    options.languageHints = @[@"en", @"hi"];
    FIRVisionDocumentTextRecognizer *textRecognizer = [vision cloudDocumentTextRecognizerWithOptions:options];
  2. Crea un oggetto VisionImage utilizzando un UIImage o un CMSampleBufferRef.

    Per utilizzare un UIImage:

    1. Se necessario, ruota l'immagine in modo che la proprietà imageOrientation sia .up.
    2. Crea un oggetto VisionImage utilizzando UIImage ruotato correttamente. Non specificare metadati di rotazione. Deve essere utilizzato il valore predefinito .topLeft.

      Swift

      let image = VisionImage(image: uiImage)

      Objective-C

      FIRVisionImage *image = [[FIRVisionImage alloc] initWithImage:uiImage];

    Per utilizzare un CMSampleBufferRef:

    1. Crea un oggetto VisionImageMetadata che specifica l'orientamento dei dati immagine contenuti nel buffer CMSampleBufferRef.

      Per ottenere l'orientamento dell'immagine:

      Swift

      func imageOrientation(
          deviceOrientation: UIDeviceOrientation,
          cameraPosition: AVCaptureDevice.Position
          ) -> VisionDetectorImageOrientation {
          switch deviceOrientation {
          case .portrait:
              return cameraPosition == .front ? .leftTop : .rightTop
          case .landscapeLeft:
              return cameraPosition == .front ? .bottomLeft : .topLeft
          case .portraitUpsideDown:
              return cameraPosition == .front ? .rightBottom : .leftBottom
          case .landscapeRight:
              return cameraPosition == .front ? .topRight : .bottomRight
          case .faceDown, .faceUp, .unknown:
              return .leftTop
          }
      }

      Objective-C

      - (FIRVisionDetectorImageOrientation)
          imageOrientationFromDeviceOrientation:(UIDeviceOrientation)deviceOrientation
                                 cameraPosition:(AVCaptureDevicePosition)cameraPosition {
        switch (deviceOrientation) {
          case UIDeviceOrientationPortrait:
            if (cameraPosition == AVCaptureDevicePositionFront) {
              return FIRVisionDetectorImageOrientationLeftTop;
            } else {
              return FIRVisionDetectorImageOrientationRightTop;
            }
          case UIDeviceOrientationLandscapeLeft:
            if (cameraPosition == AVCaptureDevicePositionFront) {
              return FIRVisionDetectorImageOrientationBottomLeft;
            } else {
              return FIRVisionDetectorImageOrientationTopLeft;
            }
          case UIDeviceOrientationPortraitUpsideDown:
            if (cameraPosition == AVCaptureDevicePositionFront) {
              return FIRVisionDetectorImageOrientationRightBottom;
            } else {
              return FIRVisionDetectorImageOrientationLeftBottom;
            }
          case UIDeviceOrientationLandscapeRight:
            if (cameraPosition == AVCaptureDevicePositionFront) {
              return FIRVisionDetectorImageOrientationTopRight;
            } else {
              return FIRVisionDetectorImageOrientationBottomRight;
            }
          default:
            return FIRVisionDetectorImageOrientationTopLeft;
        }
      }

      Quindi, crea l'oggetto dei metadati:

      Swift

      let cameraPosition = AVCaptureDevice.Position.back  // Set to the capture device you used.
      let metadata = VisionImageMetadata()
      metadata.orientation = imageOrientation(
          deviceOrientation: UIDevice.current.orientation,
          cameraPosition: cameraPosition
      )

      Objective-C

      FIRVisionImageMetadata *metadata = [[FIRVisionImageMetadata alloc] init];
      AVCaptureDevicePosition cameraPosition =
          AVCaptureDevicePositionBack;  // Set to the capture device you used.
      metadata.orientation =
          [self imageOrientationFromDeviceOrientation:UIDevice.currentDevice.orientation
                                       cameraPosition:cameraPosition];
    2. Crea un oggetto VisionImage utilizzando l'oggetto CMSampleBufferRef e i metadati di rotazione:

      Swift

      let image = VisionImage(buffer: sampleBuffer)
      image.metadata = metadata

      Objective-C

      FIRVisionImage *image = [[FIRVisionImage alloc] initWithBuffer:sampleBuffer];
      image.metadata = metadata;
  3. Quindi, passa l'immagine al metodo process(_:completion:):

    Swift

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

    Objective-C

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

2. Estrarre testo da blocchi di testo riconosciuto

Se l'operazione di riconoscimento del testo va a buon fine, viene restituito un oggetto VisionDocumentText. Un oggetto VisionDocumentText contiene il testo completo riconosciuto nell'immagine e una gerarchia di oggetti che riflettono la struttura del documento riconosciuto:

Per ogni oggetto VisionDocumentTextBlock, VisionDocumentTextParagraph, VisionDocumentTextWord e VisionDocumentTextSymbol, puoi ottenere il testo riconosciuto nella regione e le coordinate del rettangolo di selezione della regione.

Ad esempio:

Swift

let resultText = result.text
for block in result.blocks {
    let blockText = block.text
    let blockConfidence = block.confidence
    let blockRecognizedLanguages = block.recognizedLanguages
    let blockBreak = block.recognizedBreak
    let blockCornerPoints = block.cornerPoints
    let blockFrame = block.frame
    for paragraph in block.paragraphs {
        let paragraphText = paragraph.text
        let paragraphConfidence = paragraph.confidence
        let paragraphRecognizedLanguages = paragraph.recognizedLanguages
        let paragraphBreak = paragraph.recognizedBreak
        let paragraphCornerPoints = paragraph.cornerPoints
        let paragraphFrame = paragraph.frame
        for word in paragraph.words {
            let wordText = word.text
            let wordConfidence = word.confidence
            let wordRecognizedLanguages = word.recognizedLanguages
            let wordBreak = word.recognizedBreak
            let wordCornerPoints = word.cornerPoints
            let wordFrame = word.frame
            for symbol in word.symbols {
                let symbolText = symbol.text
                let symbolConfidence = symbol.confidence
                let symbolRecognizedLanguages = symbol.recognizedLanguages
                let symbolBreak = symbol.recognizedBreak
                let symbolCornerPoints = symbol.cornerPoints
                let symbolFrame = symbol.frame
            }
        }
    }
}

Objective-C

NSString *resultText = result.text;
for (FIRVisionDocumentTextBlock *block in result.blocks) {
  NSString *blockText = block.text;
  NSNumber *blockConfidence = block.confidence;
  NSArray<FIRVisionTextRecognizedLanguage *> *blockRecognizedLanguages = block.recognizedLanguages;
  FIRVisionTextRecognizedBreak *blockBreak = block.recognizedBreak;
  CGRect blockFrame = block.frame;
  for (FIRVisionDocumentTextParagraph *paragraph in block.paragraphs) {
    NSString *paragraphText = paragraph.text;
    NSNumber *paragraphConfidence = paragraph.confidence;
    NSArray<FIRVisionTextRecognizedLanguage *> *paragraphRecognizedLanguages = paragraph.recognizedLanguages;
    FIRVisionTextRecognizedBreak *paragraphBreak = paragraph.recognizedBreak;
    CGRect paragraphFrame = paragraph.frame;
    for (FIRVisionDocumentTextWord *word in paragraph.words) {
      NSString *wordText = word.text;
      NSNumber *wordConfidence = word.confidence;
      NSArray<FIRVisionTextRecognizedLanguage *> *wordRecognizedLanguages = word.recognizedLanguages;
      FIRVisionTextRecognizedBreak *wordBreak = word.recognizedBreak;
      CGRect wordFrame = word.frame;
      for (FIRVisionDocumentTextSymbol *symbol in word.symbols) {
        NSString *symbolText = symbol.text;
        NSNumber *symbolConfidence = symbol.confidence;
        NSArray<FIRVisionTextRecognizedLanguage *> *symbolRecognizedLanguages = symbol.recognizedLanguages;
        FIRVisionTextRecognizedBreak *symbolBreak = symbol.recognizedBreak;
        CGRect symbolFrame = symbol.frame;
      }
    }
  }
}

Passaggi successivi