Android के लिए ML किट की मदद से, चीज़ों को अलग-अलग ग्रुप में बांटना

अपने ऐप्लिकेशन में सब्जेक्ट सेगमेंटेशन की सुविधाएं आसानी से जोड़ने के लिए, एमएल किट का इस्तेमाल करें.

सुविधा जानकारी
Sdk का नाम play-services-mlkit-subject-segmentation
लागू करना बंडल नहीं किया गया: मॉडल, Google Play services का इस्तेमाल करके डाइनैमिक तौर पर डाउनलोड किया जाता है.
ऐप्लिकेशन के साइज़ का असर साइज़ ~200 केबी होना चाहिए.
प्रोसेस शुरू होने का समय उपयोगकर्ताओं को पहली बार इस्तेमाल करने से पहले, मॉडल के डाउनलोड होने तक इंतज़ार करना पड़ सकता है.

इसे आज़माएं

शुरू करने से पहले

  1. प्रोजेक्ट-लेवल की build.gradle फ़ाइल में, पक्का करें कि आपने buildscript और allprojects, दोनों सेक्शन में Google की Maven रिपॉज़िटरी को शामिल किया हो.
  2. अपने मॉड्यूल की ऐप्लिकेशन-लेवल की Gradle फ़ाइल में, एमएल किट सब्जेक्ट सेगमेंटेशन लाइब्रेरी के लिए डिपेंडेंसी जोड़ें. आम तौर पर, यह फ़ाइल app/build.gradle होती है:
dependencies {
   implementation 'com.google.android.gms:play-services-mlkit-subject-segmentation:16.0.0-beta1'
}

जैसा कि ऊपर बताया गया है, यह मॉडल Google Play services उपलब्ध कराता है. ऐप्लिकेशन को इस तरह कॉन्फ़िगर किया जा सकता है कि डिवाइस पर मॉडल अपने-आप डाउनलोड हो जाए Play Store से आपका ऐप्लिकेशन इंस्टॉल करने के बाद. ऐसा करने के लिए, यह जानकारी जोड़ें आपके ऐप्लिकेशन की AndroidManifest.xml फ़ाइल का एलान:

<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>

ModuleInstallClient API की मदद से, मॉडल की उपलब्धता के बारे में साफ़ तौर पर देखा जा सकता है. साथ ही, Google Play services से, उसे डाउनलोड करने का अनुरोध भी किया जा सकता है.

अगर आपने इंस्टॉल के समय मॉडल को डाउनलोड करने की सुविधा चालू नहीं की है या अश्लील फ़ाइल डाउनलोड करने का अनुरोध नहीं किया है पहली बार सेगमेंटर को चलाने पर, मॉडल डाउनलोड हो जाता है. आपके अनुरोध डाउनलोड पूरा होने से पहले ही कोई नतीजा न मिले.

1. इनपुट इमेज तैयार करें

किसी इमेज को सेगमेंट में बांटने के लिए, InputImage ऑब्जेक्ट बनाएं किसी Bitmap, media.Image, ByteBuffer, बाइट कलेक्शन से या डिवाइस.

एक InputImage बनाया जा सकता है अलग-अलग सोर्स के ऑब्जेक्ट के बारे में बताया गया है. हर ऑब्जेक्ट के बारे में नीचे बताया गया है.

media.Image का इस्तेमाल करके

InputImage बनाने के लिए किसी media.Image ऑब्जेक्ट से मिला ऑब्जेक्ट, जैसे कि जब आप किसी ऑब्जेक्ट से इमेज कैप्चर करते हैं फ़ोन का कैमरा इस्तेमाल करने के लिए, media.Image ऑब्जेक्ट को पास करें और इमेज के InputImage.fromMediaImage() का रोटेशन.

अगर आपको CameraX लाइब्रेरी, OnImageCapturedListener, और ImageAnalysis.Analyzer क्लास, रोटेशन वैल्यू को कैलकुलेट करती हैं आपके लिए.

KotlinJava
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
            // ...
        }
    }
}
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
          // ...
        }
    }
}

अगर इमेज का रोटेशन डिग्री देने वाली कैमरा लाइब्रेरी का इस्तेमाल नहीं किया जाता, तो डिवाइस की रोटेशन डिग्री और कैमरे के ओरिएंटेशन से इसका हिसाब लगा सकता है डिवाइस में सेंसर:

KotlinJava
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
}
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;
}

इसके बाद, media.Image ऑब्जेक्ट को पास करें और InputImage.fromMediaImage() डिग्री पर घुमाव:

KotlinJava
val image = InputImage.fromMediaImage(mediaImage, rotation)
InputImage image = InputImage.fromMediaImage(mediaImage, rotation);

