Utilisez ML Kit pour ajouter facilement des fonctionnalités de segmentation par sujet à votre application.
<ph type="x-smartling-placeholder">Fonctionnalité | Détails |
---|---|
Nom du SDK | play-services-mlkit-subject-segmentation |
Implémentation | Dégroupé: le modèle est téléchargé de manière dynamique à l'aide des services Google Play. |
Impact sur la taille de l'application | Augmentation de la taille d'environ 200 Ko. |
Délai d'initialisation | Les utilisateurs devront peut-être attendre la fin du téléchargement du modèle avant de l'utiliser pour la première fois. |
Essayer
- Testez l'application exemple pour : consultez un exemple d'utilisation de cette API.
Avant de commencer
<ph type="x-smartling-placeholder">- Dans le fichier
build.gradle
au niveau du projet, veillez à inclure le dépôt Maven de Google à la fois dans vos sectionsbuildscript
etallprojects
. - Ajoutez la dépendance de la bibliothèque de segmentation de l'objet de ML Kit au fichier Gradle au niveau de l'application de votre module, qui est généralement
app/build.gradle
:
dependencies {
implementation 'com.google.android.gms:play-services-mlkit-subject-segmentation:16.0.0-beta1'
}
Comme indiqué ci-dessus, le modèle est fourni par les services Google Play.
Vous pouvez configurer votre application pour télécharger automatiquement le modèle sur l'appareil
après l'installation de votre application depuis le Play Store. Pour ce faire, ajoutez ce qui suit :
dans le fichier AndroidManifest.xml
de votre application:
<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>
Vous pouvez également vérifier explicitement la disponibilité du modèle et demander un téléchargement via les services Google Play à l'aide de l'API ModuleInstallClient.
Si vous n'activez pas les téléchargements de modèles au moment de l'installation ou si vous ne demandez pas de téléchargement explicite le modèle est téléchargé la première fois que vous exécutez le segmenteur. Demandes que vous effectuez avant la fin du téléchargement ne produit aucun résultat.
1. Préparer l'image d'entrée
Pour effectuer une segmentation sur une image, créez un objet InputImage
.
à partir d'un Bitmap
, d'un media.Image
, d'un ByteBuffer
, d'un tableau d'octets ou d'un fichier sur
l'appareil.
Vous pouvez créer un InputImage
de différentes sources. Chacune d'elles est expliquée ci-dessous.
Utiliser un media.Image
Pour créer un InputImage
à partir d'un objet media.Image
, par exemple lorsque vous capturez une image à partir d'un
l'appareil photo de l'appareil, transmettez l'objet media.Image
et l'image
la rotation sur InputImage.fromMediaImage()
.
Si vous utilisez les
<ph type="x-smartling-placeholder"></ph>
la bibliothèque CameraX, les OnImageCapturedListener
et
Les classes ImageAnalysis.Analyzer
calculent la valeur de rotation
pour vous.
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 // ... } } }
Si vous n'utilisez pas de bibliothèque d'appareils photo qui indique le degré de rotation de l'image, le calcul à partir du degré de rotation de l'appareil et de l'orientation de la caméra capteur de l'appareil:
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; }
Ensuite, transmettez l'objet media.Image
et
valeur du degré de rotation sur InputImage.fromMediaImage()
:
Kotlin
val image = InputImage.fromMediaImage(mediaImage, rotation)
Java
InputImage image = InputImage.fromMediaImage(mediaImage, rotation);
Utiliser un URI de fichier
Pour créer un InputImage
à partir d'un URI de fichier, transmettez le contexte de l'application et l'URI du fichier à
InputImage.fromFilePath()
Cela est utile lorsque vous
Utiliser un intent ACTION_GET_CONTENT
pour inviter l'utilisateur à sélectionner
une image de son application Galerie.
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(); }
Utiliser un ByteBuffer
ou un ByteArray
Pour créer un InputImage
d'un objet ByteBuffer
ou ByteArray
, calculez d'abord l'image
degré de rotation décrit précédemment pour l'entrée media.Image
.
Ensuite, créez l'objet InputImage
avec le tampon ou le tableau, ainsi que l'objet image
la hauteur, la largeur, le format d'encodage des couleurs et le degré de rotation:
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 );
Utiliser un Bitmap
Pour créer un InputImage
à partir d'un objet Bitmap
, effectuez la déclaration suivante:
Kotlin
val image = InputImage.fromBitmap(bitmap, 0)
Java
InputImage image = InputImage.fromBitmap(bitmap, rotationDegree);
L'image est représentée par un objet Bitmap
associé à des degrés de rotation.
2. Créer une instance de SubjectSegmenter
Définir les options du segmenteur
Pour segmenter votre image, créez d'abord une instance de SubjectSegmenterOptions
en tant que
suivre:
Kotlin
val options = SubjectSegmenterOptions.Builder() // enable options .build()
Java
SubjectSegmenterOptions options = new SubjectSegmenterOptions.Builder() // enable options .build();
Voici les détails de chaque option:
Masque de confiance au premier plan
Le masque de confiance au premier plan vous permet de distinguer le sujet au premier plan en arrière-plan.
Appelez enableForegroundConfidenceMask()
dans les options pour récupérer plus tard
le masque de premier plan en appelant getForegroundMask()
sur la
Objet SubjectSegmentationResult
renvoyé après le traitement de l'image.
Kotlin
val options = SubjectSegmenterOptions.Builder() .enableForegroundConfidenceMask() .build()
Java
SubjectSegmenterOptions options = new SubjectSegmenterOptions.Builder() .enableForegroundConfidenceMask() .build();
Bitmap de premier plan
De même, vous pouvez obtenir un bitmap du sujet au premier plan.
Appelez enableForegroundBitmap()
dans les options pour récupérer plus tard
le bitmap de premier plan en appelant getForegroundBitmap()
sur le
Objet SubjectSegmentationResult
renvoyé après le traitement de l'image.
Kotlin
val options = SubjectSegmenterOptions.Builder() .enableForegroundBitmap() .build()
Java
SubjectSegmenterOptions options = new SubjectSegmenterOptions.Builder() .enableForegroundBitmap() .build();
Masque de confiance multisujet
Comme pour les options de premier plan, vous pouvez utiliser SubjectResultOptions
pour activer
le masque de confiance pour chaque sujet au premier plan, comme suit:
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 multi-sujets
De même, vous pouvez activer le bitmap pour chaque sujet:
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()
Créer le segmenteur de sujet
Après avoir spécifié les options SubjectSegmenterOptions
, créez un
Instance SubjectSegmenter
qui appelle getClient()
et transmet les options en tant que
:
Kotlin
val segmenter = SubjectSegmentation.getClient(options)
Java
SubjectSegmenter segmenter = SubjectSegmentation.getClient(options);
3. Traiter une image
Transmettre le InputImage
préparé
à la méthode process
de SubjectSegmenter
:
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. Obtenir le résultat de la segmentation du sujet
Récupérer les masques et les bitmaps de premier plan
Une fois le traitement terminé, vous pouvez récupérer le masque de premier plan de votre image appelante.
getForegroundConfidenceMask()
comme suit:
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 );
Vous pouvez également récupérer un bitmap du premier plan de l'image en appelant getForegroundBitmap()
:
Kotlin
val foregroundBitmap = result.foregroundBitmap
Java
Bitmap foregroundBitmap = result.getForegroundBitmap();
Récupérer les masques et les bitmaps pour chaque sujet
De même, vous pouvez récupérer le masque des sujets segmentés en appelant
getConfidenceMask()
sur chaque sujet, comme suit:
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 );
Vous pouvez également accéder au bitmap de chaque sujet segmenté comme suit:
Kotlin
val bitmaps = mutableListOf() for (subject in subjects) { bitmaps.add(subject.bitmap) }
Java
Listbitmaps = new ArrayList<>(); for (Subject subject : subjects) { bitmaps.add(subject.getBitmap()); }
Conseils pour améliorer les performances
Pour chaque session d'application, la première inférence est souvent plus lente que les suivantes dues à l'initialisation du modèle. Si une faible latence est essentielle, envisagez CANNOT TRANSLATE l'inférence à l'avance.
La qualité des résultats dépend de la qualité de l'image d'entrée:
- Pour que ML Kit obtienne un résultat de segmentation précis, l'image doit faire au moins 512 x 512 pixels.
- Une mauvaise mise au point de l'image peut également nuire à sa précision. Si les résultats ne sont pas satisfaisants, demandez à l'utilisateur de reprendre l'image.