אחרי שמאמנים מודל משלכם באמצעות AutoML Vision Edge, אפשר להשתמש בו באפליקציה כדי לתייג תמונות.
יש שתי דרכים לשלב מודלים שאומנו באמצעות AutoML Vision Edge. אפשר לארוז את המודל על ידי העתקת הקבצים של המודל לפרויקט Xcode, או להוריד אותו באופן דינמי מ-Firebase.
אפשרויות של חבילות מודלים | |
---|---|
כלול באפליקציה |
|
באירוח של Firebase |
|
לפני שמתחילים
מוסיפים את ספריות ML Kit ל-Podfile:
לצירוף מודל לאפליקציה:
pod 'GoogleMLKit/ImageLabelingCustom'
כדי להוריד באופן דינמי מודל מ-Firebase, מוסיפים את
LinkFirebase
התלות:pod 'GoogleMLKit/ImageLabelingCustom' pod 'GoogleMLKit/LinkFirebase'
אחרי שמתקינים או מעדכנים את ה-Pods של הפרויקט, פותחים את פרויקט Xcode באמצעות
.xcworkspace
. ML Kit נתמך ב-Xcode בגרסה 12.2 ומעלה.אם רוצים להוריד מודל, צריך לוודא שהוספתם את Firebase לפרויקט Android, אם עדיין לא עשיתם זאת. זה לא נדרש כשמצרפים את המודל לחבילה.
1. טעינת המודל
הגדרת מקור מודל מקומי
כדי לארוז את המודל עם האפליקציה:
מחולצים את המודל ואת המטא-נתונים שלו מארכיון ה-ZIP שהורדתם ממסוף Firebase לתיקייה:
your_model_directory |____dict.txt |____manifest.json |____model.tflite
שלושת הקבצים צריכים להיות באותה תיקייה. מומלץ להשתמש בקבצים כמו שהורדתם אותם, בלי לבצע בהם שינויים (כולל שמות הקבצים).
מעתיקים את התיקייה לפרויקט Xcode, ומוודאים שסימנתם את האפשרות Create folder references. קובץ המודל והמטא-נתונים ייכללו בחבילת האפליקציה ויהיו זמינים ל-ML Kit.
יוצרים אובייקט
LocalModel
ומציינים את הנתיב לקובץ המניפסט של המודל:Swift
guard let manifestPath = Bundle.main.path( forResource: "manifest", ofType: "json", inDirectory: "your_model_directory" ) else { return true } let localModel = LocalModel(manifestPath: manifestPath)
Objective-C
NSString *manifestPath = [NSBundle.mainBundle pathForResource:@"manifest" ofType:@"json" inDirectory:@"your_model_directory"]; MLKLocalModel *localModel = [[MLKLocalModel alloc] initWithManifestPath:manifestPath];
הגדרה של מקור מודל שמתארח ב-Firebase
כדי להשתמש במודל שמתארח מרחוק, יוצרים אובייקט CustomRemoteModel
ומציינים את השם שהקציתם למודל כשפרסמתם אותו:
Swift
// Initialize the model source with the name you assigned in
// the Firebase console.
let remoteModelSource = FirebaseModelSource(name: "your_remote_model")
let remoteModel = CustomRemoteModel(remoteModelSource: remoteModelSource)
Objective-C
// Initialize the model source with the name you assigned in
// the Firebase console.
MLKFirebaseModelSource *firebaseModelSource =
[[MLKFirebaseModelSource alloc] initWithName:@"your_remote_model"];
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] downloadRemoteModel:remoteModel
conditions:downloadConditions];
הרבה אפליקציות מתחילות את משימת ההורדה בקוד האתחול שלהן, אבל אפשר לעשות את זה בכל שלב לפני שצריך להשתמש במודל.
יצירת כלי לתוויות תמונות מהמודל
אחרי שמגדירים את מקורות המודלים, יוצרים אובייקט ImageLabeler
מאחד מהם.
אם יש לכם רק מודל שצורף באופן מקומי, פשוט יוצרים תווית מLocalModel
האובייקט ומגדירים את סף ציון מהימנות שרוצים לדרוש (ראו הערכת המודל):
Swift
let options = CustomImageLabelerOptions(localModel: localModel)
options.confidenceThreshold = NSNumber(value: 0.0) // Evaluate your model in the Cloud console
// to determine an appropriate value.
let imageLabeler = ImageLabeler.imageLabeler(options)
Objective-C
CustomImageLabelerOptions *options =
[[CustomImageLabelerOptions alloc] initWithLocalModel:localModel];
options.confidenceThreshold = @(0.0f); // Evaluate your model in the Cloud console
// to determine an appropriate value.
MLKImageLabeler *imageLabeler =
[MLKImageLabeler imageLabelerWithOptions:options];
אם יש לכם מודל שמתארח מרחוק, תצטרכו לוודא שהוא הורד לפני שתפעילו אותו. אפשר לבדוק את סטטוס ההורדה של המודל באמצעות השיטה isModelDownloaded(remoteModel:)
של הכלי לניהול מודלים.
למרות שצריך לאשר את זה רק לפני שמריצים את הכלי לסימון תוויות, אם יש לכם גם מודל שמתארח מרחוק וגם מודל שצורף באופן מקומי, כדאי לבצע את הבדיקה הזו כשיוצרים מופע של ImageLabeler
: ליצור כלי לסימון תוויות מהמודל המרוחק אם הוא הורד, ומהמודל המקומי אחרת.
Swift
var options: CustomImageLabelerOptions
if (ModelManager.modelManager().isModelDownloaded(remoteModel)) {
options = CustomImageLabelerOptions(remoteModel: remoteModel)
} else {
options = CustomImageLabelerOptions(localModel: localModel)
}
options.confidenceThreshold = NSNumber(value: 0.0) // Evaluate your model in the Firebase console
// to determine an appropriate value.
let imageLabeler = ImageLabeler.imageLabeler(options: options)
Objective-C
MLKCustomImageLabelerOptions *options;
if ([[MLKModelManager modelManager] isModelDownloaded:remoteModel]) {
options = [[MLKCustomImageLabelerOptions alloc] initWithRemoteModel:remoteModel];
} else {
options = [[MLKCustomImageLabelerOptions alloc] initWithLocalModel:localModel];
}
options.confidenceThreshold = @(0.0f); // Evaluate your model in the Firebase console
// to determine an appropriate value.
MLKImageLabeler *imageLabeler =
[MLKImageLabeler imageLabelerWithOptions:options];
אם יש לכם רק מודל שמתארח מרחוק, אתם צריכים להשבית את הפונקציונליות שקשורה למודל – למשל, להאפיר או להסתיר חלק מהממשק – עד שתאשרו שהמודל הורד.
אפשר לקבל את סטטוס ההורדה של המודל על ידי צירוף observers למרכז ההתראות שמוגדר כברירת מחדל. חשוב להשתמש בהפניה חלשה ל-self
בבלוק של האובייקט שצופה בשינויים, כי ההורדות יכולות להימשך זמן מה, והאובייקט המקורי יכול להיות משוחרר עד שההורדה מסתיימת. לדוגמה:
Swift
NotificationCenter.default.addObserver(
forName: .mlkitMLModelDownloadDidSucceed,
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: .mlkitMLModelDownloadDidFail,
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];
}];
2. הכנת תמונת הקלט
יוצרים אובייקט VisionImage
באמצעות UIImage
או CMSampleBufferRef
.
אם אתם משתמשים ב-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;
אם אתם משתמשים ב-CMSampleBufferRef
, פועלים לפי השלבים הבאים:
-
מציינים את האוריינטציה של נתוני התמונה שמופיעים במאגר
CMSampleBufferRef
.כדי לקבל את כיוון התמונה:
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 position == AVCaptureDevicePositionFront ? UIImageOrientationLeftMirrored : UIImageOrientationRight; case UIDeviceOrientationLandscapeLeft: return position == AVCaptureDevicePositionFront ? UIImageOrientationDownMirrored : UIImageOrientationUp; case UIDeviceOrientationPortraitUpsideDown: return position == AVCaptureDevicePositionFront ? UIImageOrientationRightMirrored : UIImageOrientationLeft; case UIDeviceOrientationLandscapeRight: return position == AVCaptureDevicePositionFront ? UIImageOrientationUpMirrored : UIImageOrientationDown; case UIDeviceOrientationUnknown: case UIDeviceOrientationFaceUp: case UIDeviceOrientationFaceDown: return UIImageOrientationUp; } }
- יוצרים אובייקט
VisionImage
באמצעות האובייקטCMSampleBufferRef
והכיוון: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. הפעלת הכלי להוספת תוויות לתמונות
באופן אסינכרוני:
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<MLKImageLabel *> *_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<MLKImageLabel *> *labels =
[imageLabeler resultsInImage:image error:&error];
// Show results or handle the error.
4. קבלת מידע על אובייקטים עם תוויות
אם פעולת התיוג של התמונה מצליחה, היא מחזירה מערך של ImageLabel
. כל ImageLabel
מייצג משהו שסומן בתמונה. אפשר לקבל את תיאור הטקסט של כל תווית (אם הוא זמין במטא-נתונים של קובץ המודל של TensorFlow Lite), את ציון הביטחון ואת האינדקס.
לדוגמה:
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;
}
טיפים לשיפור הביצועים בזמן אמת
אם רוצים לתייג תמונות באפליקציה בזמן אמת, כדאי לפעול לפי ההנחיות הבאות כדי להשיג את קצב הפריימים הטוב ביותר:
- הגבלת מספר השיחות למזהה. אם פריים חדש של סרטון הופך לזמין בזמן שהגלאי פועל, צריך להשליך את הפריים.
- אם אתם משתמשים בפלט של הגלאי כדי להוסיף שכבת גרפיקה על תמונת הקלט, קודם צריך לקבל את התוצאה ואז לעבד את התמונה ולהוסיף את השכבה בשלב אחד. כך, הרינדור מתבצע רק פעם אחת לכל מסגרת קלט. דוגמה אפשר לראות במחלקות previewOverlayView ו-FIRDetectionOverlayView באפליקציית הדוגמה showcase.