Możesz użyć ML Kit do rozpoznawania tekstu na obrazach. ML Kit ma zarówno interfejs API ogólnego przeznaczenia, odpowiedni do rozpoznawania tekstu na obrazach, taki jak tekst znaku ulicznego, oraz interfejs API zoptymalizowany do rozpoznawania tekstu dokumentów. Interfejs API ogólnego przeznaczenia ma zarówno modele na urządzeniu, jak i w chmurze. Rozpoznawanie tekstu dokumentu jest dostępne tylko jako model oparty na chmurze. Zobacz przegląd , aby porównać modele w chmurze i na urządzeniu.
Zanim zaczniesz
- Jeśli jeszcze tego nie zrobiłeś, dodaj Firebase do swojego projektu na Androida .
- Dodaj zależności dla bibliotek ML Kit dla systemu Android 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 korzystasz z 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 następującą deklarację do pliku
AndroidManifest.xml
swojej aplikacji:<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 nie włączysz pobierania modelu w czasie instalacji, model zostanie pobrany przy pierwszym uruchomieniu detektora na urządzeniu. Żądania złożone przed zakończeniem pobierania nie przyniosą żadnych wyników. Jeśli chcesz korzystać z modelu opartego na chmurze, a nie masz jeszcze włączonych interfejsów API opartych na chmurze dla swojego projektu, zrób to teraz:
- Otwórz stronę ML Kit APIs w konsoli Firebase.
Jeśli Twój projekt nie został jeszcze uaktualniony 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 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 zacząć rozpoznawać tekst na obrazach.
Wskazówki dotyczące obrazu wejściowego
Aby zestaw ML Kit mógł dokładnie rozpoznać tekst, obrazy wejściowe muszą zawierać tekst reprezentowany przez wystarczającą ilość danych pikseli. Idealnie, w przypadku tekstu łacińskiego, każdy znak powinien mieć co najmniej 16x16 pikseli. W przypadku tekstu w języku chińskim, japońskim i koreańskim (obsługiwane tylko przez interfejsy API oparte na chmurze) każdy znak powinien mieć wymiary 24 x 24 piksele. W przypadku wszystkich języków nie ma na ogół żadnej korzyści z dokładności w przypadku znaków większych niż 24x24 piksele.
Na przykład obraz 640x480 może dobrze się sprawdzić w przypadku wizytówki zajmującej całą szerokość obrazu. Aby zeskanować dokument wydrukowany na papierze formatu Letter, może być wymagany obraz o wymiarach 720x1280 pikseli.
Słaba ostrość obrazu może zaszkodzić dokładności rozpoznawania tekstu. Jeśli nie uzyskujesz zadowalających wyników, poproś użytkownika o ponowne przechwycenie obrazu.
Jeśli rozpoznajesz tekst w aplikacji działającej w czasie rzeczywistym, możesz również wziąć pod uwagę 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ęcej obrazu. Zobacz także Wskazówki dotyczące poprawy wydajności w czasie rzeczywistym .
Rozpoznawaj tekst na obrazach
Aby rozpoznać tekst na obrazie przy użyciu modelu na urządzeniu lub w chmurze, uruchom aparat rozpoznawania tekstu zgodnie z poniższym opisem.
1. Uruchom aparat rozpoznawania tekstu
Aby rozpoznać tekst w obrazie, utwórz obiektFirebaseVisionImage
z Bitmap
, media.Image
, ByteBuffer
, tablicy bajtów lub pliku na urządzeniu. Następnie przekaż obiekt FirebaseVisionImage
do metody FirebaseVisionTextRecognizer
processImage
.Utwórz obiekt
FirebaseVisionImage
z obrazu.Aby utworzyć obiekt
FirebaseVisionImage
z obiektumedia.Image
, na przykład podczas przechwytywania obrazu z aparatu urządzenia, przekaż obiektmedia.Image
i obrót obrazu do funkcjiFirebaseVisionImage.fromMediaImage()
.Jeśli używasz biblioteki CameraX , klasy
OnImageCapturedListener
iImageAnalysis.Analyzer
obliczają wartość obrotu za Ciebie, więc wystarczy przekonwertować obrót 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+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, która podaje obrót obrazu, możesz to obliczyć na podstawie obrotu 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+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
i wartość obrotu doFirebaseVisionImage.fromMediaImage()
:Java
FirebaseVisionImage image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation);
Kotlin+KTX
val image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation)
- Aby utworzyć obiekt
FirebaseVisionImage
z identyfikatora URI pliku, przekaż kontekst aplikacji i identyfikator URI pliku doFirebaseVisionImage.fromFilePath()
. Jest to przydatne, gdy używasz intencjiACTION_GET_CONTENT
, aby skłonić użytkownika do wybrania obrazu z jego aplikacji galerii.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
zByteBuffer
lub tablicy bajtów, najpierw oblicz obrót obrazu zgodnie z powyższym opisem dla danych wejściowychmedia.Image
.Następnie utwórz obiekt
FirebaseVisionImageMetadata
zawierający wysokość, szerokość, format kodowania kolorów i obrót 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+KTX
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 buforu lub tablicy oraz obiektu metadanych, aby utworzyć obiekt
FirebaseVisionImage
: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
z obiektuBitmap
:Obraz reprezentowany przez obiektJava
FirebaseVisionImage image = FirebaseVisionImage.fromBitmap(bitmap);
Kotlin+KTX
val image = FirebaseVisionImage.fromBitmap(bitmap)
Bitmap
musi być ustawiony pionowo, bez konieczności dodatkowego obracania.
Pobierz wystąpienie
FirebaseVisionTextRecognizer
.Aby użyć modelu na urządzeniu:
Java
FirebaseVisionTextRecognizer detector = FirebaseVision.getInstance() .getOnDeviceTextRecognizer();
Kotlin+KTX
val detector = FirebaseVision.getInstance() .onDeviceTextRecognizer
Aby skorzystać z 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+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ębnij tekst z bloków rozpoznanego tekstu
Jeśli operacja rozpoznawania tekstu się powiedzie, obiektFirebaseVisionText
zostanie przekazany do detektora sukcesu. Obiekt FirebaseVisionText
zawiera pełny tekst rozpoznany na obrazie oraz zero lub więcej obiektów TextBlock
. Każdy TextBlock
reprezentuje prostokątny blok tekstu, który zawiera zero lub więcej obiektów Line
. Każdy obiekt Line
zawiera zero lub więcej obiektów Element
, które reprezentują słowa i elementy słowopodobne (daty, liczby itd.).
Dla każdego obiektu TextBlock
, Line
i Element
można uzyskać tekst rozpoznawany w regionie oraz współrzędne ograniczające regionu.
Na 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 wydajnoś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 poniższymi wskazówkami, aby uzyskać najlepszą liczbę klatek na sekundę:
- Ograniczaj wywołania aparatu rozpoznawania tekstu. Jeśli nowa ramka wideo stanie się dostępna, gdy aparat rozpoznawania tekstu jest uruchomiony, upuść ramkę.
- Jeśli używasz danych wyjściowych aparatu rozpoznawania tekstu do nakładania grafiki na obraz wejściowy, najpierw pobierz wynik z ML Kit, a następnie wyrenderuj obraz i nakładkę w jednym kroku. W ten sposób renderujesz na powierzchnię wyświetlania tylko raz dla każdej klatki wejściowej.
W przypadku korzystania z interfejsu API Camera2 przechwytywanie obrazów w formacie
ImageFormat.YUV_420_888
.Jeśli używasz starszego interfejsu Camera API, przechwytuj obrazy w formacie
ImageFormat.NV21
.- Rozważ robienie zdjęć w niższej rozdzielczości. Należy jednak pamiętać o wymaganiach dotyczących wymiarów obrazu tego interfejsu API.
Następne kroki
- Przed wdrożeniem w środowisku produkcyjnym aplikacji korzystającej z interfejsu Cloud API należy podjąć dodatkowe kroki, aby zapobiec nieautoryzowanemu dostępowi do interfejsu API i złagodzić jego skutki .
Rozpoznawaj tekst na obrazach dokumentów
Aby rozpoznać tekst dokumentu, skonfiguruj i uruchom oparty na chmurze aparat rozpoznawania tekstu dokumentu zgodnie z poniższym opisem.
Opisany poniżej interfejs API rozpoznawania tekstu dokumentu zapewnia interfejs, który ma być wygodniejszy do pracy z obrazami dokumentów. Jeśli jednak wolisz interfejs udostępniany przez interfejs API FirebaseVisionTextRecognizer
, możesz go użyć do skanowania dokumentów, konfigurując aparat rozpoznawania tekstu w chmurze tak, aby używał modelu gęstego tekstu .
Aby użyć interfejsu API rozpoznawania tekstu dokumentu:
1. Uruchom aparat rozpoznawania tekstu
Aby rozpoznać tekst w obrazie, utwórz obiektFirebaseVisionImage
z Bitmap
, media.Image
, ByteBuffer
, tablicy bajtów lub pliku na urządzeniu. Następnie przekaż obiekt FirebaseVisionImage
do metody FirebaseVisionDocumentTextRecognizer
processImage
.Utwórz obiekt
FirebaseVisionImage
z obrazu.Aby utworzyć obiekt
FirebaseVisionImage
z obiektumedia.Image
, na przykład podczas przechwytywania obrazu z aparatu urządzenia, przekaż obiektmedia.Image
i obrót obrazu do funkcjiFirebaseVisionImage.fromMediaImage()
.Jeśli używasz biblioteki CameraX , klasy
OnImageCapturedListener
iImageAnalysis.Analyzer
obliczają wartość obrotu za Ciebie, więc wystarczy przekonwertować obrót 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+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, która podaje obrót obrazu, możesz to obliczyć na podstawie obrotu 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+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
i wartość obrotu doFirebaseVisionImage.fromMediaImage()
:Java
FirebaseVisionImage image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation);
Kotlin+KTX
val image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation)
- Aby utworzyć obiekt
FirebaseVisionImage
z identyfikatora URI pliku, przekaż kontekst aplikacji i identyfikator URI pliku doFirebaseVisionImage.fromFilePath()
. Jest to przydatne, gdy używasz intencjiACTION_GET_CONTENT
, aby skłonić użytkownika do wybrania obrazu z jego aplikacji galerii.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
zByteBuffer
lub tablicy bajtów, najpierw oblicz obrót obrazu zgodnie z powyższym opisem dla danych wejściowychmedia.Image
.Następnie utwórz obiekt
FirebaseVisionImageMetadata
zawierający wysokość, szerokość, format kodowania kolorów i obrót 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+KTX
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 buforu lub tablicy oraz obiektu metadanych, aby utworzyć obiekt
FirebaseVisionImage
: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
z obiektuBitmap
:Obraz reprezentowany przez obiektJava
FirebaseVisionImage image = FirebaseVisionImage.fromBitmap(bitmap);
Kotlin+KTX
val image = FirebaseVisionImage.fromBitmap(bitmap)
Bitmap
musi być ustawiony 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ębnij tekst 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, która odzwierciedla strukturę rozpoznanego dokumentu:
-
FirebaseVisionDocumentText.Block
-
FirebaseVisionDocumentText.Paragraph
-
FirebaseVisionDocumentText.Word
-
FirebaseVisionDocumentText.Symbol
Dla każdego obiektu Block
, Paragraph
, Word
i Symbol
można uzyskać tekst rozpoznawany w regionie oraz współrzędne ograniczające regionu.
Na 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 } } } }
Następne kroki
- Przed wdrożeniem w środowisku produkcyjnym aplikacji korzystającej z interfejsu Cloud API należy podjąć dodatkowe kroki, aby zapobiec nieautoryzowanemu dostępowi do interfejsu API i złagodzić jego skutki .