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

ML Kit সেলফি সেগমেন্টেশনের জন্য একটি অপ্টিমাইজড SDK প্রদান করে। সেলফি সেগমেন্টার অ্যাসেটগুলি তৈরির সময় আপনার অ্যাপের সাথে স্ট্যাটিক্যালি লিঙ্ক করা থাকে। এটি আপনার অ্যাপের আকার 24MB পর্যন্ত বৃদ্ধি করবে এবং API ল্যাটেন্সি ~7ms থেকে ~12ms পর্যন্ত পরিবর্তিত হতে পারে ইনপুট ছবির আকারের উপর নির্ভর করে, যেমন iPhone X-তে পরিমাপ করা হয়েছে।

চেষ্টা করে দেখো

শুরু করার আগে

  1. আপনার পডফাইলে নিম্নলিখিত ML কিট লাইব্রেরিগুলি অন্তর্ভুক্ত করুন:

    pod 'GoogleMLKit/SegmentationSelfie', '8.0.0'
    
  2. আপনার প্রোজেক্টের পড ইনস্টল বা আপডেট করার পর, আপনার Xcode প্রোজেক্টটি xcworkspace ব্যবহার করে খুলুন। ML Kit Xcode সংস্করণ 13.2.1 বা তার উচ্চতর সংস্করণে সমর্থিত।

১. সেগমেন্টারের একটি উদাহরণ তৈরি করুন

একটি সেলফি ছবিতে সেগমেন্টেশন করতে, প্রথমে 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];

2. ইনপুট ইমেজ প্রস্তুত করুন

সেলফিগুলিকে ভাগ করার জন্য, প্রতিটি ছবি বা ভিডিওর ফ্রেমের জন্য নিম্নলিখিতগুলি করুন। যদি আপনি স্ট্রিম মোড সক্ষম করে থাকেন, তাহলে আপনাকে 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);
}

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

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

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

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

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

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