Puoi utilizzare ML Kit per riconoscere il testo nelle immagini. ML Kit dispone sia di un'API generica adatta al riconoscimento del testo nelle immagini, come il testo di un segnale stradale, sia di un'API ottimizzata per il riconoscimento del testo dei documenti. L'API generica dispone sia di modelli su dispositivo che basati su cloud. Il riconoscimento del testo del documento è disponibile solo come modello basato su cloud. Consulta la panoramica per un confronto tra i modelli cloud e on-device.
Prima di iniziare
- Se non hai già aggiunto Firebase alla tua app, fallo seguendo i passaggi nella guida introduttiva .
- 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 tuo progetto, assicurati di aprire il tuo progetto Xcode utilizzando il relativo.xcworkspace
. - Nella tua app, importa Firebase:
Veloce
import Firebase
Obiettivo-C
@import Firebase;
Se desideri utilizzare il modello basato su cloud e non hai già abilitato le API basate su cloud per il tuo progetto, fallo ora:
- Apri la pagina API ML Kit della console Firebase.
Se non hai già aggiornato il tuo progetto a un piano tariffario Blaze, fai clic su Aggiorna per farlo. (Ti verrà richiesto di eseguire l'aggiornamento solo se il tuo progetto non è incluso nel piano Blaze.)
Solo i progetti a livello di Blaze possono utilizzare API basate su cloud.
- Se le API basate su cloud non sono già abilitate, fai clic su Abilita API basate su cloud .
Se desideri utilizzare solo il modello su dispositivo, puoi saltare questo passaggio.
Ora sei pronto per iniziare a riconoscere il testo nelle immagini.
Inserisci le linee guida per l'immagine
Affinché ML Kit riconosca con precisione il testo, le immagini di input devono contenere testo rappresentato da dati pixel sufficienti. Idealmente, per il testo latino, ogni carattere dovrebbe essere di almeno 16x16 pixel. Per il testo cinese, giapponese e coreano (supportato solo dalle API basate su cloud), ogni carattere deve essere di 24x24 pixel. Per tutte le lingue, in genere non vi è alcun vantaggio in termini di precisione se i caratteri sono più grandi di 24x24 pixel.
Quindi, ad esempio, un'immagine 640x480 potrebbe funzionare bene per scansionare 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 da 720x1280 pixel.
Una scarsa messa a fuoco dell'immagine può compromettere la precisione del riconoscimento del testo. Se non ottieni risultati accettabili, prova a chiedere all'utente di acquisire nuovamente l'immagine.
Se stai riconoscendo il testo in un'applicazione in tempo reale, potresti anche voler considerare le dimensioni complessive delle immagini di input. Le immagini più piccole possono essere elaborate più velocemente, quindi per ridurre la latenza, acquisire immagini a risoluzioni inferiori (tenendo presente i requisiti di precisione di cui sopra) e garantire che il testo occupi la maggior parte possibile dell'immagine. Vedi anche Suggerimenti per migliorare le prestazioni in tempo reale .
Riconoscere il testo nelle immagini
Per riconoscere il testo in un'immagine utilizzando un modello sul dispositivo o basato su cloud, esegui il riconoscimento del testo come descritto di seguito.
1. Esegui il riconoscimento del testo
Passa l'immagine come "UIImage" o "CMSampleBufferRef" al metodo "process(_:completion:)" di "VisionTextRecognizer":- Ottieni un'istanza di
VisionTextRecognizer
chiamandoonDeviceTextRecognizer
ocloudTextRecognizer
:Veloce
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)
Obiettivo-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];
Crea un oggetto
VisionImage
utilizzandoUIImage
oCMSampleBufferRef
.Per utilizzare un'immagine
UIImage
:- Se necessario, ruotare l'immagine in modo che la relativa proprietà
imageOrientation
sia.up
. - Crea un oggetto
VisionImage
utilizzandoUIImage
ruotato correttamente. Non specificare alcun metadato di rotazione: è necessario utilizzare il valore predefinito,.topLeft
.Veloce
let image = VisionImage(image: uiImage)
Obiettivo-C
FIRVisionImage *image = [[FIRVisionImage alloc] initWithImage:uiImage];
Per utilizzare un
CMSampleBufferRef
:Crea un oggetto
VisionImageMetadata
che specifica l'orientamento dei dati dell'immagine contenuti nel bufferCMSampleBufferRef
.Per ottenere l'orientamento dell'immagine:
Veloce
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 } }
Obiettivo-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 metadati:
Veloce
let cameraPosition = AVCaptureDevice.Position.back // Set to the capture device you used. let metadata = VisionImageMetadata() metadata.orientation = imageOrientation( deviceOrientation: UIDevice.current.orientation, cameraPosition: cameraPosition )
Obiettivo-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];
- Crea un oggetto
VisionImage
utilizzando l'oggettoCMSampleBufferRef
e i metadati di rotazione:Veloce
let image = VisionImage(buffer: sampleBuffer) image.metadata = metadata
Obiettivo-C
FIRVisionImage *image = [[FIRVisionImage alloc] initWithBuffer:sampleBuffer]; image.metadata = metadata;
- Se necessario, ruotare l'immagine in modo che la relativa proprietà
- Quindi, passa l'immagine al metodo
process(_:completion:)
:Veloce
textRecognizer.process(visionImage) { result, error in guard error == nil, let result = result else { // ... return } // Recognized text }
Obiettivo-C
[textRecognizer processImage:image completion:^(FIRVisionText *_Nullable result, NSError *_Nullable error) { if (error != nil || result == nil) { // ... return; } // Recognized text }];
2. Estrarre il testo da blocchi di testo riconosciuto
Se l'operazione di riconoscimento del testo ha esito positivo, restituirà 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 rettangolare di testo, 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 di delimitazione della regione. Per esempio:Veloce
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 } } }
Obiettivo-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 le prestazioni in tempo reale
Se desideri utilizzare il modello su dispositivo per riconoscere il testo in un'applicazione in tempo reale, segui queste linee guida per ottenere i migliori framerate:
- Limita le chiamate al riconoscimento del testo. Se un nuovo fotogramma video diventa disponibile mentre il riconoscimento del testo è in esecuzione, rilascia il fotogramma.
- Se stai utilizzando l'output del riconoscimento del testo per sovrapporre la grafica all'immagine di input, ottieni prima il risultato da ML Kit, quindi esegui il rendering dell'immagine e della sovrapposizione in un unico passaggio. In questo modo, viene eseguito il rendering sulla superficie di visualizzazione solo una volta per ciascun fotogramma di input. Per un esempio, vedi le classi PreviewOverlayView e FIRDetectionOverlayView nell'app di esempio vetrina.
- Considera l'idea di acquisire immagini con una risoluzione inferiore. Tuttavia, tieni presente anche i requisiti relativi alla dimensione dell'immagine di questa API.
Prossimi passi
- Prima di distribuire in produzione un'app che utilizza un'API cloud, dovresti adottare alcune misure aggiuntive per prevenire e mitigare gli effetti dell'accesso API non autorizzato .
Riconoscere il testo nelle immagini dei documenti
Per riconoscere il testo di un documento, configurare ed eseguire il riconoscimento del testo del documento basato su cloud come descritto di seguito.
L'API di riconoscimento del testo del documento, descritta di seguito, fornisce un'interfaccia pensata per essere più comoda per lavorare con le immagini dei documenti. Tuttavia, se preferisci l'interfaccia fornita dall'API di testo sparse, puoi utilizzarla invece per scansionare documenti configurando il riconoscimento del testo cloud per utilizzare il modello di testo denso .
Per utilizzare l'API di riconoscimento del testo del documento:
1. Esegui il riconoscimento del testo
Passa l'immagine comeUIImage
o CMSampleBufferRef
al metodo process(_:completion:)
di VisionDocumentTextRecognizer
:- Ottieni un'istanza di
VisionDocumentTextRecognizer
chiamandocloudDocumentTextRecognizer
:Veloce
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)
Obiettivo-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];
Crea un oggetto
VisionImage
utilizzandoUIImage
oCMSampleBufferRef
.Per utilizzare un'immagine
UIImage
:- Se necessario, ruotare l'immagine in modo che la relativa proprietà
imageOrientation
sia.up
. - Crea un oggetto
VisionImage
utilizzandoUIImage
ruotato correttamente. Non specificare alcun metadato di rotazione: è necessario utilizzare il valore predefinito,.topLeft
.Veloce
let image = VisionImage(image: uiImage)
Obiettivo-C
FIRVisionImage *image = [[FIRVisionImage alloc] initWithImage:uiImage];
Per utilizzare un
CMSampleBufferRef
:Crea un oggetto
VisionImageMetadata
che specifica l'orientamento dei dati dell'immagine contenuti nel bufferCMSampleBufferRef
.Per ottenere l'orientamento dell'immagine:
Veloce
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 } }
Obiettivo-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 metadati:
Veloce
let cameraPosition = AVCaptureDevice.Position.back // Set to the capture device you used. let metadata = VisionImageMetadata() metadata.orientation = imageOrientation( deviceOrientation: UIDevice.current.orientation, cameraPosition: cameraPosition )
Obiettivo-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];
- Crea un oggetto
VisionImage
utilizzando l'oggettoCMSampleBufferRef
e i metadati di rotazione:Veloce
let image = VisionImage(buffer: sampleBuffer) image.metadata = metadata
Obiettivo-C
FIRVisionImage *image = [[FIRVisionImage alloc] initWithBuffer:sampleBuffer]; image.metadata = metadata;
- Se necessario, ruotare l'immagine in modo che la relativa proprietà
- Quindi, passa l'immagine al metodo
process(_:completion:)
:Veloce
textRecognizer.process(visionImage) { result, error in guard error == nil, let result = result else { // ... return } // Recognized text }
Obiettivo-C
[textRecognizer processImage:image completion:^(FIRVisionDocumentText *_Nullable result, NSError *_Nullable error) { if (error != nil || result == nil) { // ... return; } // Recognized text }];
2. Estrarre il testo da blocchi di testo riconosciuto
Se l'operazione di riconoscimento del testo ha esito positivo, restituirà un oggettoVisionDocumentText
. 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
, è possibile ottenere il riconoscimento del testo nella regione e le coordinate di delimitazione della regione.
Per esempio:
Veloce
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 } } } }
Obiettivo-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; } } } }
Prossimi passi
- Prima di distribuire in produzione un'app che utilizza un'API cloud, dovresti adottare alcune misure aggiuntive per prevenire e mitigare gli effetti dell'accesso API non autorizzato .