iOS-এ ML Kit-এর মাধ্যমে সেলফি সেগমেন্টেশন

ML Kit সেলফি সেগমেন্টেশনের জন্য অপ্টিমাইজ করা SDK প্রদান করে। সেলফি সেগমেন্টার অ্যাসেট বিল্ড করার সময় আপনার অ্যাপের সাথে স্ট্যাটিক্যালি লিঙ্ক করা হয়। এর ফলে আপনার অ্যাপের সাইজ ২৪ এমবি পর্যন্ত বেড়ে যাবে এবং ইনপুট ছবির সাইজের উপর নির্ভর করে API লেটেন্সি ~৭ মিলি সেকেন্ড থেকে ~১২ মিলি সেকেন্ড পর্যন্ত হতে পারে, যেমন iPhone X-এ পরিমাপ করা হয়েছে।

এটি ব্যবহার করে দেখুন

শুরু করার আগে

  1. আপনার Podfile-এ নিম্নলিখিত ML Kit লাইব্রেরি অন্তর্ভুক্ত করুন:

    pod 'GoogleMLKit/SegmentationSelfie', '8.0.0'
    
  2. আপনার প্রোজেক্টের Pods ইনস্টল বা আপডেট করার পরে, .xcworkspace ব্যবহার করে আপনার Xcode প্রোজেক্ট খুলুন। ML Kit, Xcode ভার্সন 13.2.1 বা তার পরবর্তী যেকোনও ভার্সনে কাজ করে।

১. সেগমেন্টারের একটি ইনস্ট্যান্স তৈরি করুন

সেলফি ইমেজে সেগমেন্টেশন করতে, প্রথমে SelfieSegmenterOptions সহ Segmenter-এর ইনস্ট্যান্স তৈরি করুন এবং বিকল্প হিসেবে সেগমেন্টেশন সেটিংস নির্দিষ্ট করুন।

সেগমেন্টার বিকল্প

সেগমেন্টার মোড

Segmenter দুটি মোডে কাজ করে। আপনার ব্যবহারের সাথে মানানসই বিকল্পটি বেছে নিয়েছেন কিনা দেখে নিন।

STREAM_MODE (default)

এই মোডটি ভিডিও বা ক্যামেরা থেকে ফ্রেম স্ট্রিম করার জন্য ডিজাইন করা হয়েছে। এই মোডে, সেগমেন্টার আগের ফ্রেম থেকে ফলাফল ব্যবহার করে আরও মসৃণ সেগমেন্টেশন ফলাফল প্রদান করবে।

SINGLE_IMAGE_MODE (default)

এই মোডটি এমন একক ছবির জন্য ডিজাইন করা হয়েছে যা একে অপরের সাথে সম্পর্কিত নয়। এই মোডে, সেগমেন্টার প্রতিটি ছবি আলাদাভাবে প্রসেস করবে, ফ্রেমের উপর কোনও স্মুদিং থাকবে না।

র সাইজ মাস্ক চালু করুন

সেগমেন্টারকে র-সাইজ মাস্ক ফেরত দিতে বলে যা মডেল আউটপুট সাইজের সাথে মেলে।

র মাস্ক সাইজ (যেমন, ২৫৬x২৫৬) সাধারণত ইনপুট ছবির সাইজের থেকে ছোট হয়।

এই বিকল্প নির্দিষ্ট না করলে, সেগমেন্টার ইনপুট ছবির সাইজের সাথে ম্যাচ করার জন্য র-মাস্ক রিস্কেল করবে। আপনি যদি কাস্টমাইজ করা রিস্কেলিং লজিক প্রয়োগ করতে চান অথবা আপনার ব্যবহারের ক্ষেত্রে রিস্কেলিংয়ের প্রয়োজন না হয়, তাহলে এই বিকল্পটি ব্যবহার করার কথা বিবেচনা করুন।

সেগমেন্টার বিকল্প নির্দিষ্ট করুন:

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

২. ইনপুট ছবি প্রস্তুত করুন

