Za pomocą ML Kit możesz rozpoznawać tekst na obrazach. ML Kit zawiera zarówno ogólny interfejs API odpowiedni do rozpoznawania tekstu na obrazach, np. tekstu na znaku drogowym, jak i interfejs API zoptymalizowany pod kątem rozpoznawania tekstu w dokumentach. Interfejs API ogólnego przeznaczenia ma modele działające na urządzeniu i w chmurze. Rozpoznawanie tekstu w dokumentach jest dostępne tylko jako model oparty na chmurze. Porównanie modeli w chmurze i na urządzeniu znajdziesz w tym artykule.
Zanim zaczniesz
- Jeśli nie masz jeszcze dodanego Firebase do aplikacji, zrób to, wykonując czynności opisane w przewodniku dla początkujących.
- Dodaj biblioteki ML Kit do pliku Podfile:
Po zainstalowaniu lub zaktualizowaniu Pods w projekcie otwórz projekt Xcode za pomocą plikupod 'Firebase/MLVision', '6.25.0' # If using an on-device API: pod 'Firebase/MLVisionTextModel', '6.25.0'
.xcworkspace
. - Zaimportuj Firebase w aplikacji:
Swift
import Firebase
Objective-C
@import Firebase;
-
Jeśli chcesz używać modelu opartego na chmurze, a nie masz jeszcze włączonych interfejsów API opartych na chmurze w swoim projekcie, zrób to teraz:
- Otwórz stronę interfejsów API ML Kit w konsoli Firebase.
-
Jeśli nie masz jeszcze projektu w abonamencie Blaze, kliknij Uaktualnij. (Prośba o uaktualnienie pojawi się tylko wtedy, gdy projekt nie jest w abonamencie Blaze).
Tylko projekty na poziomie Blaze mogą korzystać z interfejsów API opartych na chmurze.
- Jeśli interfejsy API oparte na chmurze nie są jeszcze włączone, kliknij Włącz interfejsy API oparte na chmurze.
Jeśli chcesz używać tylko modelu na urządzeniu, możesz pominąć ten krok.
Możesz teraz rozpocząć rozpoznawanie tekstu na obrazach.
Wytyczne dotyczące obrazu wejściowego
-
Aby ML Kit mógł dokładnie rozpoznawać tekst, obrazy wejściowe muszą zawierać tekst reprezentowany przez wystarczającą ilość danych pikseli. W przypadku tekstu w alfabecie łacińskim każdy znak powinien mieć co najmniej 16 x 16 pikseli. W przypadku tekstu w języku chińskim, japońskim i koreańskim (obsługiwanego tylko przez interfejsy API oparte na chmurze) każdy znak powinien mieć wymiary 24 x 24 piksele. W przypadku wszystkich języków znaki o rozmiarze większym niż 24 x 24 piksele nie zwiększają dokładności.
Obraz o wymiarach 640 x 480 może się sprawdzić w przypadku skanowania wizytówki, która zajmuje całą szerokość obrazu. Aby zeskanować dokument wydrukowany na papierze w formacie Letter, może być wymagany obraz o rozmiarze 720 × 1280 pikseli.
-
Słaba ostrość obrazu może obniżyć dokładność rozpoznawania tekstu. Jeśli wyniki nie są zadowalające, poproś użytkownika o ponowne zrobienie zdjęcia.
-
Jeśli rozpoznajesz tekst w aplikacji działającej w czasie rzeczywistym, możesz też wziąć pod uwagę ogólne wymiary obrazów wejściowych. Mniejsze obrazy można przetwarzać szybciej, więc aby zmniejszyć opóźnienie, rób zdjęcia w niższych rozdzielczościach (pamiętając o wymaganiach dotyczących dokładności) i dbaj o to, aby tekst zajmował jak największą część obrazu. Zobacz też wskazówki dotyczące poprawy skuteczności w czasie rzeczywistym.
Rozpoznawanie tekstu w obrazach
Aby rozpoznać tekst na obrazie za pomocą modelu na urządzeniu lub w chmurze, uruchom narzędzie do rozpoznawania tekstu w sposób opisany poniżej.
1. Uruchom rozpoznawanie tekstu
Przekaż obraz jako `UIImage` lub `CMSampleBufferRef` do metody `process(_:completion:)` klasy `VisionTextRecognizer`:- Uzyskaj instancję
VisionTextRecognizer
, wywołująconDeviceTextRecognizer
lubcloudTextRecognizer
:Swift
Aby użyć modelu na urządzeniu:
let vision = Vision.vision() let textRecognizer = vision.onDeviceTextRecognizer()
Aby użyć modelu w chmurze:
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
Aby użyć modelu na urządzeniu:
FIRVision *vision = [FIRVision vision]; FIRVisionTextRecognizer *textRecognizer = [vision onDeviceTextRecognizer];
Aby użyć modelu w chmurze:
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];
-
Utwórz obiekt
VisionImage
za pomocąUIImage
lubCMSampleBufferRef
.Aby użyć
UIImage
:- W razie potrzeby obróć obraz, aby jego właściwość
imageOrientation
miała wartość.up
. - Utwórz obiekt
VisionImage
, używając prawidłowo obróconegoUIImage
. Nie podawaj żadnych metadanych rotacji – musisz użyć wartości domyślnej.topLeft
.Swift
let image = VisionImage(image: uiImage)
Objective-C
FIRVisionImage *image = [[FIRVisionImage alloc] initWithImage:uiImage];
Aby użyć
CMSampleBufferRef
:-
Utwórz obiekt
VisionImageMetadata
, który określa orientację danych obrazu zawartych w buforzeCMSampleBufferRef
.Aby uzyskać orientację obrazu:
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; } }
Następnie utwórz obiekt metadanych:
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];
- Utwórz obiekt
VisionImage
za pomocą obiektuCMSampleBufferRef
i metadanych rotacji:Swift
let image = VisionImage(buffer: sampleBuffer) image.metadata = metadata
Objective-C
FIRVisionImage *image = [[FIRVisionImage alloc] initWithBuffer:sampleBuffer]; image.metadata = metadata;
- W razie potrzeby obróć obraz, aby jego właściwość
-
Następnie przekaż obraz do metody
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. Wyodrębnianie tekstu z bloków rozpoznanego tekstu
Jeśli operacja rozpoznawania tekstu się powiedzie, zwróci obiekt [`VisionText`][VisionText]. Obiekt `VisionText` zawiera pełny tekst rozpoznany na obrazie oraz zero lub więcej obiektów [`VisionTextBlock`][VisionTextBlock]. Każdy obiekt `VisionTextBlock` reprezentuje prostokątny blok tekstu, który zawiera co najmniej 1 obiekt [`VisionTextLine`][VisionTextLine]. Każdy obiekt `VisionTextLine` zawiera co najmniej 1 obiekt [`VisionTextElement`][VisionTextElement], który reprezentuje słowa i podobieństwa do słów (daty, liczby itp.). W przypadku każdego obiektu `VisionTextBlock`, `VisionTextLine` i `VisionTextElement` możesz uzyskać tekst rozpoznany w regionie i współrzędne ograniczające tego regionu. Przykład: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; } } }
Wskazówki dotyczące poprawy skuteczności w czasie rzeczywistym
Jeśli chcesz używać modelu na urządzeniu do rozpoznawania tekstu w aplikacji działającej w czasie rzeczywistym, postępuj zgodnie z tymi wytycznymi, aby uzyskać najlepszą liczbę klatek na sekundę:
- Ograniczanie liczby wywołań modułu rozpoznawania tekstu. Jeśli podczas działania modułu rozpoznawania tekstu pojawi się nowa klatka wideo, odrzuć ją.
- Jeśli używasz danych wyjściowych rozpoznawania tekstu do nakładania grafiki na obraz wejściowy, najpierw uzyskaj wynik z ML Kit, a następnie w jednym kroku wyrenderuj obraz i nałóż na niego grafikę. Dzięki temu renderowanie na powierzchnię wyświetlania odbywa się tylko raz dla każdej ramki wejściowej. Przykład znajdziesz w klasach previewOverlayView i FIRDetectionOverlayView w przykładowej aplikacji demonstracyjnej.
- Rozważ robienie zdjęć w niższej rozdzielczości. Pamiętaj jednak o wymaganiach dotyczących wymiarów obrazu w tym interfejsie API.
Dalsze kroki
- Zanim wdrożysz w środowisku produkcyjnym aplikację korzystającą z interfejsu Cloud API, podejmij dodatkowe działania, aby zapobiec nieautoryzowanemu dostępowi do interfejsu API i zminimalizować jego skutki.
Rozpoznawanie tekstu na obrazach dokumentów
Aby rozpoznać tekst dokumentu, skonfiguruj i uruchom oparty na chmurze moduł rozpoznawania tekstu w dokumencie zgodnie z poniższymi instrukcjami.
Opisany poniżej interfejs API do rozpoznawania tekstu w dokumentach udostępnia interfejs, który ma ułatwiać pracę z obrazami dokumentów. Jeśli jednak wolisz interfejs udostępniany przez interfejs Sparse Text API, możesz go używać do skanowania dokumentów, konfigurując rozpoznawanie tekstu w chmurze tak, aby korzystało z modelu tekstu gęstego.
Aby użyć interfejsu API do rozpoznawania tekstu w dokumentach:
1. Uruchom rozpoznawanie tekstu
Przekaż obraz jakoUIImage
lub CMSampleBufferRef
do metody process(_:completion:)
obiektu VisionDocumentTextRecognizer
:
- Uzyskaj instancję
VisionDocumentTextRecognizer
, wywołując funkcję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];
-
Utwórz obiekt
VisionImage
za pomocąUIImage
lubCMSampleBufferRef
.Aby użyć
UIImage
:- W razie potrzeby obróć obraz, aby jego właściwość
imageOrientation
miała wartość.up
. - Utwórz obiekt
VisionImage
, używając prawidłowo obróconegoUIImage
. Nie podawaj żadnych metadanych rotacji – musisz użyć wartości domyślnej.topLeft
.Swift
let image = VisionImage(image: uiImage)
Objective-C
FIRVisionImage *image = [[FIRVisionImage alloc] initWithImage:uiImage];
Aby użyć
CMSampleBufferRef
:-
Utwórz obiekt
VisionImageMetadata
, który określa orientację danych obrazu zawartych w buforzeCMSampleBufferRef
.Aby uzyskać orientację obrazu:
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; } }
Następnie utwórz obiekt metadanych:
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];
- Utwórz obiekt
VisionImage
za pomocą obiektuCMSampleBufferRef
i metadanych rotacji:Swift
let image = VisionImage(buffer: sampleBuffer) image.metadata = metadata
Objective-C
FIRVisionImage *image = [[FIRVisionImage alloc] initWithBuffer:sampleBuffer]; image.metadata = metadata;
- W razie potrzeby obróć obraz, aby jego właściwość
-
Następnie przekaż obraz do metody
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. Wyodrębnianie tekstu z bloków rozpoznanego tekstu
Jeśli operacja rozpoznawania tekstu się powiedzie, zwróci obiektVisionDocumentText
. Obiekt VisionDocumentText
zawiera pełny tekst rozpoznany na obrazie oraz hierarchię obiektów, które odzwierciedlają strukturę rozpoznanego dokumentu:
W przypadku każdego obiektu VisionDocumentTextBlock
, VisionDocumentTextParagraph
, VisionDocumentTextWord
i VisionDocumentTextSymbol
możesz uzyskać tekst rozpoznany w regionie oraz współrzędne ograniczające tego regionu.
Przykład:
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; } } } }
Dalsze kroki
- Zanim wdrożysz w środowisku produkcyjnym aplikację korzystającą z interfejsu Cloud API, podejmij dodatkowe działania, aby zapobiec nieautoryzowanemu dostępowi do interfejsu API i zminimalizować jego skutki.