iOS पर एमएल किट की मदद से सेल्फ़ी को अलग-अलग सेगमेंट में बांटना

ML किट, सेल्फ़ी सेगमेंटेशन के लिए ऑप्टिमाइज़ किया गया SDK टूल उपलब्ध कराती है. सेल्फ़ी सेगमेंटर एसेट, बिल्ड के दौरान आपके ऐप्लिकेशन से स्थिर रूप से लिंक होती हैं. इससे आपके ऐप्लिकेशन का साइज़ 24 एमबी तक बढ़ जाएगा. साथ ही, iPhone X पर मेज़र की गई इमेज के साइज़ के हिसाब से, इंतज़ार का समय ~7 मि॰से॰ से लेकर ~12 मि॰से॰ तक हो सकता है.

इसे आज़माएं

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

  1. अपनी Podfile में, यहां दी गई ML किट लाइब्रेरी शामिल करें:

    pod 'GoogleMLKit/SegmentationSelfie', '3.2.0'
    
  2. अपने प्रोजेक्ट के पॉड इंस्टॉल या अपडेट करने के बाद, Xcode प्रोजेक्ट के .xcworkspace का इस्तेमाल करें. ML किट, Xcode 13.2.1 या इसके बाद के वर्शन पर काम करती है.

1. सेगमेंटर का एक इंस्टेंस बनाएं

सेल्फ़ी इमेज को सेगमेंट में बांटने के लिए, पहले SelfieSegmenterOptions के साथ Segmenter का इंस्टेंस बनाएं. साथ ही, सेगमेंटेशन सेटिंग तय करें. हालांकि, ऐसा करना ज़रूरी नहीं है.

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

सेगमेंटर मोड

Segmenter दो मोड में काम करता है. पक्का करें कि आपने वही ईमेल पता चुना हो जो आपके इस्तेमाल के उदाहरण से मेल खाता हो.

STREAM_MODE (default)

यह मोड, वीडियो या कैमरे से फ़्रेम स्ट्रीम करने के लिए डिज़ाइन किया गया है. इस मोड में, सेगमेंटर पिछले फ़्रेम के नतीजों का इस्तेमाल करेगा, ताकि सेगमेंटेशन के दौरान बेहतर नतीजे मिल सकें.

SINGLE_IMAGE_MODE (default)

यह मोड ऐसी इमेज के लिए डिज़ाइन किया गया है जो आपस में जुड़ी नहीं हैं. इस मोड में, सेगमेंटर हर इमेज को अलग-अलग प्रोसेस करेगा. इसमें फ़्रेम पर स्मूदिंग नहीं होगी.

रॉ साइज़ मास्क चालू करें

सेगमेंटर को मूल साइज़ का मास्क वापस करने के लिए कहता है, जो मॉडल के आउटपुट साइज़ से मेल खाता है.

मास्क का रॉ साइज़ (जैसे, 256x256), आम तौर पर इनपुट इमेज के साइज़ से छोटा होता है.

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

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

Swift

let options = SelfieSegmenterOptions()
options.segmenterMode = .singleImage
options.shouldEnableRawSizeMask = true

Objective-C

MLKSelfieSegmenterOptions *options = [[MLKSelfieSegmenterOptions alloc] init];
options.segmenterMode = MLKSegmenterModeSingleImage;
options.shouldEnableRawSizeMask = YES;

आखिर में, Segmenter का एक इंस्टेंस पाएं. अपने बताए गए विकल्पों को पास करें:

Swift

let segmenter = Segmenter.segmenter(options: options)

Objective-C

MLKSegmenter *segmenter = [MLKSegmenter segmenterWithOptions:options];

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

सेल्फ़ी को अलग-अलग सेगमेंट में बांटने के लिए, वीडियो के हर इमेज या फ़्रेम के लिए नीचे दिया गया तरीका अपनाएं. अगर आपने स्ट्रीम मोड चालू किया है, तो आपको CMSampleBuffer से VisionImage ऑब्जेक्ट बनाने होंगे.

UIImage या CMSampleBuffer का इस्तेमाल करके, VisionImage ऑब्जेक्ट बनाएं.

अगर UIImage का इस्तेमाल किया जाता है, तो यह तरीका अपनाएं:

  • UIImage की मदद से VisionImage ऑब्जेक्ट बनाएं. पक्का करें कि आपने सही .orientation डाला हो.

    Swift

    let image = VisionImage(image: UIImage)
    visionImage.orientation = image.imageOrientation

    Objective-C

    MLKVisionImage *visionImage = [[MLKVisionImage alloc] initWithImage:image];
    visionImage.orientation = image.imageOrientation;

