دليل تقسيم الصور لنظام التشغيل iOS

تتيح لك مهمة "مُقسِّم الصور" تقسيم الصور إلى مناطق استنادًا إلى ملف شخصي مُحدّد مسبقًا، وتطبيق تأثيرات مرئية مثل تمويه الخلفية. توضّح لك هذه التعليمات كيفية استخدام أداة "تقسيم الصور" مع تطبيقات iOS.

يتوفّر نموذج الرمز البرمجي الموضّح في هذه التعليمات على GitHub.

يمكنك الاطّلاع على هذه المهمة وهي قيد التنفيذ من خلال الاطّلاع على العرض التوضيحي للويب. لمزيد من المعلومات عن الإمكانات والنماذج وخيارات الضبط لهذه المهمة، اطّلِع على نظرة عامة.

مثال على الرمز البرمجي

يحتوي مثال رمز MediaPipe Tasks على تنفيذ بسيط لتطبيق Image Segmenter لنظام التشغيل iOS.

ينفِّذ المثال أداة لتقسيم الصور تُخرج أقنعة الفئات. ويستخدم هذا الإجراء الكاميرا على جهاز iOS لإجراء تقسيم الصور في خلاصة كاميرا حية أو على الصور والفيديوهات من معرض الصور على الجهاز.

يمكنك استخدام التطبيق كنقطة بداية لتطبيقك المتوافق مع نظام التشغيل iOS، أو الرجوع إليه عند تعديل تطبيق حالي. يتم استضافة رمز مثال "أداة تقسيم الصور" على GitHub.

تنزيل الرمز

توضّح لك التعليمات التالية كيفية إنشاء نسخة محلية من نموذج الرمز باستخدام أداة سطر الأوامر git.

لتنزيل نموذج الرمز:

  1. استنسِخ مستودع git باستخدام الأمر التالي:

    git clone https://github.com/google-ai-edge/mediapipe-samples/
    
  2. يمكنك اختياريًا ضبط مثيل git لاستخدام ميزة "الفحص الخفيف"، بحيث تتوفّر لديك فقط ملفات مثال تطبيق "أداة تقسيم الصور":

    cd mediapipe
    git sparse-checkout init --cone
    git sparse-checkout set examples/image_segmentation/ios/
    

بعد إنشاء نسخة محلية من نموذج الرمز البرمجي، يمكنك تثبيت مكتبة مهام MediaPipe وفتح المشروع باستخدام Xcode وتشغيل التطبيق. للاطّلاع على التعليمات، راجِع دليل الإعداد لنظام التشغيل iOS.

المكوّنات الرئيسية

تحتوي الملفات التالية على الرمز البرمجي المهم لتطبيق مثال "مُقسِّم الصور" :

  • ImageSegmenterService.swift: تُستخدَم هذه الوظيفة لإعداد أداة "تقسيم الصور" ومعالجة اختيار النموذج وتنفيذ عملية التنقّل في البيانات المُدخلة.
  • CameraViewController.swift: ينفِّذ واجهة المستخدم لوضع إدخال خلاصة الكاميرا المباشرة ويعرض visually results.
  • MediaLibraryViewController.swift: تنفِّذ واجهة المستخدم لوضع إدخال الصور الثابتة وملفات الفيديو، ويُمكن استخدامها لعرض النتائج.

ضبط إعدادات الجهاز

يوضّح هذا القسم الخطوات الرئيسية لإعداد بيئة التطوير و مشاريع الرموز البرمجية لاستخدام أداة "تقسيم الصور". للحصول على معلومات عامة عن إعداد بيئة التطوير لاستخدام مهام MediaPipe، بما في ذلك متطلبات إصدار النظام الأساسي، يُرجى الاطّلاع على دليل الإعداد لنظام التشغيل iOS.

التبعيات

تستخدِم أداة "تقسيم الصور" مكتبة MediaPipeTasksVision التي يجب تثبيتها باستخدام CocoaPods. وتتوافق المكتبة مع تطبيقي Swift وObjective-C ولا تتطلب أي إعداد إضافي بلغة محدّدة.

