כשמעבירים תמונה ללמידת מכונה, המערכת מזהה עד חמישה אובייקטים בתמונה, לצד המיקום של כל אובייקט בתמונה. כשמזהים אובייקטים בסטרימינג של וידאו, לכל אובייקט יש מזהה ייחודי שאפשר להשתמש בו כדי לעקוב אחרי האובייקט בין פריים.
אפשר להשתמש במודל לסיווג תמונות בהתאמה אישית כדי לסווג את האובייקטים שזוהו. תוכלו להיעזר במודלים המותאמים אישית באמצעות ערכת ה-ML כדי להבין מהן דרישות התאימות של המודלים, איפה אפשר למצוא מודלים שאומנו מראש ואיך לאמן את המודלים שלכם.
יש שתי דרכים לשלב מודל מותאם אישית. ניתן לקבץ את המודל על ידי שמירתו בתיקיית הנכסים של האפליקציה, או באמצעות האפשרות להוריד אותו באופן דינמי מ-Firebase. הטבלה הבאה משווה בין שתי האפשרויות.
מודל משולב | מודל מתארח |
---|---|
המודל הוא חלק מהקובץ .ipa של האפליקציה שלך, והגודל שלה גדל. |
המודל אינו חלק מהקובץ .ipa של האפליקציה שלך. האירוח
מתבצע על ידי העלאה אל
למידת המכונה של Firebase. |
הדגם יהיה זמין באופן מיידי, גם אם מכשיר ה-Android לא מחובר לאינטרנט | המערכת מורידה את המודל על פי דרישה |
אין צורך בפרויקט Firebase | נדרש פרויקט Firebase |
צריך לפרסם את האפליקציה מחדש כדי לעדכן את המודל | דחיפת עדכונים של המודל בלי לפרסם מחדש את האפליקציה |
אין בדיקת A/B מובנית | בדיקת A/B קלה בעזרת הגדרת תצורה מרחוק ב-Firebase |
רוצה לנסות?
- כדי לראות דוגמה לשימוש במודל המתארח, יש לעיין באפליקציה למתחילים של הדמיה ובאפליקציה 'הפעלה אוטומטית'.
- כדי לבצע הטמעה מקצה לקצה של ה-API הזה, אפשר להיעזר באפליקציה של Material Design.
לפני שמתחילים
בספריות Podfile ייכללו הספריות של ערכת ML:
כדי לקבץ מודל עם האפליקציה:
pod 'GoogleMLKit/ObjectDetectionCustom', '3.2.0'
כדי להוריד מודל באופן דינמי מ-Firebase, צריך להוסיף את התלות של
LinkFirebase
:pod 'GoogleMLKit/ObjectDetectionCustom', '3.2.0' pod 'GoogleMLKit/LinkFirebase', '3.2.0'
אחרי ההתקנה או העדכון של ה-Pods של הפרויקט, פותחים את פרויקט Xcode באמצעות
.xcworkspace
שלו. קיימת תמיכה ב-ML Kit בגרסה Xcode 13.2.1 ואילך.אם אתם רוצים להוריד מודל, הקפידו להוסיף את Firebase לפרויקט ב-iOS אם עדיין לא עשיתם זאת. אין צורך לעשות את זה בחבילה.
1. טעינת המודל
הגדרת מקור של מודל מקומי
כדי ליצור חבילה של המודל עם האפליקציה:
מעתיקים את קובץ המודל (בדרך כלל באמצעות
.tflite
או.lite
) לפרויקט Xcode ומקפידים לבחור באפשרותCopy bundle resources
כשעושים זאת. קובץ המודל ייכלל בקובץ App Bundle ויהיה זמין לערכת ה-ML.יוצרים אובייקט
LocalModel
, מציינים את הנתיב אל קובץ המודל:Swift
let localModel = LocalModel(path: localModelFilePath)
Objective-C
MLKLocalModel *localModel = [[MLKLocalModel alloc] initWithPath:localModelFilePath];
הגדרת מקור של מודל שמתארח ב-Firebase
כדי להשתמש במודל שמתארח מרחוק, צריך ליצור אובייקט CustomRemoteModel
ולציין את השם שהקציתם לו כשפרסמתם אותו:
Swift
let firebaseModelSource = FirebaseModelSource( name: "your_remote_model") // The name you assigned in // the Firebase console. let remoteModel = CustomRemoteModel(remoteModelSource: firebaseModelSource)
Objective-C
MLKFirebaseModelSource *firebaseModelSource = [[MLKFirebaseModelSource alloc] initWithName:@"your_remote_model"]; // The name you assigned in // the Firebase console. MLKCustomRemoteModel *remoteModel = [[MLKCustomRemoteModel alloc] initWithRemoteModelSource:firebaseModelSource];
לאחר מכן מתחילים במשימה של הורדת המודל ומציינים את התנאים שבהם רוצים לאפשר את ההורדה. אם המודל לא נמצא במכשיר או אם יש גרסה חדשה יותר של המודל, המשימה תוריד באופן אסינכרוני את המודל מ-Firebase:
Swift
let downloadConditions = ModelDownloadConditions( allowsCellularAccess: true, allowsBackgroundDownloading: true ) let downloadProgress = ModelManager.modelManager().download( remoteModel, conditions: downloadConditions )
Objective-C
MLKModelDownloadConditions *downloadConditions = [[MLKModelDownloadConditions alloc] initWithAllowsCellularAccess:YES allowsBackgroundDownloading:YES]; NSProgress *downloadProgress = [[MLKModelManager modelManager] downloadModel:remoteModel conditions:downloadConditions];
הרבה אפליקציות מתחילות את משימת ההורדה בקוד האתחול, אבל אפשר לעשות זאת בכל שלב לפני שמשתמשים במודל.
2. הגדרה של מזהה האובייקט
אחרי שמגדירים את מקורות המודלים, מגדירים את מזהה האובייקט לתרחיש לדוגמה באמצעות אובייקט CustomObjectDetectorOptions
. תוכלו לשנות את ההגדרות הבאות:
הגדרות של מזהה אובייקטים | |
---|---|
מצב זיהוי |
STREAM_MODE (ברירת מחדל) | SINGLE_IMAGE_MODE
ב- ב- |
זיהוי ומעקב אחר אובייקטים מרובים |
false (ברירת מחדל) | true
אם לזהות ולעקוב אחר עד חמישה אובייקטים או רק את האובייקט הבולט ביותר (ברירת מחדל). |
סיווג אובייקטים |
false (ברירת מחדל) | true
האם לסווג את האובייקטים שזוהו באמצעות מודל המסווג
המותאם אישית שסופק. כדי להשתמש במודל הסיווג
המותאם אישית, עליך להגדיר אותו כ- |
סף מהימנות לסיווג |
ציון מהימנות מינימלי של תוויות שזוהו. אם המדיניות לא מוגדרת, ייעשה שימוש בכל סף סיווג שצוין על ידי מטא נתונים של המודל. אם המודל לא מכיל מטא-נתונים או שהמטא-נתונים לא מציינים סף מסווג, ייעשה שימוש בסף ברירת מחדל של 0.0. |
תוויות מקסימליות לכל אובייקט |
המספר המקסימלי של תוויות לכל אובייקט שהמוחזר יחזיר. אם המדיניות לא מוגדרת, ייעשה שימוש בערך 10 כברירת מחדל. |
אם יש לכם רק מודל בחבילה מקומית, פשוט צרו מזהה אובייקט מאובייקט LocalModel
:
Swift
let options = CustomObjectDetectorOptions(localModel: localModel) options.detectorMode = .singleImage options.shouldEnableClassification = true options.shouldEnableMultipleObjects = true options.classificationConfidenceThreshold = NSNumber(value: 0.5) options.maxPerObjectLabelCount = 3
Objective-C
MLKCustomObjectDetectorOptions *options = [[MLKCustomObjectDetectorOptions alloc] initWithLocalModel:localModel]; options.detectorMode = MLKObjectDetectorModeSingleImage; options.shouldEnableClassification = YES; options.shouldEnableMultipleObjects = YES; options.classificationConfidenceThreshold = @(0.5); options.maxPerObjectLabelCount = 3;
אם יש לכם מודל שמתארח מרחוק, תצטרכו לבדוק שהוא הורד לפני הפעלתו. ניתן לבדוק את הסטטוס של משימת ההורדה של המודל באמצעות השיטה isModelDownloaded(remoteModel:)
של מנהל המודל.
אמנם צריך לאשר זאת רק לפני שמפעילים את מזהה האובייקט, אבל אם יש לכם גם מודל שהתארח מרחוק וגם מודל שנארז באופן מקומי, כדאי לבצע את הבדיקה הזו כשאתם יוצרים את ה-ObjectDetector
: עליכם ליצור מזהה מהמודל המרוחק אם הוא הורד, וגם מהמודל המקומי.
Swift
var options: CustomObjectDetectorOptions! if (ModelManager.modelManager().isModelDownloaded(remoteModel)) { options = CustomObjectDetectorOptions(remoteModel: remoteModel) } else { options = CustomObjectDetectorOptions(localModel: localModel) } options.detectorMode = .singleImage options.shouldEnableClassification = true options.shouldEnableMultipleObjects = true options.classificationConfidenceThreshold = NSNumber(value: 0.5) options.maxPerObjectLabelCount = 3
Objective-C
MLKCustomObjectDetectorOptions *options; if ([[MLKModelManager modelManager] isModelDownloaded:remoteModel]) { options = [[MLKCustomObjectDetectorOptions alloc] initWithRemoteModel:remoteModel]; } else { options = [[MLKCustomObjectDetectorOptions alloc] initWithLocalModel:localModel]; } options.detectorMode = MLKObjectDetectorModeSingleImage; options.shouldEnableClassification = YES; options.shouldEnableMultipleObjects = YES; options.classificationConfidenceThreshold = @(0.5); options.maxPerObjectLabelCount = 3;
אם יש לכם רק מודל המארח מרחוק, עליכם להשבית פונקציונליות שקשורה למודלים – לדוגמה, להציג באפור או להסתיר חלק מממשק המשתמש – עד לאישור הורדת המודל.
כדי לקבל את הסטטוס של הורדת המודלים, אתם יכולים לצרף צופים למרכז ההתראות שמוגדר כברירת מחדל. הקפידו להשתמש בהפניה חלשה ל-self
בבלוק של כלי הצפייה, כי ההורדה עשויה להימשך זמן מה ותוכלו לשחרר את האובייקט המקורי עד כשההורדה תסתיים. למשל:
Swift
NotificationCenter.default.addObserver( forName: .mlkitModelDownloadDidSucceed, object: nil, queue: nil ) { [weak self] notification in guard let strongSelf = self, let userInfo = notification.userInfo, let model = userInfo[ModelDownloadUserInfoKey.remoteModel.rawValue] as? RemoteModel, model.name == "your_remote_model" else { return } // The model was downloaded and is available on the device } NotificationCenter.default.addObserver( forName: .mlkitModelDownloadDidFail, object: nil, queue: nil ) { [weak self] notification in guard let strongSelf = self, let userInfo = notification.userInfo, let model = userInfo[ModelDownloadUserInfoKey.remoteModel.rawValue] as? RemoteModel else { return } let error = userInfo[ModelDownloadUserInfoKey.error.rawValue] // ... }
Objective-C
__weak typeof(self) weakSelf = self; [NSNotificationCenter.defaultCenter addObserverForName:MLKModelDownloadDidSucceedNotification object:nil queue:nil usingBlock:^(NSNotification *_Nonnull note) { if (weakSelf == nil | note.userInfo == nil) { return; } __strong typeof(self) strongSelf = weakSelf; MLKRemoteModel *model = note.userInfo[MLKModelDownloadUserInfoKeyRemoteModel]; if ([model.name isEqualToString:@"your_remote_model"]) { // The model was downloaded and is available on the device } }]; [NSNotificationCenter.defaultCenter addObserverForName:MLKModelDownloadDidFailNotification object:nil queue:nil usingBlock:^(NSNotification *_Nonnull note) { if (weakSelf == nil | note.userInfo == nil) { return; } __strong typeof(self) strongSelf = weakSelf; NSError *error = note.userInfo[MLKModelDownloadUserInfoKeyError]; }];
ה-API לזיהוי ולמעקב אחר אובייקטים מותאם לשני התרחישים העיקריים הבאים:
- זיהוי חי ומעקב של האובייקט הבולט ביותר בעינית המצלמה.
- זיהוי של אובייקטים מרובים מתמונה סטטית.
כדי להגדיר את ה-API לתרחישים הבאים:
Swift
// Live detection and tracking let options = CustomObjectDetectorOptions(localModel: localModel) options.shouldEnableClassification = true options.maxPerObjectLabelCount = 3 // Multiple object detection in static images let options = CustomObjectDetectorOptions(localModel: localModel) options.detectorMode = .singleImage options.shouldEnableMultipleObjects = true options.shouldEnableClassification = true options.maxPerObjectLabelCount = 3
Objective-C
// Live detection and tracking MLKCustomObjectDetectorOptions *options = [[MLKCustomObjectDetectorOptions alloc] initWithLocalModel:localModel]; options.shouldEnableClassification = YES; options.maxPerObjectLabelCount = 3; // Multiple object detection in static images MLKCustomObjectDetectorOptions *options = [[MLKCustomObjectDetectorOptions alloc] initWithLocalModel:localModel]; options.detectorMode = MLKObjectDetectorModeSingleImage; options.shouldEnableMultipleObjects = YES; options.shouldEnableClassification = YES; options.maxPerObjectLabelCount = 3;
3. מכינים את תמונת הקלט
יוצרים אובייקט 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];
4. יצירה והפעלה של מזהה האובייקט
יצירת מזהה אובייקט חדש:
Swift
let objectDetector = ObjectDetector.objectDetector(options: options)
Objective-C
MLKObjectDetector *objectDetector = [MLKObjectDetector objectDetectorWithOptions:options];
לאחר מכן, השתמשו במזהה:
באופן אסינכרוני:
Swift
objectDetector.process(image) { objects, error in guard error == nil, let objects = objects, !objects.isEmpty else { // Handle the error. return } // Show results. }
Objective-C
[objectDetector processImage:image completion:^(NSArray
*_Nullable objects, NSError *_Nullable error) { if (objects.count == 0) { // Handle the error. return; } // Show results. }]; באופן סינכרוני:
Swift
var objects: [Object] do { objects = try objectDetector.results(in: image) } catch let error { // Handle the error. return } // Show results.
Objective-C
NSError *error; NSArray
*objects = [objectDetector resultsInImage:image error:&error]; // Show results or handle the error.
5. קבלת מידע על אובייקטים מתויגים
אם הקריאה למעבד התמונות מצליחה, היא מעבירה רשימה של Object
s ל-handler של ההשלמה או מחזירה את הרשימה, בהתאם לקריאה לשיטה האסינכרונית או הסינכרונית.
כל Object
מכיל את המאפיינים הבאים:
frame |
CGRect שמציין את מיקום האובייקט בתמונה. |
||||||
trackingID |
מספר שלם שמזהה את האובייקט בתמונות, או 'nil' ב-SINGLE_IMAGE_MODE. | ||||||
labels |
|
Swift
// objects contains one item if multiple object detection wasn't enabled. for object in objects { let frame = object.frame let trackingID = object.trackingID let description = object.labels.enumerated().map { (index, label) in "Label \(index): \(label.text), \(label.confidence), \(label.index)" }.joined(separator: "\n") }
Objective-C
// The list of detected objects contains one item if multiple object detection // wasn't enabled. for (MLKObject *object in objects) { CGRect frame = object.frame; NSNumber *trackingID = object.trackingID; for (MLKObjectLabel *label in object.labels) { NSString *labelString = [NSString stringWithFormat:@"%@, %f, %lu", label.text, label.confidence, (unsigned long)label.index]; } }
הבטחת חוויית משתמש מעולה
כדי ליהנות מחוויית המשתמש הטובה ביותר, מומלץ לפעול לפי ההנחיות הבאות באפליקציה:
- זיהוי אובייקט מוצלח תלוי במורכבות החזותית של האובייקט. כדי שאובייקטים יזוהו, ייתכן שאובייקטים עם מספר קטן של תכונות ויזואליות יתפסו חלק גדול יותר מהתמונה. עליכם לספק למשתמשים הנחיות לצילום הקלט שמתאים היטב לסוג האובייקטים שרוצים לזהות.
- במהלך השימוש בסיווג, אם אתם רוצים לזהות אובייקטים שלא שייכים בקלות לקטגוריות הנתמכות, כדאי להשתמש בטיפול מיוחד באובייקטים לא ידועים.
כדאי גם לבדוק את האפליקציה [ML Kit Material Design][showcase-link]{: .external } ואת האוסף תבניות לפיצ'רים של למידת מכונה.
Improving performance
אם אתם רוצים להשתמש בזיהוי אובייקטים באפליקציה בזמן אמת, עליכם לפעול לפי ההנחיות הבאות כדי ליצור את מסגרות הפריימים הטובות ביותר:אם אתם משתמשים במצב סטרימינג באפליקציה בזמן אמת, אל תשתמשו בכמה זיהויי אובייקטים, כי רוב המכשירים לא יוכלו ליצור קצבי פריימים מתאימים.
- לעיבוד מסגרות וידאו, יש להשתמש ב-
results(in:)
ב-API הסינכרוני של המזהה. ניתן לקרוא לשיטה הזו באמצעות הפונקציהAVCaptureVideoDataOutputSampleBufferDelegate
captureOutput(_, didOutput:from:)
כדי לקבל תוצאות סינכרוניות מהפריים של הווידאו. צריך להשאיר את ה-alwaysDiscardsLateVideoFrames
שלAVCaptureVideoDataOutput
בתורtrue
כדי לווסת את השיחות. אם יהפוך לפריים חדש של סרטון בזמן שהמזהה פועל, הוא יוסר. - אם משתמשים בפלט של המזהה כשכבת-על של גרפיקה בתמונת הקלט, קודם צריך לקבל את התוצאה מ-ML Kit, ואז לעבד את התמונה ואת שכבת-העל בפעולה אחת. אם עושים זאת, מתבצע רינדור של התצוגה למשטח התצוגה רק פעם אחת בכל מסגרת קלט שעברה עיבוד. כדי לקבל דוגמה, אפשר לעיין בupdatePreviewLayerViewWithLastFrame שבדוגמה למתחילים של ML.