अगर CMSampleBuffer का इस्तेमाल किया जाता है, तो यह तरीका अपनाएं:

  • CMSampleBuffer में शामिल इमेज डेटा का ओरिएंटेशन बताएं.

    इमेज ओरिएंटेशन पाने के लिए:

    Swift

    func imageOrientation(
      deviceOrientation: UIDeviceOrientation,
      cameraPosition: AVCaptureDevice.Position
    ) -> UIImage.Orientation {
      switch deviceOrientation {
      case .portrait:
        return cameraPosition == .front ? .leftMirrored : .right
      case .landscapeLeft:
        return cameraPosition == .front ? .downMirrored : .up
      case .portraitUpsideDown:
        return cameraPosition == .front ? .rightMirrored : .left
      case .landscapeRight:
        return cameraPosition == .front ? .upMirrored : .down
      case .faceDown, .faceUp, .unknown:
        return .up
      }
    }
          

    Objective-C

    - (UIImageOrientation)
      imageOrientationFromDeviceOrientation:(UIDeviceOrientation)deviceOrientation
                             cameraPosition:(AVCaptureDevicePosition)cameraPosition {
      switch (deviceOrientation) {
        case UIDeviceOrientationPortrait:
          return cameraPosition == AVCaptureDevicePositionFront ? UIImageOrientationLeftMirrored
                                                                : UIImageOrientationRight;
    
        case UIDeviceOrientationLandscapeLeft:
          return cameraPosition == AVCaptureDevicePositionFront ? UIImageOrientationDownMirrored
                                                                : UIImageOrientationUp;
        case UIDeviceOrientationPortraitUpsideDown:
          return cameraPosition == AVCaptureDevicePositionFront ? UIImageOrientationRightMirrored
                                                                : UIImageOrientationLeft;
        case UIDeviceOrientationLandscapeRight:
          return cameraPosition == AVCaptureDevicePositionFront ? UIImageOrientationUpMirrored
                                                                : UIImageOrientationDown;
        case UIDeviceOrientationUnknown:
        case UIDeviceOrientationFaceUp:
        case UIDeviceOrientationFaceDown:
          return UIImageOrientationUp;
      }
    }
          
  • CMSampleBuffer ऑब्जेक्ट और ओरिएंटेशन का इस्तेमाल करके, VisionImage ऑब्जेक्ट बनाएं:

    Swift

    let image = VisionImage(buffer: sampleBuffer)
    image.orientation = imageOrientation(
      deviceOrientation: UIDevice.current.orientation,
      cameraPosition: cameraPosition)

    Objective-C

     MLKVisionImage *image = [[MLKVisionImage alloc] initWithBuffer:sampleBuffer];
     image.orientation =
       [self imageOrientationFromDeviceOrientation:UIDevice.currentDevice.orientation
                                    cameraPosition:cameraPosition];

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

VisionImage ऑब्जेक्ट को Segmenter के इमेज प्रोसेसिंग के किसी तरीके में पास करें. एसिंक्रोनस process(image:) तरीके या सिंक्रोनस results(in:) तरीके का इस्तेमाल किया जा सकता है.

साथ ही, सेल्फ़ी इमेज को अलग-अलग सेगमेंट में बांटने के लिए:

Swift

var mask: [SegmentationMask]
do {
  mask = try segmenter.results(in: image)
} catch let error {
  print("Failed to perform segmentation with error: \(error.localizedDescription).")
  return
}

// Success. Get a segmentation mask here.

Objective-C

NSError *error;
MLKSegmentationMask *mask =
    [segmenter resultsInImage:image error:&error];
if (error != nil) {
  // Error.
  return;
}

// Success. Get a segmentation mask here.

एसिंक्रोनस तरीके से सेल्फ़ी इमेज को अलग-अलग सेगमेंट में बांटने के लिए:

Swift

