iOS-এ ML কিটের সাথে সেলফি সেগমেন্টেশন

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

চেষ্টা করে দেখুন

  • এই API-টির একটি উদাহরণমূলক ব্যবহার দেখতে নমুনা অ্যাপটি ব্যবহার করে দেখুন।

শুরু করার আগে

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

    pod 'GoogleMLKit/SegmentationSelfie', '8.0.0'
    
  2. আপনার প্রোজেক্টের পডগুলো ইনস্টল বা আপডেট করার পর, সেটির xcworkspace ব্যবহার করে আপনার এক্সকোড প্রোজেক্টটি খুলুন। এমএল কিট এক্সকোড ভার্সন ১৩.২.১ বা তার উচ্চতর সংস্করণে সমর্থিত।

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

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

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

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

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

STREAM_MODE (default)

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

SINGLE_IMAGE_MODE (default)

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

কাঁচা আকারের মাস্ক সক্রিয় করুন

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

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

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

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

সুইফট

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

উদ্দেশ্য-সি

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

অবশেষে, Segmenter এর একটি ইনস্ট্যান্স নিন। আপনার নির্দিষ্ট করা অপশনগুলো পাস করুন:

সুইফট

let segmenter = Segmenter.segmenter(options: options)

উদ্দেশ্য-সি

MLKSegmenter *segmenter = [MLKSegmenter segmenterWithOptions:options];

২. ইনপুট চিত্রটি প্রস্তুত করুন।

সেলফিগুলোকে ভাগ করার জন্য, প্রতিটি ছবি বা ভিডিওর ফ্রেমের ক্ষেত্রে নিম্নলিখিত পদক্ষেপগুলো অনুসরণ করুন। যদি আপনি স্ট্রিম মোড চালু করে থাকেন, তবে আপনাকে অবশ্যই CMSampleBuffer থেকে VisionImage অবজেক্ট তৈরি করতে হবে।

একটি UIImage বা একটি CMSampleBuffer ব্যবহার করে একটি VisionImage অবজেক্ট তৈরি করুন।

আপনি যদি UIImage ব্যবহার করেন, তাহলে এই ধাপগুলো অনুসরণ করুন:

  • UIImage ব্যবহার করে একটি VisionImage অবজেক্ট তৈরি করুন। সঠিক .orientation উল্লেখ করতে ভুলবেন না।

    সুইফট

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

    উদ্দেশ্য-সি

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

আপনি যদি CMSampleBuffer ব্যবহার করেন, তাহলে এই ধাপগুলো অনুসরণ করুন:

  • CMSampleBuffer এ থাকা ইমেজ ডেটার অভিমুখ নির্দিষ্ট করুন।

    ছবির অভিমুখ পেতে:

    সুইফট

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

    উদ্দেশ্য-সি

    - (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 অবজেক্ট তৈরি করুন:

    সুইফট

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

    উদ্দেশ্য-সি

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

৩. ছবিটি প্রক্রিয়া করুন

VisionImage অবজেক্টটি Segmenter এর যেকোনো একটি ইমেজ প্রসেসিং মেথডে পাস করুন। আপনি অ্যাসিঙ্ক্রোনাস process(image:) মেথড অথবা সিঙ্ক্রোনাস results(in:) মেথড ব্যবহার করতে পারেন।

একটি সেলফি ছবিতে একযোগে সেগমেন্টেশন সম্পাদন করতে:

সুইফট

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.

উদ্দেশ্য-সি

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

// Success. Get a segmentation mask here.

একটি সেলফি ছবিতে অ্যাসিঙ্ক্রোনাসভাবে সেগমেন্টেশন সম্পাদন করতে:

সুইফট

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

উদ্দেশ্য-সি

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

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

আপনি নিম্নলিখিতভাবে বিভাজনের ফলাফল পেতে পারেন:

সুইফট

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
}

উদ্দেশ্য-সি

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

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

কর্মক্ষমতা উন্নত করার টিপস

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

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

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

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