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