يمكنك استخدام حزمة تعلّم الآلة للتعرّف على الكيانات في صورة وتصنيفها. تتوافق واجهة برمجة التطبيقات هذه مع مجموعة كبيرة من نماذج تصنيف الصور المخصّصة. راجِع مقالة النماذج المخصّصة باستخدام حزمة تعلّم الآلة للحصول على إرشادات حول متطلبات توافق النماذج ومكان العثور على النماذج المدرَّبة مسبقًا وكيفية تدريب نماذجك الخاصة.
هناك طريقتان لدمج نموذج مخصّص، إما عن طريق تجميع النموذج ووضعه داخل مجلد مواد العرض في تطبيقك، أو عن طريق تنزيله ديناميكيًا من "مساحة التخزين السحابي". يوضّح الجدول التالي الفرق بين الخيارَين.
| النموذج المجمَّع | النموذج المستضاف |
|---|---|
| النموذج هو جزء من حِزمة APK الخاصة بتطبيقك، ما يؤدي إلى زيادة حجمها. | ولا يشكّل النموذج جزءًا من حزمة APK، بل تتم استضافته من خلال تحميله إلى Cloud Storage. وننصحك باستخدام Cloud Storage for Firebase. |
| يتوفّر النموذج على الفور، حتى عندما يكون جهاز Android غير متصل بالإنترنت. | يجب أن يتضمّن تطبيقك رمزًا برمجيًا لتنزيل النموذج عند الطلب |
| لا حاجة إلى مشروع Firebase | يتطلّب مشروع Firebase (في حال استخدام "مساحة تخزين سحابية لـ Firebase"). |
| يجب إعادة نشر تطبيقك لتحديث النموذج. | إرسال تحديثات النموذج بدون إعادة نشر تطبيقك |
| ما مِن ميزة مدمجة لاختبار A/B | إجراء اختبار A/B باستخدام ميزة الإعداد عن بُعد عبر Firebase |
للتجربة:
- يمكنك الاطّلاع على تطبيق البدء السريع الخاص بميزة "الرؤية" للحصول على مثال على استخدام النموذج المجمّع، وتطبيق البدء السريع الخاص بميزة AutoML للحصول على مثال على استخدام النموذج المستضاف.
قبل البدء
أدرِج مكتبات حزمة تعلّم الآلة في ملف Podfile:
pod 'GoogleMLKit/ImageLabelingCustom', '8.0.0'بعد تثبيت أو تعديل Pods في مشروعك، افتح مشروع Xcode باستخدام
.xcworkspace. تتوافق حزمة ML Kit مع الإصدار 13.2.1 أو الإصدارات الأحدث من Xcode.إذا أردت تنزيل نموذج باستخدام مساحة تخزين سحابية لـ Firebase، تأكَّد من إضافة Firebase إلى مشروع iOS، إذا لم يسبق لك إجراء ذلك. لا يكون ذلك مطلوبًا عند تجميع النموذج.
1. تحميل النموذج
ضبط مصدر نموذج محلي
لتضمين النموذج في تطبيقك، اتّبِع الخطوات التالية:
انسخ ملف النموذج (الذي ينتهي عادةً بـ
.tfliteأو.lite) إلى مشروع Xcode، مع الحرص على اختيارCopy bundle resourcesعند إجراء ذلك. سيتم تضمين ملف النموذج في حِزمة التطبيق وسيكون متاحًا لحزمة تعلّم الآلة.أنشئ الكائن
LocalModel، مع تحديد المسار إلى ملف النموذج:Swift
let localModel = LocalModel(path: localModelFilePath)
Objective-C
MLKLocalModel *localModel = [[MLKLocalModel alloc] initWithPath:localModelFilePath];
ضبط مصدر نموذج مستضاف عن بُعد
لاستخدام النموذج المستضاف عن بُعد، عليك تنزيل ملف النموذج إلى وحدة التخزين المحلية على الجهاز باستخدام منطق التطبيق الخاص بك، ثم تحميله كنموذج محلي. ننصحك باستخدام مساحة تخزين سحابية لـ Firebase لاستضافة نموذج. وللحصول على تفاصيل التنفيذ، راجِع دليل نقل البيانات من Firebase ML إلى Cloud Storage.
ضبط أداة تصنيف الصور
بعد ضبط مصادر النموذج، أنشئ عنصر ImageLabeler من أحدها.
تتوفّر الخيارات التالية:
| الخيارات | |
|---|---|
confidenceThreshold
|
الحدّ الأدنى لدرجة الثقة في التصنيفات التي تم رصدها في حال عدم ضبط هذه القيمة، سيتم استخدام أي حد مصنّف تحدّده البيانات الوصفية للنموذج. إذا كان النموذج لا يحتوي على أي بيانات وصفية أو إذا كانت البيانات الوصفية لا تحدّد حدًا أدنى للمصنّف، سيتم استخدام حد أدنى تلقائي يبلغ 0.0. |
maxResultCount
|
الحد الأقصى لعدد التصنيفات المطلوب عرضها. في حال عدم ضبطها، سيتم استخدام القيمة التلقائية 10. |
إذا كان لديك نموذج مجمّع محليًا فقط، ما عليك سوى إنشاء أداة تصنيف من عنصر
LocalModel:
Swift
let options = CustomImageLabelerOptions(localModel: localModel) options.confidenceThreshold = NSNumber(value: 0.0) let imageLabeler = ImageLabeler.imageLabeler(options: options)
Objective-C
MLKCustomImageLabelerOptions *options = [[MLKCustomImageLabelerOptions alloc] initWithLocalModel:localModel]; options.confidenceThreshold = @(0.0); MLKImageLabeler *imageLabeler = [MLKImageLabeler imageLabelerWithOptions:options];
إذا كان لديك نموذج مستضاف عن بُعد، عليك التأكّد من تنزيله قبل تشغيله.
على الرغم من أنّه عليك تأكيد ذلك قبل تشغيل أداة وضع التصنيفات، إذا كان لديك نموذج مستضاف عن بُعد ونموذج مجمّع محليًا، قد يكون من المنطقي إجراء هذا التحقّق عند إنشاء مثيل ImageLabeler: إنشاء أداة وضع تصنيفات من النموذج المستضاف عن بُعد إذا تم تنزيله، ومن النموذج المحلي في الحالات الأخرى.
Swift
// Path where your download logic saves the model let documentDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first! let localModelURL = documentDirectory.appendingPathComponent("my_remote_model.tflite") let model: LocalModel if FileManager.default.fileExists(atPath: localModelURL.path) { // Use the downloaded model model = LocalModel(path: localModelURL.path) } else { // Fall back to bundled model guard let bundledModelPath = Bundle.main.path(forResource: "model", ofType: "tflite") else { return } model = LocalModel(path: bundledModelPath) } let options = CustomImageLabelerOptions(localModel: model) let imageLabeler = ImageLabeler.imageLabeler(options: options)
Objective-C
NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject]; NSString *localModelPath = [documentsDirectory stringByAppendingPathComponent:@"my_remote_model.tflite"]; MLKLocalModel *model; if ([NSFileManager.defaultManager fileExistsAtPath:localModelPath]) { // Use the downloaded model model = [[MLKLocalModel alloc] initWithPath:localModelPath]; } else { // Fall back to bundled model NSString *bundledModelPath = [NSBundle.mainBundle pathForResource:@"model" ofType:@"tflite"]; model = [[MLKLocalModel alloc] initWithPath:bundledModelPath]; } MLKCustomImageLabelerOptions *options = [[MLKCustomImageLabelerOptions alloc] initWithLocalModel:model]; MLKImageLabeler *imageLabeler = [MLKImageLabeler imageLabelerWithOptions:options];
إذا كان لديك نموذج مستضاف عن بُعد فقط، عليك إيقاف الوظائف ذات الصلة بالنموذج، مثل إخفاء جزء من واجهة المستخدم أو عرضه باللون الرمادي، إلى أن تتأكّد من تنزيل النموذج.
Swift
let documentDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first! let localModelURL = documentDirectory.appendingPathComponent("my_remote_model.tflite") if FileManager.default.fileExists(atPath: localModelURL.path) { // Model is already cached, initialize immediately self.initializeLabeler(with: localModelURL) } else { // Model is not yet available, show loading UI and start download self.showLoadingUI() let storage = Storage.storage() let modelRef = storage.reference(forURL: "gs://YOUR_BUCKET/path/to/model.tflite") modelRef.write(toFile: localModelURL) { url, error in self.hideLoadingUI() if let error = error { // Handle download error self.showErrorUI() } else if let modelURL = url { // Download success, initialize labeler self.initializeLabeler(with: modelURL) } } } func initializeLabeler(with modelURL: URL) { let localModel = LocalModel(path: modelURL.path) let options = CustomImageLabelerOptions(localModel: localModel) self.imageLabeler = ImageLabeler.imageLabeler(options: options) // Enable ML-related UI features here self.enableMLFeatures() }
Objective-C
NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject]; NSString *localModelPath = [documentsDirectory stringByAppendingPathComponent:@"my_remote_model.tflite"]; NSURL *localModelURL = [NSURL fileURLWithPath:localModelPath]; if ([NSFileManager.defaultManager fileExistsAtPath:localModelPath]) { // Model is already cached, initialize immediately [self initializeLabelerWithURL:localModelURL]; } else { // Model is not yet available, show loading UI and start download [self showLoadingUI]; FIRStorage *storage = [FIRStorage storage]; FIRStorageReference *modelRef = [storage referenceForURL:@"gs://YOUR_BUCKET/path/to/model.tflite"]; [modelRef writeToFile:localModelURL completion:^(NSURL * _Nullable URL, NSError * _Nullable error) { [self hideLoadingUI]; if (error != nil) { // Handle download error [self showErrorUI]; } else { // Download success, initialize labeler [self initializeLabelerWithURL:URL]; } }]; } - (void)initializeLabelerWithURL:(NSURL *)modelURL { MLKLocalModel *localModel = [[MLKLocalModel alloc] initWithPath:modelURL.path]; MLKCustomImageLabelerOptions *options = [[MLKCustomImageLabelerOptions alloc] initWithLocalModel:localModel]; self.imageLabeler = [MLKImageLabeler imageLabelerWithOptions:options]; // Enable ML-related UI features here [self enableMLFeatures]; }
2. تجهيز الصورة المصدر
أنشئ عنصر 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- تشغيل أداة تصنيف الصور
لتصنيف العناصر في صورة، مرِّر العنصر image إلى طريقة ImageLabelerprocess().
بشكل غير متزامن:
Swift
imageLabeler.process(image) { labels, error in guard error == nil, let labels = labels, !labels.isEmpty else { // Handle the error. return } // Show results. }
Objective-C
[imageLabeler processImage:image completion:^(NSArray*_Nullable labels, NSError *_Nullable error) { if (label.count == 0) { // Handle the error. return; } // Show results. }];
بشكل متزامن:
Swift
var labels: [ImageLabel] do { labels = try imageLabeler.results(in: image) } catch let error { // Handle the error. return } // Show results.
Objective-C
NSError *error; NSArray*labels = [imageLabeler resultsInImage:image error:&error]; // Show results or handle the error.
4. الحصول على معلومات عن الكيانات المصنَّفة
في حال نجاح عملية تصنيف الصور، سيتم عرض مصفوفة منImageLabel. يمثّل كل ImageLabel عنصرًا تم تصنيفه في الصورة. يمكنك الحصول على الوصف النصي لكل تصنيف (إذا كان متاحًا في البيانات الوصفية لملف نموذج LiteRT) ونسبة الثقة والفهرس. على سبيل المثال:
Swift
for label in labels { let labelText = label.text let confidence = label.confidence let index = label.index }
Objective-C
for (MLKImageLabel *label in labels) { NSString *labelText = label.text; float confidence = label.confidence; NSInteger index = label.index; }
نصائح لتحسين الأداء في الوقت الفعلي
إذا كنت تريد تصنيف الصور في تطبيق يعمل في الوقت الفعلي، اتّبِع الإرشادات التالية للحصول على أفضل معدلات عرض اللقطات في الثانية:
- لمعالجة لقطات الفيديو، استخدِم واجهة برمجة التطبيقات المتزامنة
results(in:)الخاصة بأداة الرصد. استدعِ هذه الطريقة من الدالةAVCaptureVideoDataOutputSampleBufferDelegatecaptureOutput(_, didOutput:from:)للحصول بشكل متزامن على نتائج من إطار الفيديو المحدّد. احتفِظAVCaptureVideoDataOutputalwaysDiscardsLateVideoFramesبالقيمةtrueللحدّ من عدد المكالمات التي يتم إجراؤها إلى أداة الرصد. إذا توفّر إطار فيديو جديد أثناء تشغيل أداة الرصد، سيتم تجاهله. - إذا كنت تستخدم ناتج أداة رصد لتراكب الرسومات على صورة الإدخال، احصل أولاً على النتيجة من حزمة تعلّم الآلة، ثم اعرض الصورة والتراكب في خطوة واحدة. وبذلك، لن يتم العرض على سطح الشاشة إلا مرة واحدة لكل إطار إدخال تمت معالجته. راجِع updatePreviewOverlayViewWithLastFrame في نموذج التشغيل السريع الخاص بـ حزمة تعلّم الآلة للحصول على مثال.