Mit dem ML Kit können Sie Ihrer App ganz einfach Funktionen zur Themensegmentierung hinzufügen.
<ph type="x-smartling-placeholder">Feature | Details |
---|---|
SDK-Name | play-services-mlkit-subject-segmentation |
Implementierung | Entbündelt: Das Modell wird mithilfe der Google Play-Dienste dynamisch heruntergeladen. |
Auswirkung auf die App-Größe | ca. 200 KB vergrößert. |
Initialisierungszeit | Nutzer müssen möglicherweise warten, bis das Modell heruntergeladen wurde, bevor sie es verwenden können. |
Jetzt ausprobieren
- Probieren Sie die Beispiel-App aus, um sehen Sie sich ein Anwendungsbeispiel für diese API an.
Hinweis
<ph type="x-smartling-placeholder">- Fügen Sie in der Datei
build.gradle
auf Projektebene das Maven-Repository von Google in die Abschnittebuildscript
undallprojects
ein. - Fügen Sie die Abhängigkeit für die ML Kit-Themensegmentierungsbibliothek zur Gradle-Datei auf App-Ebene Ihres Moduls hinzu, die normalerweise
app/build.gradle
lautet:
dependencies {
implementation 'com.google.android.gms:play-services-mlkit-subject-segmentation:16.0.0-beta1'
}
Wie bereits erwähnt, wird das Modell von den Google Play-Diensten bereitgestellt.
Du kannst deine App so konfigurieren, dass das Modell automatisch auf das Gerät heruntergeladen wird
nachdem deine App aus dem Play Store installiert wurde. Fügen Sie dazu Folgendes hinzu:
Deklaration in der Datei AndroidManifest.xml
deiner App an:
<application ...>
...
<meta-data
android:name="com.google.mlkit.vision.DEPENDENCIES"
android:value="subject_segment" >
<!-- To use multiple models: android:value="subject_segment,model2,model3" -->
</application>
Sie können mit der ModuleInstallClient API auch explizit die Modellverfügbarkeit prüfen und einen Download über die Google Play-Dienste anfordern.
Modelldownloads bei der Installation aktivieren oder expliziten Download anfordern: wird das Modell heruntergeladen, wenn Sie den Segmenter zum ersten Mal ausführen. Von Ihnen gestellte Anfragen bevor der Download abgeschlossen ist, keine Ergebnisse liefern.
1. Eingabebild vorbereiten
Wenn Sie ein Bild segmentieren möchten, erstellen Sie ein InputImage
-Objekt
aus einem Bitmap
-, media.Image
-, ByteBuffer
-, Byte-Array oder einer Datei in
auf dem Gerät.
Sie können eine InputImage
erstellen
aus verschiedenen Quellen stammen. Diese werden im Folgenden erläutert.
Mit einem media.Image
So erstellen Sie eine InputImage
:
media.Image
-Objekts erstellen, beispielsweise wenn Sie ein Bild von einem
des Geräts an, übergeben Sie das media.Image
-Objekt und die
Drehung auf InputImage.fromMediaImage()
.
Wenn Sie das
<ph type="x-smartling-placeholder"></ph>
CameraX-Bibliothek, den OnImageCapturedListener
und
ImageAnalysis.Analyzer
-Klassen berechnen den Rotationswert
für Sie.
Kotlin
private class YourImageAnalyzer : ImageAnalysis.Analyzer { override fun analyze(imageProxy: ImageProxy) { val mediaImage = imageProxy.image if (mediaImage != null) { val image = InputImage.fromMediaImage(mediaImage, imageProxy.imageInfo.rotationDegrees) // Pass image to an ML Kit Vision API // ... } } }
Java
private class YourAnalyzer implements ImageAnalysis.Analyzer { @Override public void analyze(ImageProxy imageProxy) { Image mediaImage = imageProxy.getImage(); if (mediaImage != null) { InputImage image = InputImage.fromMediaImage(mediaImage, imageProxy.getImageInfo().getRotationDegrees()); // Pass image to an ML Kit Vision API // ... } } }
Wenn Sie keine Kamerabibliothek verwenden, die Ihnen den Drehungsgrad des Bildes anzeigt, lässt sich anhand des Drehungsgrads des Geräts und der Ausrichtung der Kamera berechnen. Sensor im Gerät:
Kotlin
private val ORIENTATIONS = SparseIntArray() init { ORIENTATIONS.append(Surface.ROTATION_0, 0) ORIENTATIONS.append(Surface.ROTATION_90, 90) ORIENTATIONS.append(Surface.ROTATION_180, 180) ORIENTATIONS.append(Surface.ROTATION_270, 270) } /** * 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, isFrontFacing: Boolean): 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) // Get the device's sensor orientation. val cameraManager = activity.getSystemService(CAMERA_SERVICE) as CameraManager val sensorOrientation = cameraManager .getCameraCharacteristics(cameraId) .get(CameraCharacteristics.SENSOR_ORIENTATION)!! if (isFrontFacing) { rotationCompensation = (sensorOrientation + rotationCompensation) % 360 } else { // back-facing rotationCompensation = (sensorOrientation - rotationCompensation + 360) % 360 } return rotationCompensation }
Java
private static final SparseIntArray ORIENTATIONS = new SparseIntArray(); static { ORIENTATIONS.append(Surface.ROTATION_0, 0); ORIENTATIONS.append(Surface.ROTATION_90, 90); ORIENTATIONS.append(Surface.ROTATION_180, 180); ORIENTATIONS.append(Surface.ROTATION_270, 270); } /** * 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, boolean isFrontFacing) 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); // Get the device's sensor orientation. CameraManager cameraManager = (CameraManager) activity.getSystemService(CAMERA_SERVICE); int sensorOrientation = cameraManager .getCameraCharacteristics(cameraId) .get(CameraCharacteristics.SENSOR_ORIENTATION); if (isFrontFacing) { rotationCompensation = (sensorOrientation + rotationCompensation) % 360; } else { // back-facing rotationCompensation = (sensorOrientation - rotationCompensation + 360) % 360; } return rotationCompensation; }
Übergeben Sie dann das media.Image
-Objekt und den
Wert für Rotationsgrad auf InputImage.fromMediaImage()
:
Kotlin
val image = InputImage.fromMediaImage(mediaImage, rotation)
Java
InputImage image = InputImage.fromMediaImage(mediaImage, rotation);
Datei-URI verwenden
So erstellen Sie eine InputImage
:
aus einem Datei-URI entfernen möchten, übergeben Sie den App-Kontext und den Datei-URI an
InputImage.fromFilePath()
. Dies ist nützlich, wenn Sie
Verwenden Sie den Intent ACTION_GET_CONTENT
, um den Nutzer zur Auswahl aufzufordern
ein Bild aus ihrer Galerie-App.
Kotlin
val image: InputImage try { image = InputImage.fromFilePath(context, uri) } catch (e: IOException) { e.printStackTrace() }
Java
InputImage image; try { image = InputImage.fromFilePath(context, uri); } catch (IOException e) { e.printStackTrace(); }
ByteBuffer
oder ByteArray
verwenden
So erstellen Sie eine InputImage
:
aus einem ByteBuffer
- oder ByteArray
-Objekt zu erstellen, berechnen Sie
Drehung wie zuvor für die media.Image
-Eingabe beschrieben.
Erstellen Sie dann das InputImage
-Objekt mit dem Zwischenspeicher oder Array
Höhe, Breite, Farbcodierungsformat und Drehungsgrad:
Kotlin
val image = InputImage.fromByteBuffer( byteBuffer, /* image width */ 480, /* image height */ 360, rotationDegrees, InputImage.IMAGE_FORMAT_NV21 // or IMAGE_FORMAT_YV12 ) // Or: val image = InputImage.fromByteArray( byteArray, /* image width */ 480, /* image height */ 360, rotationDegrees, InputImage.IMAGE_FORMAT_NV21 // or IMAGE_FORMAT_YV12 )
Java
InputImage image = InputImage.fromByteBuffer(byteBuffer, /* image width */ 480, /* image height */ 360, rotationDegrees, InputImage.IMAGE_FORMAT_NV21 // or IMAGE_FORMAT_YV12 ); // Or: InputImage image = InputImage.fromByteArray( byteArray, /* image width */480, /* image height */360, rotation, InputImage.IMAGE_FORMAT_NV21 // or IMAGE_FORMAT_YV12 );
Mit einem Bitmap
So erstellen Sie eine InputImage
:
Bitmap
-Objekt zu erstellen, nehmen Sie folgende Deklaration vor:
Kotlin
val image = InputImage.fromBitmap(bitmap, 0)
Java
InputImage image = InputImage.fromBitmap(bitmap, rotationDegree);
Das Bild wird durch ein Bitmap
-Objekt in Verbindung mit Drehungsgrad dargestellt.
2. Instanz von SubjectSegmenter erstellen
Segmentierungsoptionen definieren
Zum Segmentieren des Images erstellen Sie zuerst eine Instanz von SubjectSegmenterOptions
als
folgen:
Kotlin
val options = SubjectSegmenterOptions.Builder() // enable options .build()
Java
SubjectSegmenterOptions options = new SubjectSegmenterOptions.Builder() // enable options .build();
Hier sind die Details der einzelnen Optionen:
Konfidenzmaske im Vordergrund
Mit der Konfidenzmaske im Vordergrund können Sie das Objekt im Vordergrund von im Hintergrund.
Rufen Sie enableForegroundConfidenceMask()
in den Optionen auf, um sie später abzurufen.
Vordergrundmaske durch Aufrufen von getForegroundMask()
für die
SubjectSegmentationResult
-Objekt, das nach der Verarbeitung des Bildes zurückgegeben wurde.
Kotlin
val options = SubjectSegmenterOptions.Builder() .enableForegroundConfidenceMask() .build()
Java
SubjectSegmenterOptions options = new SubjectSegmenterOptions.Builder() .enableForegroundConfidenceMask() .build();
Vordergrund-Bitmap
Ebenso können Sie auch eine Bitmap des Motivs im Vordergrund abrufen.
Rufen Sie enableForegroundBitmap()
in den Optionen auf, um sie später abzurufen.
Bitmap im Vordergrund durch Aufrufen von getForegroundBitmap()
auf der
SubjectSegmentationResult
-Objekt, das nach der Verarbeitung des Bildes zurückgegeben wurde.
Kotlin
val options = SubjectSegmenterOptions.Builder() .enableForegroundBitmap() .build()
Java
SubjectSegmenterOptions options = new SubjectSegmenterOptions.Builder() .enableForegroundBitmap() .build();
Konfidenzmaske für mehrere Themen
Wie bei den Vordergrundoptionen können Sie SubjectResultOptions
verwenden, um
die Konfidenzmaske für jedes Vordergrundobjekt so:
Kotlin
val subjectResultOptions = SubjectSegmenterOptions.SubjectResultOptions.Builder() .enableConfidenceMask() .build() val options = SubjectSegmenterOptions.Builder() .enableMultipleSubjects(subjectResultOptions) .build()
Java
SubjectResultOptions subjectResultOptions = new SubjectSegmenterOptions.SubjectResultOptions.Builder() .enableConfidenceMask() .build() SubjectSegmenterOptions options = new SubjectSegmenterOptions.Builder() .enableMultipleSubjects(subjectResultOptions) .build()
Bitmap mit mehreren Themen
Auf ähnliche Weise können Sie die Bitmap für jedes Thema aktivieren:
Kotlin
val subjectResultOptions = SubjectSegmenterOptions.SubjectResultOptions.Builder() .enableSubjectBitmap() .build() val options = SubjectSegmenterOptions.Builder() .enableMultipleSubjects(subjectResultOptions) .build()
Java
SubjectResultOptions subjectResultOptions = new SubjectSegmenterOptions.SubjectResultOptions.Builder() .enableSubjectBitmap() .build() SubjectSegmenterOptions options = new SubjectSegmenterOptions.Builder() .enableMultipleSubjects(subjectResultOptions) .build()
Themen-Segmentierungstool erstellen
Nachdem Sie die Optionen für SubjectSegmenterOptions
angegeben haben, erstellen Sie ein
SubjectSegmenter
-Instanz, die getClient()
aufruft und die Optionen als eine
Parameter:
Kotlin
val segmenter = SubjectSegmentation.getClient(options)
Java
SubjectSegmenter segmenter = SubjectSegmentation.getClient(options);
3. Bilder verarbeiten
Die vorbereiteten InputImage
übergeben
-Objekt zur process
-Methode von SubjectSegmenter
hinzu:
Kotlin
segmenter.process(inputImage) .addOnSuccessListener { result -> // Task completed successfully // ... } .addOnFailureListener { e -> // Task failed with an exception // ... }
Java
segmenter.process(inputImage) .addOnSuccessListener(new OnSuccessListener() { @Override public void onSuccess(SubjectSegmentationResult result) { // Task completed successfully // ... } }) .addOnFailureListener(new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { // Task failed with an exception // ... } });
4. Ergebnis der Themensegmentierung abrufen
Vordergrundmasken und Bitmaps abrufen
Nach der Verarbeitung können Sie die Vordergrundmaske für Ihren Bildaufruf abrufen
getForegroundConfidenceMask()
wie folgt:
Kotlin
val colors = IntArray(image.width * image.height) val foregroundMask = result.foregroundConfidenceMask for (i in 0 until image.width * image.height) { if (foregroundMask[i] > 0.5f) { colors[i] = Color.argb(128, 255, 0, 255) } } val bitmapMask = Bitmap.createBitmap( colors, image.width, image.height, Bitmap.Config.ARGB_8888 )
Java
int[] colors = new int[image.getWidth() * image.getHeight()]; FloatBuffer foregroundMask = result.getForegroundConfidenceMask(); for (int i = 0; i < image.getWidth() * image.getHeight(); i++) { if (foregroundMask.get() > 0.5f) { colors[i] = Color.argb(128, 255, 0, 255); } } Bitmap bitmapMask = Bitmap.createBitmap( colors, image.getWidth(), image.getHeight(), Bitmap.Config.ARGB_8888 );
Sie können auch eine Bitmap des Vordergrunds des Bildes abrufen, in dem getForegroundBitmap()
aufgerufen wird:
Kotlin
val foregroundBitmap = result.foregroundBitmap
Java
Bitmap foregroundBitmap = result.getForegroundBitmap();
Masken und Bitmaps für jedes Thema abrufen
In ähnlicher Weise können Sie die Maske für die segmentierten Subjekte abrufen, indem Sie folgenden Befehl aufrufen:
getConfidenceMask()
zu jedem Thema wie folgt:
Kotlin
val subjects = result.subjects val colors = IntArray(image.width * image.height) for (subject in subjects) { val mask = subject.confidenceMask for (i in 0 until subject.width * subject.height) { val confidence = mask[i] if (confidence > 0.5f) { colors[image.width * (subject.startY - 1) + subject.startX] = Color.argb(128, 255, 0, 255) } } } val bitmapMask = Bitmap.createBitmap( colors, image.width, image.height, Bitmap.Config.ARGB_8888 )
Java
Listsubjects = result.getSubjects(); int[] colors = new int[image.getWidth() * image.getHeight()]; for (Subject subject : subjects) { FloatBuffer mask = subject.getConfidenceMask(); for (int i = 0; i < subject.getWidth() * subject.getHeight(); i++) { float confidence = mask.get(); if (confidence > 0.5f) { colors[width * (subject.getStartY() - 1) + subject.getStartX()] = Color.argb(128, 255, 0, 255); } } } Bitmap bitmapMask = Bitmap.createBitmap( colors, image.width, image.height, Bitmap.Config.ARGB_8888 );
Sie können auch wie folgt auf die Bitmap der einzelnen segmentierten Themen zugreifen:
Kotlin
val bitmaps = mutableListOf() for (subject in subjects) { bitmaps.add(subject.bitmap) }
Java
Listbitmaps = new ArrayList<>(); for (Subject subject : subjects) { bitmaps.add(subject.getBitmap()); }
Tipps zur Verbesserung der Leistung
Bei jeder App-Sitzung ist die erste Inferenz oft langsamer als die nachfolgende Inferenzen aufgrund der Modellinitialisierung. Wenn eine niedrige Latenz kritisch ist, sollten Sie eine „Dummy“ anrufen frühzeitige Schlussfolgerung ziehen.
Die Qualität Ihrer Ergebnisse hängt von der Qualität des Eingabebildes ab:
- Damit ML Kit ein genaues Segmentierungsergebnis erhalten kann, sollte das Bild mindestens 512 x 512 Pixel groß sein.
- Ein schlechter Bildfokus kann auch die Genauigkeit beeinträchtigen. Wenn Sie keine akzeptablen Ergebnisse erhalten, bitten Sie den Nutzer, das Bild erneut aufzunehmen.