segmenter.process(image) { mask, error in
  guard error == nil else {
    // Error.
    return
  }
  // Success. Get a segmentation mask here.

Objective-C

[segmenter processImage:image
             completion:^(MLKSegmentationMask * _Nullable mask,
                          NSError * _Nullable error) {
               if (error != nil) {
                 // Error.
                 return;
               }
               // Success. Get a segmentation mask here.
             }];

4. सेगमेंटेशन मास्क पाएं

सेगमेंटेशन के नतीजे इस तरह मिलते हैं:

Swift

let maskWidth = CVPixelBufferGetWidth(mask.buffer)
let maskHeight = CVPixelBufferGetHeight(mask.buffer)

CVPixelBufferLockBaseAddress(mask.buffer, CVPixelBufferLockFlags.readOnly)
let maskBytesPerRow = CVPixelBufferGetBytesPerRow(mask.buffer)
var maskAddress =
    CVPixelBufferGetBaseAddress(mask.buffer)!.bindMemory(
        to: Float32.self, capacity: maskBytesPerRow * maskHeight)

for _ in 0...(maskHeight - 1) {
  for col in 0...(maskWidth - 1) {
    // Gets the confidence of the pixel in the mask being in the foreground.
    let foregroundConfidence: Float32 = maskAddress[col]
  }
  maskAddress += maskBytesPerRow / MemoryLayout<Float32>.size
}

Objective-C

size_t width = CVPixelBufferGetWidth(mask.buffer);
size_t height = CVPixelBufferGetHeight(mask.buffer);

CVPixelBufferLockBaseAddress(mask.buffer, kCVPixelBufferLock_ReadOnly);
size_t maskBytesPerRow = CVPixelBufferGetBytesPerRow(mask.buffer);
float *maskAddress = (float *)CVPixelBufferGetBaseAddress(mask.buffer);

for (int row = 0; row < height; ++row) {
  for (int col = 0; col < width; ++col) {
    // Gets the confidence of the pixel in the mask being in the foreground.
    float foregroundConfidence = maskAddress[col];
  }
  maskAddress += maskBytesPerRow / sizeof(float);
}

सेगमेंटेशन नतीजों को इस्तेमाल करने के तरीके से जुड़े सभी उदाहरणों के लिए, कृपया एमएल किट का क्विकस्टार्ट सैंपल देखें.

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

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

  • एमएल किट के लिए, इमेज को कम से कम 256x256 पिक्सल का होना चाहिए, ताकि सेगमेंटेशन का सटीक नतीजा मिले.
  • अगर रीयल-टाइम में सेल्फ़ी को अलग-अलग सेगमेंट में बांटा जा रहा है, तो इनपुट इमेज के सभी डाइमेंशन पर भी ध्यान दिया जा सकता है. छोटी इमेज को तेज़ी से प्रोसेस किया जा सकता है. इसलिए, इंतज़ार का समय कम करने के लिए, कम रिज़ॉल्यूशन वाली इमेज लें. हालांकि, ऊपर बताई गई रिज़ॉल्यूशन की शर्तों को ध्यान में रखें. साथ ही, पक्का करें कि सब्जेक्ट को ज़्यादा से ज़्यादा इमेज दी गई हो.
  • खराब इमेज फ़ोकस भी सटीक जानकारी पर असर डाल सकता है. अगर आपको स्वीकार करने लायक नतीजे नहीं मिलते हैं, तो उपयोगकर्ता से इमेज को फिर से कैप्चर करने के लिए कहें.

अगर आपको रीयल-टाइम ऐप्लिकेशन में सेगमेंटेशन का इस्तेमाल करना है, तो सबसे सही फ़्रेम रेट पाने के लिए इन दिशा-निर्देशों का पालन करें:

  • stream सेगमेंटर मोड का इस्तेमाल करें.
  • इससे कम रिज़ॉल्यूशन वाली इमेज कैप्चर की जा सकती हैं. हालांकि, इस एपीआई की इमेज डाइमेंशन से जुड़ी ज़रूरी शर्तों का भी ध्यान रखें.
  • वीडियो फ़्रेम को प्रोसेस करने के लिए, सेगमेंटर के results(in:) सिंक्रोनस एपीआई का इस्तेमाल करें. दिए गए वीडियो फ़्रेम से सिंक्रोनस तरीके से नतीजे पाने के लिए, AVCaptureVideoDataOutputSampleBufferDelegate के captureOutput(_, didOutput:from:) फ़ंक्शन से इस तरीके को कॉल करें. सेगमेंटर कॉल को थ्रॉटल करने के लिए, AVCaptureVideoDataOutput के alwaysDiscardsLateVideoFrames को सही के तौर पर सेट करें. सेगमेंटर के चालू होने के दौरान, अगर कोई नया वीडियो फ़्रेम उपलब्ध होता है, तो उसे छोड़ दिया जाएगा.
  • अगर इनपुट इमेज पर ग्राफ़िक ओवरले करने के लिए, सेगमेंटर के आउटपुट का इस्तेमाल किया जाता है, तो सबसे पहले ML किट से नतीजा पाएं. इसके बाद, एक ही चरण में इमेज और ओवरले को रेंडर करें. ऐसा करने पर, प्रोसेस किए गए हर इनपुट फ़्रेम के लिए सिर्फ़ एक बार डिसप्ले प्लैटफ़ॉर्म पर इमेज बनाई जाती है. उदाहरण के लिए, एमएल किट क्विकस्टार्ट सैंपल में previewOverlayView और CameraViewController क्लास देखें.