توفّر حزمة تعلّم الآلة حزمة تطوير برامج (SDK) محسّنة لتصنيف الصور الذاتية. تكون مواد عرض "أداة تقسيم الصور الذاتية" مرتبطة بشكل ثابت بتطبيقك في وقت الإصدار. سيؤدي ذلك إلى زيادة حجم التطبيق بمقدار 24 ميغابايت، ويمكن أن يختلف وقت استجابة واجهة برمجة التطبيقات من 7 ملي ثانية إلى ما يقرب من 12 ملي ثانية حسب حجم الصورة التي يتم إدخالها، كما يتم قياسه على هاتف iPhone X.
جرّبه الآن
- يمكنك تجربة نموذج التطبيق من أجل يمكنك الاطّلاع على مثال حول استخدام واجهة برمجة التطبيقات هذه.
قبل البدء
تضمين مكتبات ML Kit التالية في Podfile:
pod 'GoogleMLKit/SegmentationSelfie', '3.2.0'
بعد تثبيت لوحات مشروعك أو تحديثها، افتح مشروع Xcode باستخدام ملف
xcworkspace
. تتوفّر حزمة تعلّم الآلة في الإصدار 13.2.1 من Xcode أو الإصدارات الأحدث.
1. إنشاء مثيل لأداة تقسيم
لإجراء تصنيف على صورة ذاتية، عليك أولاً إنشاء مثيل Segmenter
باستخدام SelfieSegmenterOptions
، ثم تحديد إعدادات التصنيف إلى قطاعات أو شرائح.
خيارات أداة التقسيم
وضع أداة تقسيم البيانات
تعمل Segmenter
بوضعَين. احرص على اختيار الحالة التي تتطابق مع حالة استخدامك.
STREAM_MODE (default)
تم تصميم هذا الوضع لبث الإطارات من الفيديو أو الكاميرا. في هذا الوضع، سوف تستفيد أداة التقسيم من النتائج الواردة من الإطارات السابقة لعرض نتائج تصنيف أكثر سلاسة.
SINGLE_IMAGE_MODE (default)
تم تصميم هذا الوضع للصور الفردية غير المرتبطة ببعضها. في هذا الوضع، سيعمل المقتطع على معالجة كل صورة على حدة، بدون التجانس على الإطارات.
تفعيل قناع حجم البيانات الأولية
تطلب من المقسِّم عرض قناع الحجم الأولي الذي يتطابق مع حجم إخراج النموذج.
عادةً ما يكون حجم القناع الأولي (على سبيل المثال 256×256) أصغر من حجم الصورة التي تم إدخالها.
بدون تحديد هذا الخيار، سيعيد المقتطع تغيير حجم القناع الأولي ليلائم حجم الصورة المدخلة. يمكنك استخدام هذا الخيار إذا كنت تريد تطبيق منطق مخصّص لتغيير الحجم أو عدم الحاجة إلى تغيير الحجم لحالة الاستخدام.
حدد خيارات أداة التقسيم:
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. تحضير صورة الإدخال
لتقسيم الصور الذاتية، اتّبِع الخطوات التالية لكل صورة أو إطار فيديو.
في حال تفعيل وضع البث، يجب إنشاء VisionImage
عناصر من
CMSampleBuffer
إنشاء عنصر VisionImage
باستخدام UIImage
أو
CMSampleBuffer
إذا كنت تستخدم UIImage
، يُرجى اتّباع الخطوات التالية:
- أنشئ كائن
VisionImage
باستخدامUIImage
. تأكَّد من تحديد قيمة.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; } }
- إنشاء عنصر
VisionImage
باستخدام عنصرCMSampleBuffer
والاتجاه: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); }
للاطلاع على مثال كامل عن كيفية استخدام نتائج التقسيم، يُرجى مراجعة نموذج للبدء السريع في حزمة تعلّم الآلة
نصائح لتحسين الأداء
تعتمد جودة نتائجك على جودة الصورة التي تم إدخالها:
- للحصول على نتائج تصنيف دقيقة لـ ML Kit، يجب أن يبلغ حجم الصورة 256x256 بكسل على الأقل.
- إذا كنت تجري تقسيمًا للصور الذاتية في تطبيق الوقت الفعلي، فقد تحتاج أيضًا إلى مراعاة الأبعاد الكلية لصور الإدخال. يمكن معالجة الصور الأصغر بشكل أسرع، لذلك لتقليل وقت الاستجابة، التقِط الصور بدرجات دقة أقل، ولكن يجب مراعاة متطلبات الدقة المذكورة أعلاه واحرص على أن يشغل الموضوع أكبر قدر ممكن من الصورة.
- ويمكن أن يؤثر التركيز الضعيف للصورة أيضًا في الدقة. إذا لم تحصل على نتائج مقبولة، اطلب من المستخدم تلخيص الصورة.
إذا أردت استخدام التصنيف إلى شرائح في تطبيق في الوقت الفعلي، عليك اتّباع الإرشادات التالية لتحقيق أفضل عدد من اللقطات في الثانية:
- استخدام وضع التقسيم
stream
. - يمكنك التقاط صور بدقة أقل. مع ذلك، ضَع في اعتبارك أيضًا متطلبات أبعاد الصورة في واجهة برمجة التطبيقات هذه.
- لمعالجة إطارات الفيديو، استخدِم واجهة برمجة التطبيقات المتزامنة
results(in:)
الخاصة بأداة التقسيم. استدعِ هذه الطريقة من دالة captureOutput(_, didOutput:from:) التابعة لـ AVCaptureVideoDataOutputSampleBufferDelegate للحصول على النتائج من إطار الفيديو المعني بشكل متزامن. أبقِ alwaysDiscardsLateVideoFrames التابع لـ AVCaptureVideoDataOutput مضبوطًا على ما إذا كان مضبوطًا على تقييد المكالمات الواردة إلى أداة التقسيم. إذا أصبح إطار فيديو جديد متاحًا أثناء تشغيل أداة التقسيم، سيتم تجاهلها. - في حال استخدام ناتج أداة التقسيم لتراكب الرسومات على الصورة التي تم إدخالها، يمكنك أولاً الحصول على النتيجة من أداة تعلّم الآلة، ثم عرض الصورة والتراكب في خطوة واحدة. ومن خلال القيام بذلك، فإنك تعرض المحتوى على سطح الشاشة مرة واحدة فقط لكل إطار إدخال تمت معالجته. راجع فئتي previewOverlayView وCameraViewController في نموذج البدء السريع لأدوات تعلُّم الآلة للحصول على مثال.