للحصول على تعليمات لتثبيت CocoaPods على نظام التشغيل macOS، يُرجى الرجوع إلى دليل تثبيت CocoaPods . للحصول على تعليمات حول كيفية إنشاء Podfile باستخدام المجموعات المتسلسلة اللازمة لتطبيقك، يمكنك الرجوع إلى استخدام CocoaPods.

أضِف مجموعة MediaPipeTasksVision في Podfile باستخدام الرمز التالي:

target 'MyImageSegmenterApp' do
  use_frameworks!
  pod 'MediaPipeTasksVision'
end

إذا كان تطبيقك يتضمّن أهداف اختبار الوحدات، يمكنك الرجوع إلى دليل الإعداد لنظام التشغيل iOS للحصول على معلومات إضافية عن إعداد Podfile.

الطراز

تتطلّب مهمة "مُقسِّم الصور" من MediaPipe استخدام نموذج مدرَّب متوافق مع هذه المهمة. لمزيد من المعلومات عن النماذج المدربة المتاحة لميزة "مُقسِّم الصور"، اطّلِع على قسم نماذج ضمن النظرة العامة على المهمة.

اختَر نموذجًا ونزِّله وأضِفه إلى دليل مشروعك باستخدام Xcode. للحصول على تعليمات حول كيفية إضافة ملفات إلى مشروع Xcode، يُرجى الرجوع إلى مقالة إدارة الملفات والمجلدات في مشروع Xcode.

استخدِم السمة BaseOptions.modelAssetPath لتحديد مسار الوصول إلى النموذج في حِزمة تطبيقك. للاطّلاع على مثال على الرمز، يُرجى الاطّلاع على القسم التالي.

إنشاء المهمة

يمكنك إنشاء مهمة "أداة تقسيم الصور" من خلال طلب أحد برامج التهيئة. يقبل مُنشئ ImageSegmenter(options:) قيمًا لخيارات الضبط .

إذا لم تكن بحاجة إلى أداة "تقسيم الصور" تم إعدادها باستخدام خيارات إعداد مخصّصة، يمكنك استخدام أداة الإعداد ImageSegmenter(modelPath:) لإنشاء أداة "تقسيم الصور" باستخدام الخيارات التلقائية. لمزيد من المعلومات حول خيارات الضبط، يمكنك الاطّلاع على نظرة عامة على الضبط

تتوافق مهمة "أداة تقسيم الصور" مع 3 أنواع من بيانات الإدخال: الصور الثابتة وملفات الفيديو وعمليات بث الفيديو المباشر. بشكلٍ تلقائي، يبدأ ImageSegmenter(modelPath:) مهمة للصور الثابتة. إذا كنت تريد بدء مهمتك لمعالجة ملفات الفيديو أو أحداث بث الفيديو المباشر، استخدِم ImageSegmenter(options:) لتحديد وضع تشغيل الفيديو أو البث المباشر. يتطلّب وضع البث المباشر أيضًا خيار الضبط imageSegmenterLiveStreamDelegate الإضافي، الذي يتيح لميزة "تقسيم الصور" إرسال نتائج تقسيم الصور إلى المفوَّض بدون التزامن.

اختَر علامة التبويب المناسبة لوضع التشغيل لمعرفة كيفية إنشاء المهمة وتنفيذ الاستنتاج.

Swift

صورة

import MediaPipeTasksVision

let modelPath = Bundle.main.path(forResource: "model",
                                      ofType: "tflite")

let options = ImageSegmenterOptions()
options.baseOptions.modelAssetPath = modelPath
options.runningMode = .image
options.shouldOutputCategoryMask = true
options.shouldOutputConfidenceMasks = false

let imageSegmenter = try ImageSegmenter(options: options)
    

فيديو

import MediaPipeTasksVision

let modelPath = Bundle.main.path(forResource: "model",
                                      ofType: "tflite")

let options = ImageSegmenterOptions()
options.baseOptions.modelAssetPath = modelPath
options.runningMode = .video
options.shouldOutputCategoryMask = true
options.shouldOutputConfidenceMasks = false

let imageSegmenter = try ImageSegmenter(options: options)
    

بث مباشر

import MediaPipeTasksVision