फ़ाइल यूआरआई का इस्तेमाल करना

InputImage बनाने के लिए किसी फ़ाइल यूआरआई से ऑब्जेक्ट को जोड़ने के लिए, ऐप्लिकेशन संदर्भ और फ़ाइल यूआरआई को InputImage.fromFilePath(). यह तब काम आता है, जब उपयोगकर्ता को चुनने का प्रॉम्प्ट भेजने के लिए, ACTION_GET_CONTENT इंटेंट का इस्तेमाल करें अपने गैलरी ऐप्लिकेशन से मिली इमेज शामिल करेगा.

KotlinJava
val image: InputImage
try {
    image = InputImage.fromFilePath(context, uri)
} catch (e: IOException) {
    e.printStackTrace()
}
InputImage image;
try {
    image = InputImage.fromFilePath(context, uri);
} catch (IOException e) {
    e.printStackTrace();
}

ByteBuffer या ByteArray का इस्तेमाल करना

InputImage बनाने के लिए ByteBuffer या ByteArray से लिया गया ऑब्जेक्ट है, तो पहले इमेज की गणना करें media.Image इनपुट के लिए पहले बताई गई रोटेशन डिग्री. इसके बाद, इमेज के साथ बफ़र या अरे का इस्तेमाल करके, InputImage ऑब्जेक्ट बनाएं ऊंचाई, चौड़ाई, कलर एन्कोडिंग फ़ॉर्मैट, और रोटेशन डिग्री:

KotlinJava
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
)
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
);

Bitmap का इस्तेमाल करके

InputImage बनाने के लिए Bitmap ऑब्जेक्ट में बनाए गए ऑब्जेक्ट के लिए, यह एलान करें:

KotlinJava
val image = InputImage.fromBitmap(bitmap, 0)
InputImage image = InputImage.fromBitmap(bitmap, rotationDegree);

इमेज को Bitmap ऑब्जेक्ट से, रोटेशन डिग्री के साथ दिखाया गया है.

2. Subjectsegmenter का इंस्टेंस बनाएं

सेगमेंटर के विकल्प तय करें

अपनी इमेज को सेगमेंट में बांटने के लिए, पहले SubjectSegmenterOptions का इंस्टेंस इस तौर पर बनाएं फ़ॉलो करें:

KotlinJava
val options = SubjectSegmenterOptions.Builder()
       // enable options
       .build()
SubjectSegmenterOptions options = new SubjectSegmenterOptions.Builder()
        // enable options
        .build();

यहां हर विकल्प की जानकारी दी गई है:

फ़ोरग्राउंड कॉन्फ़िडेंस मास्क

फ़ोरग्राउंड कॉन्फ़िडेंस मास्क की मदद से, फ़ोरग्राउंड सब्जेक्ट और फ़ोरग्राउंड कॉन्फ़िडेंस मास्क की पहचान की जा सकती है बैकग्राउंड.

विकल्पों में मौजूद enableForegroundConfidenceMask() को कॉल करें, ताकि आप बाद में वापस आ सकें स्क्रीन पर getForegroundMask() को कॉल करके, फ़ोरग्राउंड मास्क इमेज प्रोसेस होने के बाद SubjectSegmentationResult ऑब्जेक्ट लौटाया गया.

KotlinJava
val options = SubjectSegmenterOptions.Builder()
        .enableForegroundConfidenceMask()
        .build()
SubjectSegmenterOptions options = new SubjectSegmenterOptions.Builder()
        .enableForegroundConfidenceMask()
        .build();
फ़ोरग्राउंड बिट मैप

इसी तरह, आपको फ़ोरग्राउंड सब्जेक्ट का बिटमैप भी मिल सकता है.

विकल्पों में मौजूद enableForegroundBitmap() को कॉल करें. इससे, आपको बाद में वापस लाने में मदद मिलेगी पर getForegroundBitmap() को कॉल करके फ़ोरग्राउंड बिटमैप इमेज प्रोसेस होने के बाद SubjectSegmentationResult ऑब्जेक्ट लौटाया गया.

KotlinJava
val options = SubjectSegmenterOptions.Builder()
        .enableForegroundBitmap()
        .build()
SubjectSegmenterOptions options = new SubjectSegmenterOptions.Builder()
        .enableForegroundBitmap()
        .build();
कई विषयों वाला कॉन्फ़िडेंस मास्क

फ़ोरग्राउंड के विकल्पों की तरह ही, SubjectResultOptions का इस्तेमाल करके इसे चालू किया जा सकता है फ़ोरग्राउंड के हर सब्जेक्ट के लिए कॉन्फ़िडेंस मास्क की सुविधा नीचे दी गई है:

KotlinJava
val subjectResultOptions = SubjectSegmenterOptions.SubjectResultOptions.Builder()
    .enableConfidenceMask()
    .build()

val options = SubjectSegmenterOptions.Builder()
    .enableMultipleSubjects(subjectResultOptions)
    .build()
SubjectResultOptions subjectResultOptions =
        new SubjectSegmenterOptions.SubjectResultOptions.Builder()
            .enableConfidenceMask()
            .build()

SubjectSegmenterOptions options = new SubjectSegmenterOptions.Builder()
      .enableMultipleSubjects(subjectResultOptions)
      .build()
कई विषयों वाला बिट मैप

इसी तरह, हर विषय के लिए बिट मैप चालू किया जा सकता है:

KotlinJava
val subjectResultOptions = SubjectSegmenterOptions.SubjectResultOptions.Builder()
    .enableSubjectBitmap()
    .build()

val options = SubjectSegmenterOptions.Builder()
    .enableMultipleSubjects(subjectResultOptions)
    .build()
SubjectResultOptions subjectResultOptions =
      new SubjectSegmenterOptions.SubjectResultOptions.Builder()
        .enableSubjectBitmap()
        .build()

SubjectSegmenterOptions options = new SubjectSegmenterOptions.Builder()
      .enableMultipleSubjects(subjectResultOptions)
      .build()

सब्जेक्ट सेगमेंटर बनाना

SubjectSegmenterOptions विकल्प तय करने के बाद, SubjectSegmenter इंस्टेंस, getClient() को कॉल करके विकल्पों को पास कर रहा है पैरामीटर:

KotlinJava
val segmenter = SubjectSegmentation.getClient(options)
SubjectSegmenter segmenter = SubjectSegmentation.getClient(options);

3. इमेज प्रोसेस करना

तैयारी की गई InputImage पास करें ऑब्जेक्ट को SubjectSegmenter की process विधि से करें:

KotlinJava
segmenter.process(inputImage)
    .addOnSuccessListener { result ->
        // Task completed successfully
        // ...
    }
    .addOnFailureListener { e ->
        // Task failed with an exception
        // ...
    }
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. विषय के आधार पर बनाए गए सेगमेंट का नतीजा पाना

फ़ोरग्राउंड मास्क और बिटमैप वापस पाएं

प्रोसेस होने के बाद, इमेज कॉलिंग के लिए फ़ोरग्राउंड मास्क वापस पाया जा सकता है getForegroundConfidenceMask():

KotlinJava
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
)
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
);

आप getForegroundBitmap() को कॉल करने वाली इमेज के फ़ोरग्राउंड का बिटमैप भी हासिल कर सकते हैं:

KotlinJava
val foregroundBitmap = result.foregroundBitmap
Bitmap foregroundBitmap = result.getForegroundBitmap();

हर विषय के लिए मास्क और बिटमैप वापस पाएं

इसी तरह, आप कॉल करके विभाजित किए गए सब्जेक्ट के लिए मास्क फिर से पा सकते हैं हर विषय के लिए, getConfidenceMask() को फ़ॉलो करें:

KotlinJava
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
)
List subjects = 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
);

नीचे बताए गए तरीके का इस्तेमाल करके भी, सेगमेंट किए गए हर विषय के बिट मैप को ऐक्सेस किया जा सकता है:

KotlinJava
val bitmaps = mutableListOf()
for (subject in subjects) {
  bitmaps.add(subject.bitmap)
}
List bitmaps = new ArrayList<>();
for (Subject subject : subjects) {
  bitmaps.add(subject.getBitmap());
}

परफ़ॉर्मेंस को बेहतर बनाने के लिए सलाह

हर ऐप्लिकेशन सेशन के लिए, पहला अनुमान अक्सर बाद के अनुमान से धीमा होता है मॉडल शुरू करने की वजह से अनुमान लगाए जा सकते हैं. अगर लाइव स्ट्रीमिंग करने और उसके दिखने के बीच इंतज़ार का समय कम होना बेहद ज़रूरी है, तो "डमी" कहकर समय से पहले का अनुमान है.

आपके नतीजों की क्वालिटी, इनपुट इमेज की क्वालिटी पर निर्भर करती है:

  • एमएल किट में सेगमेंटेशन का सटीक नतीजा पाने के लिए, इमेज कम से कम 512x512 पिक्सल की होनी चाहिए.
  • खराब इमेज फ़ोकस की वजह से भी सटीक जानकारी पर असर पड़ सकता है. अगर आपको स्वीकार किए जाने वाले नतीजे नहीं मिलते, तो उपयोगकर्ता से इमेज दोबारा कैप्चर करने के लिए कहें.