সেলফি সেগমেন্ট করতে, প্রতিটি ছবি বা ভিডিওর ফ্রেমের জন্য নিম্নলিখিত ধাপগুলি অনুসরণ করুন। আপনি স্ট্রিম মোড চালু করলে, আপনাকে অবশ্যই 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];

৩. ছবি প্রসেস করুন

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.
             }];

৪. সেগমেন্টেশন মাস্ক পান

আপনি নিম্নলিখিত উপায়ে সেগমেন্টেশনের ফলাফল পেতে পারেন:

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

সেগমেন্টেশন ফলাফল কীভাবে ব্যবহার করতে হয় তার সম্পূর্ণ উদাহরণের জন্য, ML Kit কুইকস্টার্ট স্যাম্পেল দেখুন।

পারফর্ম্যান্স উন্নত করার পরামর্শ

আপনার ফলাফলের কোয়ালিটি ইনপুট ছবির কোয়ালিটির উপর নির্ভর করে:

  • ML Kit যাতে সঠিক সেগমেন্টেশন ফলাফল পেতে পারে, তার জন্য ছবি অন্তত ২৫৬x২৫৬ পিক্সেল হতে হবে।
  • আপনি রিয়েল-টাইম অ্যাপ্লিকেশনে সেলফি সেগমেন্টেশন করলে, ইনপুট ছবির সামগ্রিক ডাইমেনশনও বিবেচনা করতে চাইতে পারেন। ছোট ছবি দ্রুত প্রসেস করা যায়, তাই লেটেন্সি কমাতে কম রেজোলিউশনে ছবি তুলুন, তবে উপরে উল্লেখ করা রেজোলিউশন সংক্রান্ত প্রয়োজনীয়তা মাথায় রাখুন এবং নিশ্চিত করুন যে ছবির যতটা সম্ভব বেশি অংশ জুড়ে যেন সাবজেক্ট থাকে।
  • ছবির ফোকাস খারাপ হলেও নির্ভুলতার উপর প্রভাব পড়তে পারে। আপনি গ্রহণযোগ্য ফলাফল না পেলে, ব্যবহারকারীকে আবার ছবি তুলতে বলুন।

আপনি যদি রিয়েল-টাইম অ্যাপ্লিকেশনে সেগমেন্টেশন ব্যবহার করতে চান, তাহলে সেরা ফ্রেম রেট পেতে এই নির্দেশিকাগুলি অনুসরণ করুন:

  • stream সেগমেন্টার মোড ব্যবহার করুন।
  • কম রেজোলিউশনে ছবি তোলার কথা বিবেচনা করুন। তবে, এই API-এর ছবির ডাইমেনশন সংক্রান্ত প্রয়োজনীয়তাও মনে রাখবেন।
  • ভিডিও ফ্রেম প্রসেস করার জন্য, সেগমেন্টারের results(in:) সিঙ্ক্রোনাস API ব্যবহার করুন। প্রদত্ত ভিডিও ফ্রেম থেকে সিঙ্ক্রোনাসভাবে ফলাফল পেতে AVCaptureVideoDataOutputSampleBufferDelegate-এর captureOutput(_, didOutput:from:) ফাংশন থেকে এই পদ্ধতি কল করুন। সেগমেন্টারে কল থ্রটল করতে AVCaptureVideoDataOutput-এর alwaysDiscardsLateVideoFrames-কে true হিসেবে সেট করুন। সেগমেন্টার চলাকালীন নতুন ভিডিও ফ্রেম উপলভ্য হলে, সেটি ড্রপ করা হবে।
  • ইনপুট ইমেজে গ্রাফিক্স ওভারলে করার জন্য সেগমেন্টারের আউটপুট ব্যবহার করলে, প্রথমে ML Kit থেকে ফলাফল পান, তারপর ইমেজ রেন্ডার করুন এবং একটি ধাপে ওভারলে করুন। এটি করার মাধ্যমে, আপনি প্রতিটি প্রসেস করা ইনপুট ফ্রেমের জন্য ডিসপ্লে সারফেসে শুধুমাত্র একবার রেন্ডার করেন। উদাহরণ দেখতে ML Kit কুইকস্টার্ট স্যাম্পেল-এ previewOverlayView এবং CameraViewController ক্লাস দেখুন।