// Class that conforms to the `imageSegmenterLiveStreamDelegate` protocol and
// implements the method that the image segmenter calls once it finishes
// performing segmentation of each input frame.
class ImageSegmenterResultProcessor: NSObject, ImageSegmenterLiveStreamDelegate {

  func imageSegmenter(
    _ imageSegmenter: ImageSegmenter,
    didFinishSegmentation result: ImageSegmenterResult?,
    timestampInMilliseconds: Int,
    error: Error?) {

    // Process the image segmentation result or errors here.

  }
}

let modelPath = Bundle.main.path(forResource: "model",
                                      ofType: "tflite")

let options = ImageSegmenterOptions()
options.baseOptions.modelAssetPath = modelPath
options.runningMode = .liveStream
options.shouldOutputCategoryMask = true
options.shouldOutputConfidenceMasks = false

// Set `imageSegmenterLiveStreamDelegate` to the object of the class that
// confirms to the `ImageSegmenterLiveStreamDelegate` protocol.
let processor = ImageSegmenterResultProcessor()
options.imageSegmenterLiveStreamDelegate = processor

let imageSegmenter = try ImageSegmenter(options: options)
    

Objective-C

صورة

@import MediaPipeTasksVision;

NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"model"
                                                      ofType:@"tflite"];

MPPImageSegmenterOptions *options = [[MPPImageSegmenterOptions alloc] init];
options.baseOptions.modelAssetPath = modelPath;
options.runningMode = MPPRunningModeImage;
options.shouldOutputCategoryMask = YES;
options.shouldOutputConfidenceMasks = NO;

MPPImageSegmenter *imageSegmenter =
  [[MPPImageSegmenter alloc] initWithOptions:options error:nil];
    

فيديو

@import MediaPipeTasksVision;

NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"model"
                                                      ofType:@"tflite"];

MPPImageSegmenterOptions *options = [[MPPImageSegmenterOptions alloc] init];
options.baseOptions.modelAssetPath = modelPath;
options.runningMode = MPPRunningModeVideo;
options.shouldOutputCategoryMask = YES;
options.shouldOutputConfidenceMasks = NO;

MPPImageSegmenter *imageSegmenter =
  [[MPPImageSegmenter alloc] initWithOptions:options error:nil];
    

بث مباشر

@import MediaPipeTasksVision;

// Class that conforms to the `MPPImageSegmenterLiveStreamDelegate` protocol
// and implements the method that the image segmenter calls once it finishes
// performing segmentation of each input frame.

@interface APPImageSegmenterResultProcessor : NSObject 

@end

@implementation APPImageSegmenterResultProcessor

-   (void)imageSegmenter:(MPPImageSegmenter *)imageSegmenter
    didFinishSegmentationWithResult:(MPPImageSegmenterResult *)imageSegmenterResult
         timestampInMilliseconds:(NSInteger)timestampInMilliseconds
                           error:(NSError *)error {

    // Process the image segmentation result or errors here.

}

@end

NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"model"
                                                      ofType:@"tflite"];

MPPImageSegmenterOptions *options = [[MPPImageSegmenterOptions alloc] init];
options.baseOptions.modelAssetPath = modelPath;
options.runningMode = MPPRunningModeLiveStream;
options.shouldOutputCategoryMask = YES;
options.shouldOutputConfidenceMasks = NO;

// Set `imageSegmenterLiveStreamDelegate` to the object of the class that
// confirms to the `MPPImageSegmenterLiveStreamDelegate` protocol.
APPImageSegmenterResultProcessor *processor =
  [APPImageSegmenterResultProcessor new];
options.imageSegmenterLiveStreamDelegate = processor;

MPPImageSegmenter *imageSegmenter =
  [[MPPImageSegmenter alloc] initWithOptions:options error:nil];
    

يتيح مثال تنفيذ رمز "مُقسِّم الصور" للمستخدم التبديل بين أوضاع المعالجة. تجعل هذه الطريقة رمز إنشاء المهمة أكثر تعقيدًا وقد لا تكون مناسبة لحالة الاستخدام لديك.

خيارات الضبط

تتضمّن هذه المهمة خيارات الضبط التالية لتطبيقات iOS:

اسم الخيار الوصف نطاق القيمة القيمة التلقائية
runningMode يضبط وضع التشغيل للمهمة. هناك ثلاثة أوضاع:

IMAGE: وضع الإدخالات المكوّنة من صورة واحدة.

الفيديو: وضع الإطارات التي تم فك ترميزها في فيديو

LIVE_STREAM: وضع البث المباشر لبيانات المعالجة التي يتم إدخالها، مثل البيانات الواردة من كاميرا في هذا الوضع، يجب ضبط ImageSegmenterLiveStreamDelegate على مثيل لفئة تنفِّذ ImageSegmenterLiveStreamDelegate لتلقّي نتائج التقسيم بشكل غير متزامن.
{RunningMode.image, RunningMode.video, RunningMode.liveStream} RunningMode.image
shouldOutputCategoryMask في حال ضبطه على True، يتضمّن الناتج قناع تقسيم كصورة uint8، حيث تشير قيمة كل بكسل إلى قيمة الفئة الفائزة. {True, False} False
shouldOutputConfidenceMasks في حال ضبط القيمة على True، سيتضمّن الناتج قناع تصنيف على شكل صورة قيمة عائمة، حيث تمثل كل قيمة عائمة خريطة نتيجة الثقة الخاصة بالفئة. {True, False} True
displayNamesLocale لضبط لغة التصنيفات لاستخدامها في الأسماء المعروضة المقدَّمة في البيانات الوصفية لنموذج المهمة، في حال توفّرها. القيمة التلقائية هي en لعبارة English. يمكنك إضافة تصنيفات مترجَمة إلى البيانات الوصفية لنموذج مخصّص باستخدام واجهة برمجة التطبيقات TensorFlow Lite Metadata Writer API. رمز اللغة en
result_callback تضبط أداة معالجة النتائج على تلقّي نتائج التقسيم بشكل غير متزامن عندما تكون أداة تقسيم الصور في وضع LIVE_STREAM. لا يمكن استخدامها إلا عند ضبط وضع التشغيل على LIVE_STREAM لا ينطبق لا ينطبق

عند ضبط وضع التشغيل على LIVE_STREAM، تتطلب "أداة تقسيم الصور" خيار إعداد "imageSegmenterLiveStreamDelegate" الإضافي، الذي يمكّن "أداة تقسيم الصور" من تقديم نتائج تصنيف الصور إلى شرائح بشكل غير متزامن. يجب أن ينفذ المفوَّض الأسلوب imageSegmenter(_:didFinishSegmentation:timestampInMilliseconds:error:)، الذي يستدعيه "أداة تقسيم الصور" بعد معالجة نتائج تنفيذ التقسيم على كل إطار.

اسم الخيار الوصف نطاق القيمة القيمة التلقائية
imageSegmenterLiveStreamDelegate يتم تفعيل أداة تقسيم الصور من أجل تلقّي نتائج إجراء تقسيم الصور بشكل غير متزامن في وضع البث المباشر. يجب أن تنفّذ الفئة التي تم ضبط مثيلها على هذه السمة الأسلوب imageSegmenter(_:didFinishSegmentation:timestampInMilliseconds:error:). لا تنطبق لم يتم ضبط الوضع

إعداد البيانات

عليك تحويل الصورة أو الإطار المُدخل إلى عنصر MPImage قبل إرساله إلى أداة "تقسيم الصور". يتيح MPImage أنواعًا مختلفة من تنسيقات الصور في نظام التشغيل iOS، ويمكنه استخدامها في أي وضع تشغيل للاستنتاج. لمزيد من المعلومات عن MPImage، يُرجى الرجوع إلى MPImage API.

اختَر تنسيق صورة iOS استنادًا إلى حالة الاستخدام ووضع التشغيل الذي يتطلبه تطبيقك. يقبلMPImage تنسيقات صور iOS UIImage وCVPixelBuffer و CMSampleBuffer.

UIImage

التنسيق UIImage مناسب تمامًا لأوضاع التشغيل التالية:

  • الصور: يمكن تحويل الصور من حِزمة تطبيق أو معرض مستخدم أو نظام ملفات بتنسيق UIImage إلى كائن MPImage.

  • الفيديوهات: استخدِم AVAssetImageGenerator لاستخراج إطارات الفيديو إلى تنسيق CGImage، ثم حوِّلها إلى UIImage صورة

