Do rozpoznawania tekstu na obrazach możesz używać pakietu ML Kit. ML Kit zawiera ogólnego przeznaczenia API, odpowiedni do rozpoznawania tekstu na obrazach, takiego jak i tekstu znaku drogowego oraz interfejs API zoptymalizowany pod kątem rozpoznawania tekstu dokumenty. Interfejs API do zwykłych obciążeń obejmuje modele działające na urządzeniu i w chmurze. Rozpoznawanie tekstu dokumentów jest dostępne tylko jako model działający w chmurze. Zobacz przegląd, aby porównać w chmurze i na urządzeniu.
Zanim zaczniesz
- Jeśli jeszcze nie masz tego za sobą, dodaj Firebase do swojego projektu na Androida.
- Dodaj do modułu zależności między bibliotekami ML Kit na Androida
Plik Gradle (na poziomie aplikacji) (zwykle
app/build.gradle
):apply plugin: 'com.android.application' apply plugin: 'com.google.gms.google-services' dependencies { // ... implementation 'com.google.firebase:firebase-ml-vision:24.0.3' }
-
Opcjonalne, ale zalecane: jeśli używasz interfejsu API działającego na urządzeniu, skonfiguruj
automatycznie pobiera model ML na urządzenie po tym, jak aplikacja zostanie
ze Sklepu Play.
Aby to zrobić, dodaj tę deklarację do Plik
AndroidManifest.xml
: Jeśli nie włączysz pobierania modelu w czasie instalacji, model zostanie pobrane przy pierwszym uruchomieniu detektora na urządzeniu. Twoje prośby przed zakończeniem pobierania nie przyniesie żadnych wyników.<application ...> ... <meta-data android:name="com.google.firebase.ml.vision.DEPENDENCIES" android:value="ocr" /> <!-- To use multiple models: android:value="ocr,model2,model3" --> </application>
-
Jeśli chcesz używać modelu działającego w chmurze, który nie został jeszcze włączony interfejsów API działających w chmurze w Twoim projekcie, zrób to teraz:
- Otwórz ML Kit Strona interfejsów API w konsoli Firebase.
-
Jeśli w swoim projekcie nie korzystasz jeszcze z abonamentu Blaze, kliknij Aby to zrobić, przejdź na wyższą wersję. (Prośba o uaktualnienie wyświetli się tylko wtedy, gdy projekt nie jest objęty abonamentem Blaze).
Tylko projekty na poziomie Blaze mogą korzystać z interfejsów API działających w chmurze.
- Jeśli interfejsy API działające w chmurze nie są włączone, kliknij Włącz działające w chmurze interfejsów API.
Jeśli chcesz używać tylko modelu na urządzeniu, możesz pominąć ten krok.
Teraz możesz zacząć rozpoznawać tekst na obrazach.
Wytyczne dotyczące obrazu wejściowego
-
Aby ML Kit mógł dokładnie rozpoznawać tekst, obrazy wejściowe muszą zawierać który jest reprezentowany przez wystarczającą ilość danych pikseli. najlepiej dla alfabetu łacińskiego tekstu, każdy znak powinien mieć co najmniej 16 x 16 pikseli. W przypadku języka chińskiego, tekst w języku japońskim i koreańskim (obsługiwany tylko przez interfejsy API działające w chmurze), każdy powinien mieć rozmiar 24 x 24 piksele. Dla wszystkich języków zwykle nie ma funkcji w przypadku znaków większych niż 24 x 24 piksele.
Na przykład obraz o wymiarach 640 x 480 może się sprawdzić do zeskanowania wizytówki zajmuje całą szerokość obrazu. Aby zeskanować dokument wydrukowany na na papierze w formacie letter, może być wymagany obraz o wymiarach 720 x 1280 pikseli.
-
Słaba ostrość obrazu może obniżyć dokładność rozpoznawania tekstu. Jeśli nim nie jesteś uzyskać akceptowalne wyniki, poproś użytkownika o ponowne przechwycenie obrazu.
-
Jeśli rozpoznajesz tekst w aplikacji działającej w czasie rzeczywistym, możesz też należy wziąć pod uwagę ogólne wymiary obrazów wejściowych. Mniejszy szybsze przetwarzanie obrazów. Aby zmniejszyć opóźnienia, należy robić zdjęcia mniejsza rozdzielczość (pamiętając o powyższych wymaganiach dotyczących dokładności) aby tekst zajmował jak największą część obrazu. Zobacz też Wskazówki, jak zwiększyć skuteczność w czasie rzeczywistym.
Rozpoznawanie tekstu w obrazach
Aby rozpoznać tekst na obrazie za pomocą modelu działającego na urządzeniu lub w chmurze: uruchom moduł rozpoznawania tekstu w sposób opisany poniżej.
1. Uruchom moduł rozpoznawania tekstu
Aby rozpoznać tekst na obrazie, utwórz obiektFirebaseVisionImage
z obiektu Bitmap
, media.Image
, ByteBuffer
, tablicy bajtów lub pliku w
urządzenia. Następnie przekaż obiekt FirebaseVisionImage
do funkcji
Metoda processImage
użytkownika FirebaseVisionTextRecognizer
.
Utwórz obiekt
FirebaseVisionImage
na podstawie swojego obrazu.-
Aby utworzyć obiekt
FirebaseVisionImage
na podstawiemedia.Image
, np. podczas przechwytywania obrazu z z aparatu urządzenia, przekazać obiektmedia.Image
oraz w kierunkuFirebaseVisionImage.fromMediaImage()
.Jeśli używasz tagu CameraX,
OnImageCapturedListener
orazImageAnalysis.Analyzer
klasy obliczają wartość rotacji więc wystarczy zmienić rotację na jeden z zestawów ML Kit StałyROTATION_
przed nawiązaniem połączeniaFirebaseVisionImage.fromMediaImage()
:Java
private class YourAnalyzer implements ImageAnalysis.Analyzer { private int degreesToFirebaseRotation(int degrees) { switch (degrees) { case 0: return FirebaseVisionImageMetadata.ROTATION_0; case 90: return FirebaseVisionImageMetadata.ROTATION_90; case 180: return FirebaseVisionImageMetadata.ROTATION_180; case 270: return FirebaseVisionImageMetadata.ROTATION_270; default: throw new IllegalArgumentException( "Rotation must be 0, 90, 180, or 270."); } } @Override public void analyze(ImageProxy imageProxy, int degrees) { if (imageProxy == null || imageProxy.getImage() == null) { return; } Image mediaImage = imageProxy.getImage(); int rotation = degreesToFirebaseRotation(degrees); FirebaseVisionImage image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation); // Pass image to an ML Kit Vision API // ... } }
Kotlin+KTX
private class YourImageAnalyzer : ImageAnalysis.Analyzer { private fun degreesToFirebaseRotation(degrees: Int): Int = when(degrees) { 0 -> FirebaseVisionImageMetadata.ROTATION_0 90 -> FirebaseVisionImageMetadata.ROTATION_90 180 -> FirebaseVisionImageMetadata.ROTATION_180 270 -> FirebaseVisionImageMetadata.ROTATION_270 else -> throw Exception("Rotation must be 0, 90, 180, or 270.") } override fun analyze(imageProxy: ImageProxy?, degrees: Int) { val mediaImage = imageProxy?.image val imageRotation = degreesToFirebaseRotation(degrees) if (mediaImage != null) { val image = FirebaseVisionImage.fromMediaImage(mediaImage, imageRotation) // Pass image to an ML Kit Vision API // ... } } }
Jeśli nie korzystasz z biblioteki aparatu zapewniającej obrót obrazu, może go obliczyć na podstawie obrotu urządzenia i orientacji aparatu czujnik w urządzeniu:
Java
private static final SparseIntArray ORIENTATIONS = new SparseIntArray(); static { ORIENTATIONS.append(Surface.ROTATION_0, 90); ORIENTATIONS.append(Surface.ROTATION_90, 0); ORIENTATIONS.append(Surface.ROTATION_180, 270); ORIENTATIONS.append(Surface.ROTATION_270, 180); } /** * Get the angle by which an image must be rotated given the device's current * orientation. */ @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) private int getRotationCompensation(String cameraId, Activity activity, Context context) throws CameraAccessException { // Get the device's current rotation relative to its "native" orientation. // Then, from the ORIENTATIONS table, look up the angle the image must be // rotated to compensate for the device's rotation. int deviceRotation = activity.getWindowManager().getDefaultDisplay().getRotation(); int rotationCompensation = ORIENTATIONS.get(deviceRotation); // On most devices, the sensor orientation is 90 degrees, but for some // devices it is 270 degrees. For devices with a sensor orientation of // 270, rotate the image an additional 180 ((270 + 270) % 360) degrees. CameraManager cameraManager = (CameraManager) context.getSystemService(CAMERA_SERVICE); int sensorOrientation = cameraManager .getCameraCharacteristics(cameraId) .get(CameraCharacteristics.SENSOR_ORIENTATION); rotationCompensation = (rotationCompensation + sensorOrientation + 270) % 360; // Return the corresponding FirebaseVisionImageMetadata rotation value. int result; switch (rotationCompensation) { case 0: result = FirebaseVisionImageMetadata.ROTATION_0; break; case 90: result = FirebaseVisionImageMetadata.ROTATION_90; break; case 180: result = FirebaseVisionImageMetadata.ROTATION_180; break; case 270: result = FirebaseVisionImageMetadata.ROTATION_270; break; default: result = FirebaseVisionImageMetadata.ROTATION_0; Log.e(TAG, "Bad rotation value: " + rotationCompensation); } return result; }
Kotlin+KTX
private val ORIENTATIONS = SparseIntArray() init { ORIENTATIONS.append(Surface.ROTATION_0, 90) ORIENTATIONS.append(Surface.ROTATION_90, 0) ORIENTATIONS.append(Surface.ROTATION_180, 270) ORIENTATIONS.append(Surface.ROTATION_270, 180) } /** * Get the angle by which an image must be rotated given the device's current * orientation. */ @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) @Throws(CameraAccessException::class) private fun getRotationCompensation(cameraId: String, activity: Activity, context: Context): Int { // Get the device's current rotation relative to its "native" orientation. // Then, from the ORIENTATIONS table, look up the angle the image must be // rotated to compensate for the device's rotation. val deviceRotation = activity.windowManager.defaultDisplay.rotation var rotationCompensation = ORIENTATIONS.get(deviceRotation) // On most devices, the sensor orientation is 90 degrees, but for some // devices it is 270 degrees. For devices with a sensor orientation of // 270, rotate the image an additional 180 ((270 + 270) % 360) degrees. val cameraManager = context.getSystemService(CAMERA_SERVICE) as CameraManager val sensorOrientation = cameraManager .getCameraCharacteristics(cameraId) .get(CameraCharacteristics.SENSOR_ORIENTATION)!! rotationCompensation = (rotationCompensation + sensorOrientation + 270) % 360 // Return the corresponding FirebaseVisionImageMetadata rotation value. val result: Int when (rotationCompensation) { 0 -> result = FirebaseVisionImageMetadata.ROTATION_0 90 -> result = FirebaseVisionImageMetadata.ROTATION_90 180 -> result = FirebaseVisionImageMetadata.ROTATION_180 270 -> result = FirebaseVisionImageMetadata.ROTATION_270 else -> { result = FirebaseVisionImageMetadata.ROTATION_0 Log.e(TAG, "Bad rotation value: $rotationCompensation") } } return result }
Następnie przekaż obiekt
media.Image
oraz wartość rotacji doFirebaseVisionImage.fromMediaImage()
:Java
FirebaseVisionImage image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation);
Kotlin+KTX
val image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation)
- Aby utworzyć obiekt
FirebaseVisionImage
na podstawie identyfikatora URI pliku, przekaż kontekst aplikacji i identyfikator URI plikuFirebaseVisionImage.fromFilePath()
Jest to przydatne, gdy użyj intencjiACTION_GET_CONTENT
, aby zachęcić użytkownika do wyboru obraz z aplikacji Galeria.Java
FirebaseVisionImage image; try { image = FirebaseVisionImage.fromFilePath(context, uri); } catch (IOException e) { e.printStackTrace(); }
Kotlin+KTX
val image: FirebaseVisionImage try { image = FirebaseVisionImage.fromFilePath(context, uri) } catch (e: IOException) { e.printStackTrace() }
- Aby utworzyć obiekt
FirebaseVisionImage
na podstawieByteBuffer
lub tablicy bajtów, najpierw oblicz wartość obrazu w sposób opisany powyżej dla danych wejściowychmedia.Image
.Następnie utwórz obiekt
FirebaseVisionImageMetadata
określającą wysokość, szerokość i format kodowania kolorów obrazu i rotacja:Java
FirebaseVisionImageMetadata metadata = new FirebaseVisionImageMetadata.Builder() .setWidth(480) // 480x360 is typically sufficient for .setHeight(360) // image recognition .setFormat(FirebaseVisionImageMetadata.IMAGE_FORMAT_NV21) .setRotation(rotation) .build();
Kotlin+KTX
val metadata = FirebaseVisionImageMetadata.Builder() .setWidth(480) // 480x360 is typically sufficient for .setHeight(360) // image recognition .setFormat(FirebaseVisionImageMetadata.IMAGE_FORMAT_NV21) .setRotation(rotation) .build()
Za pomocą bufora lub tablicy oraz obiektu metadanych utwórz
FirebaseVisionImage
obiekt:Java
FirebaseVisionImage image = FirebaseVisionImage.fromByteBuffer(buffer, metadata); // Or: FirebaseVisionImage image = FirebaseVisionImage.fromByteArray(byteArray, metadata);
Kotlin+KTX
val image = FirebaseVisionImage.fromByteBuffer(buffer, metadata) // Or: val image = FirebaseVisionImage.fromByteArray(byteArray, metadata)
- Aby utworzyć obiekt
FirebaseVisionImage
na podstawie ObiektBitmap
:Java
FirebaseVisionImage image = FirebaseVisionImage.fromBitmap(bitmap);
Kotlin+KTX
val image = FirebaseVisionImage.fromBitmap(bitmap)
Bitmap
musi być pionowo bez konieczności dodatkowego obracania.
-
Pobierz instancję
FirebaseVisionTextRecognizer
.Aby używać modelu na urządzeniu:
Java
FirebaseVisionTextRecognizer detector = FirebaseVision.getInstance() .getOnDeviceTextRecognizer();
Kotlin+KTX
val detector = FirebaseVision.getInstance() .onDeviceTextRecognizer
Aby używać modelu działającego w chmurze:
Java
FirebaseVisionTextRecognizer detector = FirebaseVision.getInstance() .getCloudTextRecognizer(); // Or, to change the default settings: // FirebaseVisionTextRecognizer detector = FirebaseVision.getInstance() // .getCloudTextRecognizer(options);
// Or, to provide language hints to assist with language detection: // See https://cloud.google.com/vision/docs/languages for supported languages FirebaseVisionCloudTextRecognizerOptions options = new FirebaseVisionCloudTextRecognizerOptions.Builder() .setLanguageHints(Arrays.asList("en", "hi")) .build();
Kotlin+KTX
val detector = FirebaseVision.getInstance().cloudTextRecognizer // Or, to change the default settings: // val detector = FirebaseVision.getInstance().getCloudTextRecognizer(options)
// Or, to provide language hints to assist with language detection: // See https://cloud.google.com/vision/docs/languages for supported languages val options = FirebaseVisionCloudTextRecognizerOptions.Builder() .setLanguageHints(listOf("en", "hi")) .build()
Na koniec przekaż obraz do metody
processImage
:Java
Task<FirebaseVisionText> result = detector.processImage(image) .addOnSuccessListener(new OnSuccessListener<FirebaseVisionText>() { @Override public void onSuccess(FirebaseVisionText firebaseVisionText) { // Task completed successfully // ... } }) .addOnFailureListener( new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { // Task failed with an exception // ... } });
Kotlin+KTX
val result = detector.processImage(image) .addOnSuccessListener { firebaseVisionText -> // Task completed successfully // ... } .addOnFailureListener { e -> // Task failed with an exception // ... }
2. Wyodrębnianie tekstu z bloków rozpoznanego tekstu
Jeśli rozpoznawanie tekstu się powiedzie, Do powodzenia zostanie przekazany obiektFirebaseVisionText
słuchacz. Obiekt FirebaseVisionText
zawiera pełny tekst rozpoznany w
i zero lub więcej obiektów TextBlock
.
Każdy element TextBlock
to prostokątny blok tekstu, zawierający zero lub
więcej obiektów Line
. Każdy obiekt Line
zawiera 0 lub więcej
obiekty Element
, które reprezentują słowa i słowa
elementów (dat, liczb itp.).
Dla każdego obiektu TextBlock
, Line
i Element
można wyświetlić tekst
rozpoznawane w regionie i współrzędne graniczne regionu.
Przykład:
Java
String resultText = result.getText(); for (FirebaseVisionText.TextBlock block: result.getTextBlocks()) { String blockText = block.getText(); Float blockConfidence = block.getConfidence(); List<RecognizedLanguage> blockLanguages = block.getRecognizedLanguages(); Point[] blockCornerPoints = block.getCornerPoints(); Rect blockFrame = block.getBoundingBox(); for (FirebaseVisionText.Line line: block.getLines()) { String lineText = line.getText(); Float lineConfidence = line.getConfidence(); List<RecognizedLanguage> lineLanguages = line.getRecognizedLanguages(); Point[] lineCornerPoints = line.getCornerPoints(); Rect lineFrame = line.getBoundingBox(); for (FirebaseVisionText.Element element: line.getElements()) { String elementText = element.getText(); Float elementConfidence = element.getConfidence(); List<RecognizedLanguage> elementLanguages = element.getRecognizedLanguages(); Point[] elementCornerPoints = element.getCornerPoints(); Rect elementFrame = element.getBoundingBox(); } } }
Kotlin+KTX
val resultText = result.text for (block in result.textBlocks) { val blockText = block.text val blockConfidence = block.confidence val blockLanguages = block.recognizedLanguages val blockCornerPoints = block.cornerPoints val blockFrame = block.boundingBox for (line in block.lines) { val lineText = line.text val lineConfidence = line.confidence val lineLanguages = line.recognizedLanguages val lineCornerPoints = line.cornerPoints val lineFrame = line.boundingBox for (element in line.elements) { val elementText = element.text val elementConfidence = element.confidence val elementLanguages = element.recognizedLanguages val elementCornerPoints = element.cornerPoints val elementFrame = element.boundingBox } } }
Wskazówki dotyczące poprawy skuteczności w czasie rzeczywistym
Jeśli chcesz używać modelu na urządzeniu do rozpoznawania tekstu w czasie rzeczywistym zastosuj się do tych wskazówek, by uzyskać najlepszą liczbę klatek na sekundę:
- Ogranicz wywołania do modułu rozpoznawania tekstu. Jeśli nowa klatka wideo dostępne podczas działania modułu rozpoznawania tekstu, upuść ramkę.
- Jeśli używasz danych wyjściowych modułu rozpoznawania tekstu do nakładania grafiki na obrazu wejściowego, najpierw pobierz wynik z ML Kit, a następnie wyrenderuj obraz i nakładanie nakładek w jednym kroku. W ten sposób renderowanie na powierzchni tylko raz na każdą ramkę wejściową.
-
Jeśli korzystasz z interfejsu API Camera2, rób zdjęcia w Format:
ImageFormat.YUV_420_888
.Jeśli używasz starszej wersji interfejsu Camera API, rób zdjęcia w Format:
ImageFormat.NV21
. - Rozważ robienie zdjęć w niższej rozdzielczości. Pamiętaj jednak, wymagania dotyczące wymiarów obrazów w tym interfejsie API.
Dalsze kroki
- Przed wdrożeniem w środowisku produkcyjnym aplikacji korzystającej z interfejsu Cloud API wykonaj dodatkowe kroki, które zapobiegają i ograniczają efekt nieautoryzowanego dostępu do interfejsu API.
Rozpoznawanie tekstu na obrazach dokumentów
Aby rozpoznać tekst dokumentu, skonfiguruj i uruchom rozpoznawania tekstu dokumentu, zgodnie z opisem poniżej.
Opisany poniżej interfejs API rozpoznawania tekstu dokumentów zapewnia interfejs,
ma ułatwić pracę z obrazami dokumentów. Pamiętaj jednak:
jeśli wolisz interfejs dostarczony przez FirebaseVisionTextRecognizer
API,
możesz go używać do skanowania dokumentów, konfigurując tekst w chmurze
modułu rozpoznawania, aby używać modelu gęstego tekstu.
Aby użyć interfejsu API rozpoznawania tekstu dokumentów:
1. Uruchom moduł rozpoznawania tekstu
Aby rozpoznać tekst na obrazie, utwórz obiektFirebaseVisionImage
na podstawie
Bitmap
, media.Image
, ByteBuffer
, tablica bajtów lub plik na urządzeniu.
Następnie przekaż obiekt FirebaseVisionImage
do funkcji
Metoda processImage
użytkownika FirebaseVisionDocumentTextRecognizer
.
Utwórz obiekt
FirebaseVisionImage
na podstawie swojego obrazu.-
Aby utworzyć obiekt
FirebaseVisionImage
na podstawiemedia.Image
, np. podczas przechwytywania obrazu z z aparatu urządzenia, przekazać obiektmedia.Image
oraz w kierunkuFirebaseVisionImage.fromMediaImage()
.Jeśli używasz tagu CameraX,
OnImageCapturedListener
orazImageAnalysis.Analyzer
klasy obliczają wartość rotacji więc wystarczy zmienić rotację na jeden z zestawów ML Kit StałyROTATION_
przed nawiązaniem połączeniaFirebaseVisionImage.fromMediaImage()
:Java
private class YourAnalyzer implements ImageAnalysis.Analyzer { private int degreesToFirebaseRotation(int degrees) { switch (degrees) { case 0: return FirebaseVisionImageMetadata.ROTATION_0; case 90: return FirebaseVisionImageMetadata.ROTATION_90; case 180: return FirebaseVisionImageMetadata.ROTATION_180; case 270: return FirebaseVisionImageMetadata.ROTATION_270; default: throw new IllegalArgumentException( "Rotation must be 0, 90, 180, or 270."); } } @Override public void analyze(ImageProxy imageProxy, int degrees) { if (imageProxy == null || imageProxy.getImage() == null) { return; } Image mediaImage = imageProxy.getImage(); int rotation = degreesToFirebaseRotation(degrees); FirebaseVisionImage image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation); // Pass image to an ML Kit Vision API // ... } }
Kotlin+KTX
private class YourImageAnalyzer : ImageAnalysis.Analyzer { private fun degreesToFirebaseRotation(degrees: Int): Int = when(degrees) { 0 -> FirebaseVisionImageMetadata.ROTATION_0 90 -> FirebaseVisionImageMetadata.ROTATION_90 180 -> FirebaseVisionImageMetadata.ROTATION_180 270 -> FirebaseVisionImageMetadata.ROTATION_270 else -> throw Exception("Rotation must be 0, 90, 180, or 270.") } override fun analyze(imageProxy: ImageProxy?, degrees: Int) { val mediaImage = imageProxy?.image val imageRotation = degreesToFirebaseRotation(degrees) if (mediaImage != null) { val image = FirebaseVisionImage.fromMediaImage(mediaImage, imageRotation) // Pass image to an ML Kit Vision API // ... } } }
Jeśli nie korzystasz z biblioteki aparatu zapewniającej obrót obrazu, może go obliczyć na podstawie obrotu urządzenia i orientacji aparatu czujnik w urządzeniu:
Java
private static final SparseIntArray ORIENTATIONS = new SparseIntArray(); static { ORIENTATIONS.append(Surface.ROTATION_0, 90); ORIENTATIONS.append(Surface.ROTATION_90, 0); ORIENTATIONS.append(Surface.ROTATION_180, 270); ORIENTATIONS.append(Surface.ROTATION_270, 180); } /** * Get the angle by which an image must be rotated given the device's current * orientation. */ @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) private int getRotationCompensation(String cameraId, Activity activity, Context context) throws CameraAccessException { // Get the device's current rotation relative to its "native" orientation. // Then, from the ORIENTATIONS table, look up the angle the image must be // rotated to compensate for the device's rotation. int deviceRotation = activity.getWindowManager().getDefaultDisplay().getRotation(); int rotationCompensation = ORIENTATIONS.get(deviceRotation); // On most devices, the sensor orientation is 90 degrees, but for some // devices it is 270 degrees. For devices with a sensor orientation of // 270, rotate the image an additional 180 ((270 + 270) % 360) degrees. CameraManager cameraManager = (CameraManager) context.getSystemService(CAMERA_SERVICE); int sensorOrientation = cameraManager .getCameraCharacteristics(cameraId) .get(CameraCharacteristics.SENSOR_ORIENTATION); rotationCompensation = (rotationCompensation + sensorOrientation + 270) % 360; // Return the corresponding FirebaseVisionImageMetadata rotation value. int result; switch (rotationCompensation) { case 0: result = FirebaseVisionImageMetadata.ROTATION_0; break; case 90: result = FirebaseVisionImageMetadata.ROTATION_90; break; case 180: result = FirebaseVisionImageMetadata.ROTATION_180; break; case 270: result = FirebaseVisionImageMetadata.ROTATION_270; break; default: result = FirebaseVisionImageMetadata.ROTATION_0; Log.e(TAG, "Bad rotation value: " + rotationCompensation); } return result; }
Kotlin+KTX
private val ORIENTATIONS = SparseIntArray() init { ORIENTATIONS.append(Surface.ROTATION_0, 90) ORIENTATIONS.append(Surface.ROTATION_90, 0) ORIENTATIONS.append(Surface.ROTATION_180, 270) ORIENTATIONS.append(Surface.ROTATION_270, 180) } /** * Get the angle by which an image must be rotated given the device's current * orientation. */ @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) @Throws(CameraAccessException::class) private fun getRotationCompensation(cameraId: String, activity: Activity, context: Context): Int { // Get the device's current rotation relative to its "native" orientation. // Then, from the ORIENTATIONS table, look up the angle the image must be // rotated to compensate for the device's rotation. val deviceRotation = activity.windowManager.defaultDisplay.rotation var rotationCompensation = ORIENTATIONS.get(deviceRotation) // On most devices, the sensor orientation is 90 degrees, but for some // devices it is 270 degrees. For devices with a sensor orientation of // 270, rotate the image an additional 180 ((270 + 270) % 360) degrees. val cameraManager = context.getSystemService(CAMERA_SERVICE) as CameraManager val sensorOrientation = cameraManager .getCameraCharacteristics(cameraId) .get(CameraCharacteristics.SENSOR_ORIENTATION)!! rotationCompensation = (rotationCompensation + sensorOrientation + 270) % 360 // Return the corresponding FirebaseVisionImageMetadata rotation value. val result: Int when (rotationCompensation) { 0 -> result = FirebaseVisionImageMetadata.ROTATION_0 90 -> result = FirebaseVisionImageMetadata.ROTATION_90 180 -> result = FirebaseVisionImageMetadata.ROTATION_180 270 -> result = FirebaseVisionImageMetadata.ROTATION_270 else -> { result = FirebaseVisionImageMetadata.ROTATION_0 Log.e(TAG, "Bad rotation value: $rotationCompensation") } } return result }
Następnie przekaż obiekt
media.Image
oraz wartość rotacji doFirebaseVisionImage.fromMediaImage()
:Java
FirebaseVisionImage image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation);
Kotlin+KTX
val image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation)
- Aby utworzyć obiekt
FirebaseVisionImage
na podstawie identyfikatora URI pliku, przekaż kontekst aplikacji i identyfikator URI plikuFirebaseVisionImage.fromFilePath()
Jest to przydatne, gdy użyj intencjiACTION_GET_CONTENT
, aby zachęcić użytkownika do wyboru obraz z aplikacji Galeria.Java
FirebaseVisionImage image; try { image = FirebaseVisionImage.fromFilePath(context, uri); } catch (IOException e) { e.printStackTrace(); }
Kotlin+KTX
val image: FirebaseVisionImage try { image = FirebaseVisionImage.fromFilePath(context, uri) } catch (e: IOException) { e.printStackTrace() }
- Aby utworzyć obiekt
FirebaseVisionImage
na podstawieByteBuffer
lub tablicy bajtów, najpierw oblicz wartość obrazu w sposób opisany powyżej dla danych wejściowychmedia.Image
.Następnie utwórz obiekt
FirebaseVisionImageMetadata
określającą wysokość, szerokość i format kodowania kolorów obrazu i rotacja:Java
FirebaseVisionImageMetadata metadata = new FirebaseVisionImageMetadata.Builder() .setWidth(480) // 480x360 is typically sufficient for .setHeight(360) // image recognition .setFormat(FirebaseVisionImageMetadata.IMAGE_FORMAT_NV21) .setRotation(rotation) .build();
Kotlin+KTX
val metadata = FirebaseVisionImageMetadata.Builder() .setWidth(480) // 480x360 is typically sufficient for .setHeight(360) // image recognition .setFormat(FirebaseVisionImageMetadata.IMAGE_FORMAT_NV21) .setRotation(rotation) .build()
Za pomocą bufora lub tablicy oraz obiektu metadanych utwórz
FirebaseVisionImage
obiekt:Java
FirebaseVisionImage image = FirebaseVisionImage.fromByteBuffer(buffer, metadata); // Or: FirebaseVisionImage image = FirebaseVisionImage.fromByteArray(byteArray, metadata);
Kotlin+KTX
val image = FirebaseVisionImage.fromByteBuffer(buffer, metadata) // Or: val image = FirebaseVisionImage.fromByteArray(byteArray, metadata)
- Aby utworzyć obiekt
FirebaseVisionImage
na podstawie ObiektBitmap
:Java
FirebaseVisionImage image = FirebaseVisionImage.fromBitmap(bitmap);
Kotlin+KTX
val image = FirebaseVisionImage.fromBitmap(bitmap)
Bitmap
musi być pionowo bez konieczności dodatkowego obracania.
-
Pobierz instancję
FirebaseVisionDocumentTextRecognizer
:Java
FirebaseVisionDocumentTextRecognizer detector = FirebaseVision.getInstance() .getCloudDocumentTextRecognizer();
// Or, to provide language hints to assist with language detection: // See https://cloud.google.com/vision/docs/languages for supported languages FirebaseVisionCloudDocumentRecognizerOptions options = new FirebaseVisionCloudDocumentRecognizerOptions.Builder() .setLanguageHints(Arrays.asList("en", "hi")) .build(); FirebaseVisionDocumentTextRecognizer detector = FirebaseVision.getInstance() .getCloudDocumentTextRecognizer(options);
Kotlin+KTX
val detector = FirebaseVision.getInstance() .cloudDocumentTextRecognizer
// Or, to provide language hints to assist with language detection: // See https://cloud.google.com/vision/docs/languages for supported languages val options = FirebaseVisionCloudDocumentRecognizerOptions.Builder() .setLanguageHints(listOf("en", "hi")) .build() val detector = FirebaseVision.getInstance() .getCloudDocumentTextRecognizer(options)
Na koniec przekaż obraz do metody
processImage
:Java
detector.processImage(myImage) .addOnSuccessListener(new OnSuccessListener<FirebaseVisionDocumentText>() { @Override public void onSuccess(FirebaseVisionDocumentText result) { // Task completed successfully // ... } }) .addOnFailureListener(new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { // Task failed with an exception // ... } });
Kotlin+KTX
detector.processImage(myImage) .addOnSuccessListener { firebaseVisionDocumentText -> // Task completed successfully // ... } .addOnFailureListener { e -> // Task failed with an exception // ... }
2. Wyodrębnianie tekstu z bloków rozpoznanego tekstu
Jeśli rozpoznawanie tekstu się powiedzie, zwróci błąd
FirebaseVisionDocumentText
. O
Obiekt FirebaseVisionDocumentText
zawiera pełny tekst rozpoznany w
i hierarchię obiektów, które odzwierciedlają strukturę rozpoznawanych
dokument:
FirebaseVisionDocumentText.Block
FirebaseVisionDocumentText.Paragraph
FirebaseVisionDocumentText.Word
FirebaseVisionDocumentText.Symbol
Dla każdego obiektu Block
, Paragraph
, Word
i Symbol
można uzyskać
tekstu rozpoznawanego w regionie oraz jego współrzędnych geograficznych.
Przykład:
Java
String resultText = result.getText(); for (FirebaseVisionDocumentText.Block block: result.getBlocks()) { String blockText = block.getText(); Float blockConfidence = block.getConfidence(); List<RecognizedLanguage> blockRecognizedLanguages = block.getRecognizedLanguages(); Rect blockFrame = block.getBoundingBox(); for (FirebaseVisionDocumentText.Paragraph paragraph: block.getParagraphs()) { String paragraphText = paragraph.getText(); Float paragraphConfidence = paragraph.getConfidence(); List<RecognizedLanguage> paragraphRecognizedLanguages = paragraph.getRecognizedLanguages(); Rect paragraphFrame = paragraph.getBoundingBox(); for (FirebaseVisionDocumentText.Word word: paragraph.getWords()) { String wordText = word.getText(); Float wordConfidence = word.getConfidence(); List<RecognizedLanguage> wordRecognizedLanguages = word.getRecognizedLanguages(); Rect wordFrame = word.getBoundingBox(); for (FirebaseVisionDocumentText.Symbol symbol: word.getSymbols()) { String symbolText = symbol.getText(); Float symbolConfidence = symbol.getConfidence(); List<RecognizedLanguage> symbolRecognizedLanguages = symbol.getRecognizedLanguages(); Rect symbolFrame = symbol.getBoundingBox(); } } } }
Kotlin+KTX
val resultText = result.text for (block in result.blocks) { val blockText = block.text val blockConfidence = block.confidence val blockRecognizedLanguages = block.recognizedLanguages val blockFrame = block.boundingBox for (paragraph in block.paragraphs) { val paragraphText = paragraph.text val paragraphConfidence = paragraph.confidence val paragraphRecognizedLanguages = paragraph.recognizedLanguages val paragraphFrame = paragraph.boundingBox for (word in paragraph.words) { val wordText = word.text val wordConfidence = word.confidence val wordRecognizedLanguages = word.recognizedLanguages val wordFrame = word.boundingBox for (symbol in word.symbols) { val symbolText = symbol.text val symbolConfidence = symbol.confidence val symbolRecognizedLanguages = symbol.recognizedLanguages val symbolFrame = symbol.boundingBox } } } }
Dalsze kroki
- Przed wdrożeniem w środowisku produkcyjnym aplikacji korzystającej z interfejsu Cloud API wykonaj dodatkowe kroki, które zapobiegają i ograniczają efekt nieautoryzowanego dostępu do interfejsu API.