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 korzystasz jeszcze z Firebase, dodaj tę usługę do projektu aplikacji na Androida.
- Dodaj zależności dla bibliotek ML Kit na Androida do pliku Gradle modułu (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 na urządzeniu, skonfiguruj aplikację tak, aby automatycznie pobierała model ML na urządzenie po zainstalowaniu aplikacji ze Sklepu Play.
Aby to zrobić, dodaj do pliku
AndroidManifest.xml
aplikacji tę deklarację: Jeśli nie włączysz pobierania modelu podczas instalacji, model zostanie pobrany przy pierwszym uruchomieniu detektora na urządzeniu. Żądania wysłane przed zakończeniem pobierania nie przyniosą ż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 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
Aby rozpoznać tekst na obrazie, utwórz obiektFirebaseVisionImage
z obiektu Bitmap
, media.Image
, ByteBuffer
, tablicy bajtów lub pliku na urządzeniu. Następnie przekaż obiekt FirebaseVisionImage
do metody processImage
obiektu FirebaseVisionTextRecognizer
.
Utwórz obiekt
FirebaseVisionImage
na podstawie obrazu.-
Aby utworzyć obiekt
FirebaseVisionImage
z obiektumedia.Image
, np. podczas przechwytywania obrazu z aparatu urządzenia, przekaż obiektmedia.Image
i obrót obrazu doFirebaseVisionImage.fromMediaImage()
.Jeśli używasz biblioteki CameraX, klasy
OnImageCapturedListener
iImageAnalysis.Analyzer
obliczają wartość rotacji, więc wystarczy przekonwertować rotację na jedną ze stałychROTATION_
ML Kit przed wywołaniemFirebaseVisionImage.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
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 używasz biblioteki aparatu, która podaje rotację obrazu, możesz obliczyć ją na podstawie rotacji urządzenia i orientacji czujnika aparatu 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
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
i wartość obrotu doFirebaseVisionImage.fromMediaImage()
:Java
FirebaseVisionImage image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation);
Kotlin
val image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation)
- Aby utworzyć obiekt
FirebaseVisionImage
z identyfikatora URI pliku, przekaż kontekst aplikacji i identyfikator URI pliku do funkcjiFirebaseVisionImage.fromFilePath()
. Jest to przydatne, gdy używasz intencjiACTION_GET_CONTENT
, aby poprosić użytkownika o wybranie obrazu z aplikacji galerii.Java
FirebaseVisionImage image; try { image = FirebaseVisionImage.fromFilePath(context, uri); } catch (IOException e) { e.printStackTrace(); }
Kotlin
val image: FirebaseVisionImage try { image = FirebaseVisionImage.fromFilePath(context, uri) } catch (e: IOException) { e.printStackTrace() }
- Aby utworzyć obiekt
FirebaseVisionImage
z obiektuByteBuffer
lub tablicy bajtów, najpierw oblicz rotację obrazu zgodnie z opisem powyżej dla danych wejściowychmedia.Image
.Następnie utwórz
FirebaseVisionImageMetadata
obiekt, który zawiera wysokość, szerokość, format kodowania kolorów i rotację obrazu: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
val metadata = FirebaseVisionImageMetadata.Builder() .setWidth(480) // 480x360 is typically sufficient for .setHeight(360) // image recognition .setFormat(FirebaseVisionImageMetadata.IMAGE_FORMAT_NV21) .setRotation(rotation) .build()
Użyj bufora lub tablicy oraz obiektu metadanych, aby utworzyć obiekt
FirebaseVisionImage
:Java
FirebaseVisionImage image = FirebaseVisionImage.fromByteBuffer(buffer, metadata); // Or: FirebaseVisionImage image = FirebaseVisionImage.fromByteArray(byteArray, metadata);
Kotlin
val image = FirebaseVisionImage.fromByteBuffer(buffer, metadata) // Or: val image = FirebaseVisionImage.fromByteArray(byteArray, metadata)
- Aby utworzyć obiekt
FirebaseVisionImage
z obiektuBitmap
:Java
FirebaseVisionImage image = FirebaseVisionImage.fromBitmap(bitmap);
Kotlin
val image = FirebaseVisionImage.fromBitmap(bitmap)
Bitmap
musi być w pozycji pionowej i nie wymagać dodatkowego obracania.
-
Uzyskaj instancję
FirebaseVisionTextRecognizer
.Aby użyć modelu na urządzeniu:
Java
FirebaseVisionTextRecognizer detector = FirebaseVision.getInstance() .getOnDeviceTextRecognizer();
Kotlin
val detector = FirebaseVision.getInstance() .onDeviceTextRecognizer
Aby użyć modelu opartego na 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
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
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 operacja rozpoznawania tekstu się powiedzie, do odbiornika sukcesu zostanie przekazany obiektFirebaseVisionText
. Obiekt FirebaseVisionText
zawiera pełny tekst rozpoznany na obrazie oraz co najmniej 1 obiekt TextBlock
.
Każdy element TextBlock
reprezentuje prostokątny blok tekstu, który zawiera co najmniej 1 obiekt Line
. Każdy obiekt Line
zawiera 0 lub więcej obiektów Element
, które reprezentują słowa i podobieństwa do słów (daty, liczby itp.).
W przypadku każdego obiektu TextBlock
, Line
i Element
możesz uzyskać tekst rozpoznany w regionie oraz współrzędne ograniczające region.
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
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 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.
-
Jeśli używasz interfejsu Camera2 API, rób zdjęcia w formacie
ImageFormat.YUV_420_888
.Jeśli używasz starszego interfejsu Camera API, rób zdjęcia w formacie
ImageFormat.NV21
. - 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 FirebaseVisionTextRecognizer
API, możesz go używać do skanowania dokumentów, konfigurując rozpoznawanie tekstu w chmurze tak, aby używać modelu tekstu o dużej gęstości.
Aby użyć interfejsu API do rozpoznawania tekstu w dokumentach:
1. Uruchom rozpoznawanie tekstu
Aby rozpoznać tekst na obrazie, utwórz obiektFirebaseVisionImage
z Bitmap
, media.Image
, ByteBuffer
, tablicy bajtów lub pliku na urządzeniu.
Następnie przekaż obiekt FirebaseVisionImage
do metody processImage
obiektu FirebaseVisionDocumentTextRecognizer
.
Utwórz obiekt
FirebaseVisionImage
na podstawie obrazu.-
Aby utworzyć obiekt
FirebaseVisionImage
z obiektumedia.Image
, np. podczas przechwytywania obrazu z aparatu urządzenia, przekaż obiektmedia.Image
i obrót obrazu doFirebaseVisionImage.fromMediaImage()
.Jeśli używasz biblioteki CameraX, klasy
OnImageCapturedListener
iImageAnalysis.Analyzer
obliczają wartość rotacji, więc wystarczy przekonwertować rotację na jedną ze stałychROTATION_
ML Kit przed wywołaniemFirebaseVisionImage.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
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 używasz biblioteki aparatu, która podaje rotację obrazu, możesz obliczyć ją na podstawie rotacji urządzenia i orientacji czujnika aparatu 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
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
i wartość obrotu doFirebaseVisionImage.fromMediaImage()
:Java
FirebaseVisionImage image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation);
Kotlin
val image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation)
- Aby utworzyć obiekt
FirebaseVisionImage
z identyfikatora URI pliku, przekaż kontekst aplikacji i identyfikator URI pliku do funkcjiFirebaseVisionImage.fromFilePath()
. Jest to przydatne, gdy używasz intencjiACTION_GET_CONTENT
, aby poprosić użytkownika o wybranie obrazu z aplikacji galerii.Java
FirebaseVisionImage image; try { image = FirebaseVisionImage.fromFilePath(context, uri); } catch (IOException e) { e.printStackTrace(); }
Kotlin
val image: FirebaseVisionImage try { image = FirebaseVisionImage.fromFilePath(context, uri) } catch (e: IOException) { e.printStackTrace() }
- Aby utworzyć obiekt
FirebaseVisionImage
z obiektuByteBuffer
lub tablicy bajtów, najpierw oblicz rotację obrazu zgodnie z opisem powyżej dla danych wejściowychmedia.Image
.Następnie utwórz
FirebaseVisionImageMetadata
obiekt, który zawiera wysokość, szerokość, format kodowania kolorów i rotację obrazu: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
val metadata = FirebaseVisionImageMetadata.Builder() .setWidth(480) // 480x360 is typically sufficient for .setHeight(360) // image recognition .setFormat(FirebaseVisionImageMetadata.IMAGE_FORMAT_NV21) .setRotation(rotation) .build()
Użyj bufora lub tablicy oraz obiektu metadanych, aby utworzyć obiekt
FirebaseVisionImage
:Java
FirebaseVisionImage image = FirebaseVisionImage.fromByteBuffer(buffer, metadata); // Or: FirebaseVisionImage image = FirebaseVisionImage.fromByteArray(byteArray, metadata);
Kotlin
val image = FirebaseVisionImage.fromByteBuffer(buffer, metadata) // Or: val image = FirebaseVisionImage.fromByteArray(byteArray, metadata)
- Aby utworzyć obiekt
FirebaseVisionImage
z obiektuBitmap
:Java
FirebaseVisionImage image = FirebaseVisionImage.fromBitmap(bitmap);
Kotlin
val image = FirebaseVisionImage.fromBitmap(bitmap)
Bitmap
musi być w pozycji pionowej i nie wymagać dodatkowego obracania.
-
Uzyskiwanie instancji
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
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
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 operacja rozpoznawania tekstu się powiedzie, zwróci obiekt FirebaseVisionDocumentText
. Obiekt FirebaseVisionDocumentText
zawiera pełny tekst rozpoznany na obrazie oraz hierarchię obiektów odzwierciedlającą strukturę rozpoznanego dokumentu:
FirebaseVisionDocumentText.Block
FirebaseVisionDocumentText.Paragraph
FirebaseVisionDocumentText.Word
FirebaseVisionDocumentText.Symbol
W przypadku każdego obiektu Block
, Paragraph
, Word
i Symbol
możesz uzyskać tekst rozpoznany w regionie oraz współrzędne ograniczające region.
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
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
- 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.