Swift

// Load an image on the user's device as an iOS `UIImage` object.

// Convert the `UIImage` object to a MediaPipe's Image object having the default
// orientation `UIImage.Orientation.up`.
let image = try MPImage(uiImage: image)
    

Objective-C

// Load an image on the user's device as an iOS `UIImage` object.

// Convert the `UIImage` object to a MediaPipe's Image object having the default
// orientation `UIImageOrientationUp`.
MPImage *image = [[MPPImage alloc] initWithUIImage:image error:nil];
    

يُنشئ المثال MPImage بالاتجاه التلقائي UIImage.Orientation.Up . يمكنك إعداد MPImage باستخدام أي من قيم UIImage.Orientation المسموح بها. لا تتيح أداة "تقسيم الصور" استخدام الاتجاهات المقلّدة مثل .upMirrored .downMirrored و.leftMirrored و.rightMirrored.

لمزيد من المعلومات حول UIImage، يُرجى الرجوع إلى مستندات مطوّري تطبيقات Apple المتعلّقة بـ UIImage .

CVPixelBuffer

تنسيق CVPixelBuffer مناسب تمامًا للتطبيقات التي تُنشئ إطارات وتستخدِم إطار عمل CoreImage في iOS للمعالجة.

يناسب تنسيق CVPixelBuffer تمامًا أوضاع الجري التالية:

  • الصور: إنّ التطبيقات التي تنشئ صور CVPixelBuffer بعد إجراء بعض المعالجة باستخدام إطار العمل CoreImage في iOS يمكن إرسالها إلى "أداة تقسيم الصور" في وضع عرض الصور.

  • الفيديوهات: يمكن تحويل لقطات الفيديو إلى تنسيق CVPixelBuffer لمعالجتها، ثم إرسالها إلى أداة "تقسيم الصور" في وضع الفيديو.

  • البث المباشر: قد يتم تحويل التطبيقات التي تستخدم كاميرا iOS لإنشاء اللقطات إلى تنسيق CVPixelBuffer لمعالجتها قبل إرسالها إلى أداة "تقسيم الصور" في وضع البث المباشر.

Swift

// Obtain a CVPixelBuffer.

// Convert the `CVPixelBuffer` object to a MediaPipe's Image object having the default
// orientation `UIImage.Orientation.up`.
let image = try MPImage(pixelBuffer: pixelBuffer)
    

Objective-C

// Obtain a CVPixelBuffer.

// Convert the `CVPixelBuffer` object to a MediaPipe's Image object having the
// default orientation `UIImageOrientationUp`.
MPImage *image = [[MPPImage alloc] initWithUIImage:image error:nil];
    

لمزيد من المعلومات حول CVPixelBuffer، يمكنك الاطّلاع على وثائق مطوّري أعمال CVPixelBuffer من Apple.

CMSampleBuffer

يخزّن تنسيق CMSampleBuffer عيّنات وسائط من نوع وسائط موحّد، وهو مناسب لوضع تشغيل البث المباشر. يتم إرسال اللقطات المباشرة من كاميرات iOS بشكل غير متزامن بتنسيق CMSampleBuffer من خلال iOS AVCaptureVideoDataOutput.

Swift

// Obtain a CMSampleBuffer.

// Convert the `CMSampleBuffer` object to a MediaPipe's Image object having the default
// orientation `UIImage.Orientation.up`.
let image = try MPImage(sampleBuffer: sampleBuffer)
    

Objective-C

// Obtain a `CMSampleBuffer`.

// Convert the `CMSampleBuffer` object to a MediaPipe's Image object having the
// default orientation `UIImageOrientationUp`.
MPImage *image = [[MPPImage alloc] initWithSampleBuffer:sampleBuffer error:nil];
    

لمزيد من المعلومات حول CMSampleBuffer، يُرجى الاطّلاع على وثائق مطوّري برامج Apple CMSampleBuffer.

تنفيذ المهمة

