Za pomocą narzędzia ML Kit możesz rozpoznawać tekst na obrazach. ML Kit zawiera zarówno interfejs API ogólnego przeznaczenia, odpowiedni do rozpoznawania tekstu w obrazach, np. tekstu znaków drogowych, jak i interfejs API zoptymalizowany pod kątem rozpoznawania tekstu dokumentów. Interfejs API ogólnego przeznaczenia obejmuje modele zarówno na urządzeniu, jak i w chmurze. Rozpoznawanie tekstu dokumentu jest dostępne tylko w modelu opartym na chmurze. Zobacz przegląd , aby porównać modele w chmurze i na urządzeniu.
Zanim zaczniesz
- Jeśli nie dodałeś jeszcze Firebase do swojej aplikacji, zrób to, wykonując czynności opisane w przewodniku wprowadzającym .
- Dołącz biblioteki ML Kit do swojego Podfile:
pod 'Firebase/MLVision', '6.25.0' # If using an on-device API: pod 'Firebase/MLVisionTextModel', '6.25.0'
Po zainstalowaniu lub zaktualizowaniu Podów swojego projektu pamiętaj o otwarciu projektu Xcode przy użyciu jego.xcworkspace
. - W swojej aplikacji zaimportuj Firebase:
Szybki
import Firebase
Cel C
@import Firebase;
Jeśli chcesz korzystać z modelu opartego na chmurze, a nie włączyłeś jeszcze interfejsów API opartych na chmurze dla swojego projektu, zrób to teraz:
- Otwórz stronę interfejsów API ML Kit w konsoli Firebase.
Jeśli nie uaktualniłeś jeszcze swojego projektu do planu cenowego Blaze, kliknij Uaktualnij , aby to zrobić. (Zostaniesz poproszony o uaktualnienie tylko wtedy, gdy Twój projekt nie jest objęty planem 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 opcję Włącz interfejsy API oparte na chmurze .
Jeśli chcesz używać tylko modelu na urządzeniu, możesz pominąć ten krok.
Teraz możesz rozpocząć rozpoznawanie tekstu na obrazach.
Wytyczne dotyczące obrazu wejściowego
Aby zestaw ML Kit mógł dokładnie rozpoznawać tekst, obrazy wejściowe muszą zawierać tekst reprezentowany przez wystarczającą ilość danych w pikselach. W idealnym przypadku w przypadku tekstu łacińskiego każdy znak powinien mieć wymiary co najmniej 16 x 16 pikseli. W przypadku tekstu chińskiego, japońskiego i koreańskiego (obsługiwanego wyłącznie przez interfejsy API oparte na chmurze) każdy znak powinien mieć wymiary 24 x 24 piksele. W przypadku wszystkich języków znaki większe niż 24 x 24 piksele zasadniczo nie zapewniają korzyści w zakresie dokładności.
Na przykład obraz o wymiarach 640 x 480 może dobrze sprawdzić się w przypadku skanowania wizytówki zajmującej całą szerokość obrazu. Do skanowania dokumentu wydrukowanego na papierze formatu Letter może być wymagany obraz o wymiarach 720 x 1280 pikseli.
Słaba ostrość obrazu może zaszkodzić dokładności rozpoznawania tekstu. Jeśli wyniki nie są akceptowalne, spróbuj poprosić użytkownika o ponowne wykonanie zdjęcia.
Jeśli rozpoznajesz tekst w aplikacji działającej w czasie rzeczywistym, możesz również rozważyć ogólne wymiary obrazów wejściowych. Mniejsze obrazy można przetwarzać szybciej, więc aby zmniejszyć opóźnienia, przechwytuj obrazy w niższych rozdzielczościach (pamiętając o powyższych wymaganiach dotyczących dokładności) i upewnij się, że tekst zajmuje jak największą część obrazu. Zobacz także Wskazówki dotyczące poprawy wydajności w czasie rzeczywistym .
Rozpoznawanie tekstu na obrazach
Aby rozpoznać tekst na obrazie przy użyciu modelu na urządzeniu lub w chmurze, uruchom moduł rozpoznawania tekstu w sposób opisany poniżej.
1. Uruchom moduł rozpoznawania tekstu
Przekaż obraz jako `UIImage` lub `CMSampleBufferRef` do metody `process(_:completion:)` `VisionTextRecognizer`:- Uzyskaj instancję
VisionTextRecognizer
, wywołująconDeviceTextRecognizer
lubcloudTextRecognizer
:Szybki
Aby skorzystać z modelu na urządzeniu:
let vision = Vision.vision() let textRecognizer = vision.onDeviceTextRecognizer()
Aby skorzystać z modelu chmury:
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)
Cel C
Aby skorzystać z modelu na urządzeniu:
FIRVision *vision = [FIRVision vision]; FIRVisionTextRecognizer *textRecognizer = [vision onDeviceTextRecognizer];
Aby skorzystać z modelu chmury:
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
przy użyciuUIImage
lubCMSampleBufferRef
.Aby użyć
UIImage
:- W razie potrzeby obróć obraz tak, aby jego właściwość
imageOrientation
miała.up
. - Utwórz obiekt
VisionImage
przy użyciu poprawnie obróconegoUIImage
. Nie określaj żadnych metadanych rotacji — należy użyć wartości domyślnej.topLeft
.Szybki
let image = VisionImage(image: uiImage)
Cel 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:
Szybki
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 } }
Cel 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:
Szybki
let cameraPosition = AVCaptureDevice.Position.back // Set to the capture device you used. let metadata = VisionImageMetadata() metadata.orientation = imageOrientation( deviceOrientation: UIDevice.current.orientation, cameraPosition: cameraPosition )
Cel 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
przy użyciu obiektuCMSampleBufferRef
i metadanych rotacji:Szybki
let image = VisionImage(buffer: sampleBuffer) image.metadata = metadata
Cel C
FIRVisionImage *image = [[FIRVisionImage alloc] initWithBuffer:sampleBuffer]; image.metadata = metadata;
- W razie potrzeby obróć obraz tak, aby jego właściwość
- Następnie przekaż obraz do metody
process(_:completion:)
:Szybki
textRecognizer.process(visionImage) { result, error in guard error == nil, let result = result else { // ... return } // Recognized text }
Cel C
[textRecognizer processImage:image completion:^(FIRVisionText *_Nullable result, NSError *_Nullable error) { if (error != nil || result == nil) { // ... return; } // Recognized text }];
2. Wyodrębnij tekst z bloków rozpoznanego tekstu
Jeśli operacja rozpoznawania tekstu zakończy się pomyślnie, zwróci obiekt [`VisionText`][VisionText]. Obiekt `VisionText` zawiera pełny tekst rozpoznany w obrazie oraz zero lub więcej obiektów [`VisionTextBlock`][VisionTextBlock]. Każdy `VisionTextBlock` reprezentuje prostokątny blok tekstu, który zawiera zero lub więcej obiektów [`VisionTextLine`][VisionTextLine]. Każdy obiekt `VisionTextLine` zawiera zero lub więcej obiektów [`VisionTextElement`][VisionTextElement], które reprezentują słowa i byty słowa (daty, liczby itd.). Dla każdego obiektu `VisionTextBlock`, `VisionTextLine` i `VisionTextElement` można uzyskać tekst rozpoznany w regionie i współrzędne ograniczające region. Na przykład:Szybki
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 } } }
Cel 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, jak poprawić wydajność 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 poniższymi wskazówkami, aby uzyskać najlepszą liczbę klatek na sekundę:
- Ogranicz wywołania do modułu rozpoznawania tekstu. Jeśli w trakcie działania modułu rozpoznawania tekstu pojawi się nowa klatka wideo, usuń ją.
- Jeśli używasz wyników modułu rozpoznawania tekstu do nakładania grafiki na obraz wejściowy, najpierw uzyskaj wynik z ML Kit, a następnie wyrenderuj obraz i nakładkę w jednym kroku. W ten sposób renderujesz na powierzchnię wyświetlacza tylko raz dla każdej klatki wejściowej. Zobacz przykładowe klasy PreviewOverlayView i FIRDetectionOverlayView w przykładowej aplikacji prezentacyjnej.
- Rozważ przechwytywanie obrazów w niższej rozdzielczości. Należy jednak pamiętać o wymaganiach dotyczących wymiarów obrazu tego interfejsu API.
Następne kroki
- Zanim wdrożysz do produkcji aplikację korzystającą z Cloud API, powinieneś podjąć dodatkowe kroki, aby zapobiec i złagodzić skutki nieautoryzowanego dostępu do API .
Rozpoznawanie tekstu na obrazach dokumentów
Aby rozpoznać tekst dokumentu, skonfiguruj i uruchom moduł rozpoznawania tekstu dokumentu w chmurze, jak opisano poniżej.
Opisany poniżej interfejs API rozpoznawania tekstu dokumentu zapewnia interfejs, który ma być wygodniejszy w pracy z obrazami dokumentów. Jeśli jednak wolisz interfejs udostępniany przez interfejs API rzadkiego tekstu, możesz go zamiast tego używać do skanowania dokumentów, konfigurując moduł rozpoznawania tekstu w chmurze tak, aby korzystał z modelu gęstego tekstu .
Aby skorzystać z interfejsu API rozpoznawania tekstu dokumentu:
1. Uruchom moduł rozpoznawania tekstu
Przekaż obraz jakoUIImage
lub CMSampleBufferRef
do process(_:completion:)
metody VisionDocumentTextRecognizer
:- Uzyskaj instancję
VisionDocumentTextRecognizer
, wywołująccloudDocumentTextRecognizer
:Szybki
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)
Cel 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
przy użyciuUIImage
lubCMSampleBufferRef
.Aby użyć
UIImage
:- W razie potrzeby obróć obraz tak, aby jego właściwość
imageOrientation
miała.up
. - Utwórz obiekt
VisionImage
, używając poprawnie obróconegoUIImage
. Nie określaj żadnych metadanych rotacji — należy użyć wartości domyślnej.topLeft
.Szybki
let image = VisionImage(image: uiImage)
Cel 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:
Szybki
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 } }
Cel 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:
Szybki
let cameraPosition = AVCaptureDevice.Position.back // Set to the capture device you used. let metadata = VisionImageMetadata() metadata.orientation = imageOrientation( deviceOrientation: UIDevice.current.orientation, cameraPosition: cameraPosition )
Cel 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
przy użyciu obiektuCMSampleBufferRef
i metadanych rotacji:Szybki
let image = VisionImage(buffer: sampleBuffer) image.metadata = metadata
Cel C
FIRVisionImage *image = [[FIRVisionImage alloc] initWithBuffer:sampleBuffer]; image.metadata = metadata;
- W razie potrzeby obróć obraz tak, aby jego właściwość
- Następnie przekaż obraz do metody
process(_:completion:)
:Szybki
textRecognizer.process(visionImage) { result, error in guard error == nil, let result = result else { // ... return } // Recognized text }
Cel C
[textRecognizer processImage:image completion:^(FIRVisionDocumentText *_Nullable result, NSError *_Nullable error) { if (error != nil || result == nil) { // ... return; } // Recognized text }];
2. Wyodrębnij tekst z bloków rozpoznanego tekstu
Jeśli operacja rozpoznawania tekstu zakończy się pomyślnie, zwróci obiektVisionDocumentText
. Obiekt VisionDocumentText
zawiera pełny tekst rozpoznany na obrazie oraz hierarchię obiektów odzwierciedlającą strukturę rozpoznanego dokumentu: Dla każdego obiektu VisionDocumentTextBlock
, VisionDocumentTextParagraph
, VisionDocumentTextWord
i VisionDocumentTextSymbol
można uzyskać tekst rozpoznawany w regionie i współrzędne graniczne regionu.
Na przykład:
Szybki
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 } } } }
Cel 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; } } } }
Następne kroki
- Zanim wdrożysz do produkcji aplikację korzystającą z Cloud API, powinieneś podjąć dodatkowe kroki, aby zapobiec i złagodzić skutki nieautoryzowanego dostępu do API .