Można użyć ML Zestaw etykiet do obiektów ujętych w obrazie, przy użyciu modelu na urządzeniu lub modelu chmury. Zobacz przegląd , aby dowiedzieć się o korzyściach płynących z każdego podejścia.
Zanim zaczniesz
- Jeśli jeszcze tego nie zrobiłeś, dodaj Firebase do swojego projektu na Androida .
- Dodaj zależności dla bibliotek ML Kit Android do modułu (ok szczebla) Gradle plików (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' implementation 'com.google.firebase:firebase-ml-vision-image-label-model:20.0.1' }
- Opcjonalne, ale zalecane : W przypadku korzystania z interfejsu API na urządzeniu, należy skonfigurować aplikację do automatycznego pobierania modelu ML do urządzenia po zainstalowaniu aplikacja ze Sklepu Play.
Aby to zrobić, należy dodać następującą deklarację do swojej aplikacji
AndroidManifest.xml
pliku:<application ...> ... <meta-data android:name="com.google.firebase.ml.vision.DEPENDENCIES" android:value="label" /> <!-- To use multiple models: android:value="label,model2,model3" --> </application>
Jeśli nie pozwalają zainstalować czasie modelowych pobieranie, model zostanie pobrana przy pierwszym uruchomieniu czujki na urządzeniu. Żąda dokonać przed zakończeniu pobierania przyniesie żadnych rezultatów. Jeśli chcesz korzystać z modelu opartego na chmurze, a nie masz już włączone API chmurowej się do projektu, należy to zrobić teraz:
- Otwórz stronę ML Kit API konsoli Firebase.
Jeśli nie masz już uaktualniony projekt do planu cenowego Blaze, kliknij przycisk Zmień , aby to zrobić. (Zostaniesz poproszony, aby uaktualnić tylko jeśli projekt nie jest na planie Blaze).
Jedynie projekty Blaze szczebla mogą używać API chmurowej.
- Jeśli API w chmurze nie są już włączone, kliknij przycisk Włącz API chmurowej .
Jeśli chcesz korzystać tylko z modelu na urządzeniu, można pominąć ten krok.
Teraz jesteś gotowy do obrazów etykiety z zastosowaniem zarówno modelu na urządzeniu lub model w chmurze.
1. Przygotować obraz wejściowy
TworzenieFirebaseVisionImage
obiektu z obrazu. Etykieciarki obrazu przebiega najszybciej w przypadku korzystania z map Bitmap
lub, w przypadku korzystania z interfejsu API Camera2, JPEG-sformatowany media.Image
, które są zalecane, jeśli to możliwe.Aby utworzyć
FirebaseVisionImage
obiektu zmedia.Image
obiektu, na przykład podczas wykonywania obrazu z kamery dla urządzenia, przechodząmedia.Image
przedmiotu i obrót obrazka doFirebaseVisionImage.fromMediaImage()
.Jeśli używasz CameraX bibliotekę,
OnImageCapturedListener
iImageAnalysis.Analyzer
klas obliczyć wartość obrotu dla Ciebie, więc po prostu trzeba konwertować obrót jednego ML KitROTATION_
stałych 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 korzystać z biblioteki aparatu, który daje obracanie obrazka, można go obliczyć z 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 przechodzi się
media.Image
przedmiotu oraz wartość rotacji doFirebaseVisionImage.fromMediaImage()
:Java
FirebaseVisionImage image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation);
Kotlin+KTX
val image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation)
- Aby utworzyć
FirebaseVisionImage
obiekt z pliku URI, przekaż kontekst aplikacji i plików URIFirebaseVisionImage.fromFilePath()
. Jest to przydatne w przypadku korzystania zACTION_GET_CONTENT
zamiar skłonić użytkownika, aby wybrać zdjęcie z galerii ich aplikacji.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ć
FirebaseVisionImage
obiektu zByteBuffer
lub tablicy bajtów najpierw obliczenie obracanie obrazu, jak opisano powyżej dlamedia.Image
wejścia.Następnie utwórz
FirebaseVisionImageMetadata
obiekt, który zawiera obraz na wysokość, szerokość, kolor, format kodowania i obrót: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ą buforu lub tablicę, a obiekt metadanych w celu utworzenia
FirebaseVisionImage
obiektu: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ć
FirebaseVisionImage
obiekt zBitmap
obiektu:Obraz przedstawiony przezJava
FirebaseVisionImage image = FirebaseVisionImage.fromBitmap(bitmap);
Kotlin+KTX
val image = FirebaseVisionImage.fromBitmap(bitmap)
Bitmap
obiektu musi być wyprostowany, bez dodatkowego obrotu wymagane.
2. Konfiguracja i uruchomienie Image Labeler
Do etykiety obiektów w obrazie, przechodząFirebaseVisionImage
obiekt do FirebaseVisionImageLabeler
jest processImage
metody.Po pierwsze, uzyskać instancję
FirebaseVisionImageLabeler
.Jeśli chcesz użyć obrazu Labeler na urządzenie:
Java
FirebaseVisionImageLabeler labeler = FirebaseVision.getInstance() .getOnDeviceImageLabeler(); // Or, to set the minimum confidence required: // FirebaseVisionOnDeviceImageLabelerOptions options = // new FirebaseVisionOnDeviceImageLabelerOptions.Builder() // .setConfidenceThreshold(0.7f) // .build(); // FirebaseVisionImageLabeler labeler = FirebaseVision.getInstance() // .getOnDeviceImageLabeler(options);
Kotlin+KTX
val labeler = FirebaseVision.getInstance().getOnDeviceImageLabeler() // Or, to set the minimum confidence required: // val options = FirebaseVisionOnDeviceImageLabelerOptions.Builder() // .setConfidenceThreshold(0.7f) // .build() // val labeler = FirebaseVision.getInstance().getOnDeviceImageLabeler(options)
Jeśli chcesz użyć Labeler chmura obrazka:
Java
FirebaseVisionImageLabeler labeler = FirebaseVision.getInstance() .getCloudImageLabeler(); // Or, to set the minimum confidence required: // FirebaseVisionCloudImageLabelerOptions options = // new FirebaseVisionCloudImageLabelerOptions.Builder() // .setConfidenceThreshold(0.7f) // .build(); // FirebaseVisionImageLabeler labeler = FirebaseVision.getInstance() // .getCloudImageLabeler(options);
Kotlin+KTX
val labeler = FirebaseVision.getInstance().getCloudImageLabeler() // Or, to set the minimum confidence required: // val options = FirebaseVisionCloudImageLabelerOptions.Builder() // .setConfidenceThreshold(0.7f) // .build() // val labeler = FirebaseVision.getInstance().getCloudImageLabeler(options)
Następnie przechodzi się obraz na
processImage()
sposobu:Java
labeler.processImage(image) .addOnSuccessListener(new OnSuccessListener<List<FirebaseVisionImageLabel>>() { @Override public void onSuccess(List<FirebaseVisionImageLabel> labels) { // Task completed successfully // ... } }) .addOnFailureListener(new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { // Task failed with an exception // ... } });
Kotlin+KTX
labeler.processImage(image) .addOnSuccessListener { labels -> // Task completed successfully // ... } .addOnFailureListener { e -> // Task failed with an exception // ... }
3. Uzyskaj informacje o oznakowanych obiektów
Jeśli operacja się powiedzie etykietowanie obraz, wykazFirebaseVisionImageLabel
obiektów zostaną przekazane do słuchacza sukcesu. Każdy FirebaseVisionImageLabel
obiekt reprezentuje coś, który został oznaczony w obrazie. Na każdej etykiecie, można uzyskać opis etykiety tekstowe, jego wiedzy Graph identyfikatorze jednostki (jeśli jest dostępny), a wynik ufności meczu. Na przykład: Java
for (FirebaseVisionImageLabel label: labels) {
String text = label.getText();
String entityId = label.getEntityId();
float confidence = label.getConfidence();
}
Kotlin+KTX
for (label in labels) {
val text = label.text
val entityId = label.entityId
val confidence = label.confidence
}
Jak poprawić wydajność w czasie rzeczywistym
Jeśli chcesz obrazów etykiet w aplikacji w czasie rzeczywistym, należy przestrzegać następujących zasad, aby osiągnąć najlepsze klatek na sekundę:
- Zawrotna szybkość połączenia do Labeler obrazu. Jeśli nowa rama wideo staje się dostępna, gdy etykieciarka obraz jest uruchomiony, usunąć klatkę.
- Jeśli używasz wyjście Image Labeler do nakładanie grafiki na obrazie wejściowym, najpierw uzyskać wynik z ML Kit, a następnie renderować obraz i nakładki w jednym kroku. W ten sposób można renderować do powierzchni wyświetlacza tylko raz dla każdej ramki wejściowej.
Jeśli używasz API Camera2, wykonywanie zdjęć w
ImageFormat.YUV_420_888
formacie.Jeśli używasz starszej API aparatu, wykonywanie zdjęć w
ImageFormat.NV21
formacie.
Następne kroki
- Przed wdrożeniem do produkcji aplikacji, która korzysta z interfejsu API Cloud, należy podjąć dodatkowe kroki w celu zapobiegania i łagodzenia skutków nieautoryzowanego dostępu API .