لتشغيل أداة "تقسيم الصور"، استخدِم طريقة segment() الخاصة بالوضع الذي تم تعيينه:

  • صورة ثابتة: segment(image:)
  • الفيديو: segment(videoFrame:timestampInMilliseconds:)
  • بث مباشر: segmentAsync(image:timestampInMilliseconds:)

تعرض نماذج الرموز البرمجية التالية أمثلة بسيطة على كيفية تشغيل أداة "تقسيم الصور" في أوضاع التشغيل المختلفة التالية:

Swift

صورة

let result = try imageSegmenter.segment(image: image)
    

فيديو

let result = try imageSegmenter.segment(
  videoFrame: image,
  timestampInMilliseconds: timestamp)
    

بث مباشر

try imageSegmenter.segmentAsync(
  image: image,
  timestampInMilliseconds: timestamp)
    

Objective-C

صورة

MPPImageSegmenterResult *result =
  [imageSegmenter segmentImage:image error:nil];
    

فيديو

MPPImageSegmenterResult *result =
  [imageSegmenter segmentVideoFrame:image
            timestampInMilliseconds:timestamp
                              error:nil];
    

بث مباشر

BOOL success =
  [imageSegmenter segmentAsyncImage:image
            timestampInMilliseconds:timestamp
                              error:nil];
    

يوضّح مثال رمز أداة تقسيم الصور عمليات تنفيذ كل من هذه الأوضاع بمزيد من التفصيل segment(image:) وsegment(videoFrame:timestampInMilliseconds:) وsegmentAsync(image:timestampInMilliseconds:).

يُرجى ملاحظة ما يلي:

  • عند التشغيل في وضع الفيديو أو وضع البث المباشر، يجب أيضًا تقديم الطابع الزمني لإطار الإدخال إلى مهمة "مُقسِّم الصور".

  • عند التشغيل في وضع الصورة أو الفيديو، تحظر مهمة "مُقسِّم الصور" السلسلة الجارية إلى أن تنتهي من معالجة الصورة أو اللقطة المُدخلة. لتجنُّب حظر سلسلة المحادثات الحالية، نفِّذ المعالجة في سلسلة محادثات خلفية باستخدام إطارَي عمل iOS Dispatch أو NSOperation.

  • عند تفعيل "وضع البث المباشر"، تظهر مهمة "أداة تقسيم الصور" في الحال ولا تحجب سلسلة المحادثات الحالية. وهو يستدعي الطريقة imageSegmenter(_:didFinishSegmentation:timestampInMilliseconds:error:) مع أداة تقسيم الصور بعد معالجة كل إطار إدخال. وتستدعي أداة تقسيم الصور هذه الطريقة بشكل غير متزامن على قائمة انتظار إرسال تسلسلية مخصصة. لعرض النتائج على واجهة المستخدم، يُرجى إرسال النتائج إلى قائمة الانتظار الرئيسية بعد معالجة النتائج. إذا تم استدعاء الدالة segmentAsync عندما تكون مهمة أداة تقسيم الصور مشغولة بمعالجة إطار آخر، تتجاهل أداة تقسيم الصور إطار الإدخال الجديد.

معالجة النتائج وعرضها

عند تنفيذ الاستنتاج، تُعرِض مهمة "مُقسِّم الصور" ImageSegmenterResult عنصرًا يحتوي على نتائج مهمة التقسيم. يعتمد محتوى المخرجات على نوع المخرجات الذي تحدّده عند ضبط المهمة.

تعرض الصور التالية تمثيلاً مرئيًا لمعدّل إنجاز المهمة لقناع قيمة الفئة. نطاق قناع الفئة هو [0, 255]، وتمثل كل قيمة بكسل فهرس الفئة الفائزة في مخرجات النموذج. يحصل فئة الفهرس الفائزة على أعلى نتيجة بين الفئات التي يمكن للنموذج التعرّف عليها.

الصورة الأصلية ونتيجة قناع الفئة الصورة المصدر من مجموعة بيانات Pascal VOC 2012.

يوضّح مثال الرمز البرمجي لواحدة من ميزات "تقسيم الصور" كيفية عرض نتائجها، اطّلِع على مثال الرمز البرمجي للاطّلاع على التفاصيل.