אתם יכולים להשתמש ב-ML Kit כדי לזהות אובייקטים ולעקוב אחריהם בפריימים של סרטון.
כשמעבירים תמונות ל-ML Kit, המערכת מחזירה לכל תמונה רשימה של עד חמישה אובייקטים שזוהו ואת המיקום שלהם בתמונה. בזמן הזיהוי לאובייקטים של וידאו בסטרימינג, לכל אובייקט יש מזהה שאפשר להשתמש בו כדי לעקוב את האובייקט בין התמונות. אפשר גם להפעיל אובייקט גס סיווג, שמוסיף תוויות לאובייקטים עם תיאורים רחבים של קטגוריות.
לפני שמתחילים
- אם עדיין לא הוספתם את Firebase לאפליקציה, תוכלו לפעול לפי השלבים שמפורטים במדריך לתחילת העבודה.
- כוללים את ספריות ML Kit ב-Podfile:
pod 'Firebase/MLVision', '6.25.0' pod 'Firebase/MLVisionObjectDetection', '6.25.0'
אחרי שמתקינים או מעדכנים את קבוצות ה-Pod של הפרויקט, חשוב לפתוח את ה-Xcode באמצעות.xcworkspace
של הפרויקט שלו. - מייבאים את Firebase לאפליקציה:
Swift
import Firebase
Objective-C
@import Firebase;
1. הגדרת הכלי לזיהוי אובייקטים
כדי להתחיל לזהות אובייקטים ולעקוב אחריהם, קודם צריך ליצור מופע של VisionObjectDetector
, ולציין אם רוצים לשנות את הגדרות הגלאי מברירת המחדל.
מגדירים את ה-Object Detector לתרחיש לדוגמה באמצעות אובייקט
VisionObjectDetectorOptions
. אפשר לשנות את ההגדרות הבאות:הגדרות של גלאי אובייקטים מצב זיהוי .stream
(ברירת מחדל) |.singleImage
במצב סטרימינג (ברירת המחדל), זמן האחזור של זיהוי העצמים הוא קצר מאוד, אבל יכול להיות שהתוצאות יהיו חלקיות (למשל, תיבות מלבניות או קטגוריה לא מצוינות) בהפעלות הראשונות של הגלאי. בנוסף, במצב סטרימינג, הגלאי מקצה מזהי מעקב לאובייקטים, שאפשר להשתמש בהם כדי לעקוב אחר אובייקטים בפריימים שונים. כדאי להשתמש במצב הזה כשרוצים לעקוב אחרי אובייקטים, או כשזמן האחזור קצר חשוב מאוד, למשל כשמעבדים זרמי וידאו בזמן האימון.
במצב של תמונה אחת, גלאי האובייקטים מחכה עד שתינתן לו אפשרות להציג את התוצאה, אחרי שהוא מקבל את תיבת הגבול של האובייקט שזוהה (ואת הקטגוריה שלו, אם הפעלתם סיווג). כתוצאה מכך, זמן האחזור לזיהוי עלול להיות ארוך יותר. בנוסף, במצב של תמונה יחידה לא מוקצים מזהי מעקב. מומלץ להשתמש במצב הזה אם זמן האחזור לא קריטי ואתם לא רוצים להתמודד עם תוצאות חלקיות.
זיהוי של כמה אובייקטים ומעקב אחריהם false
(ברירת מחדל) |true
האם לזהות ולעקוב אחרי עד חמישה אובייקטים או רק אחרי האובייקט הבולט ביותר (ברירת המחדל).
סיווג אובייקטים false
(ברירת מחדל) |true
האם לסווג אובייקטים שזוהו לקטגוריות רחבות או לא. כשההגדרה מופעלת, מזהה האובייקטים מסווג את האובייקטים הקטגוריות הבאות: מוצרי אופנה, אוכל, מוצרים לבית, מקומות, צמחים ופרטים לא ידועים.
ממשק ה-API לזיהוי אובייקטים ולמעקב אחריהם מותאם לשני התרחישים הבאים:
- זיהוי ומעקב בזמן אמת של האובייקט הבולט ביותר בחלון הראייה של המצלמה
- זיהוי של מספר אובייקטים בתמונה סטטית
כדי להגדיר את ה-API לתרחישים לדוגמה האלה:
Swift
// Live detection and tracking let options = VisionObjectDetectorOptions() options.detectorMode = .stream options.shouldEnableMultipleObjects = false options.shouldEnableClassification = true // Optional // Multiple object detection in static images let options = VisionObjectDetectorOptions() options.detectorMode = .singleImage options.shouldEnableMultipleObjects = true options.shouldEnableClassification = true // Optional
Objective-C
// Live detection and tracking FIRVisionObjectDetectorOptions *options = [[FIRVisionObjectDetectorOptions alloc] init]; options.detectorMode = FIRVisionObjectDetectorModeStream; options.shouldEnableMultipleObjects = NO; options.shouldEnableClassification = YES; // Optional // Multiple object detection in static images FIRVisionObjectDetectorOptions *options = [[FIRVisionObjectDetectorOptions alloc] init]; options.detectorMode = FIRVisionObjectDetectorModeSingleImage; options.shouldEnableMultipleObjects = YES; options.shouldEnableClassification = YES; // Optional
אחזור מופע של
FirebaseVisionObjectDetector
:Swift
let objectDetector = Vision.vision().objectDetector() // Or, to change the default settings: let objectDetector = Vision.vision().objectDetector(options: options)
Objective-C
FIRVisionObjectDetector *objectDetector = [[FIRVision vision] objectDetector]; // Or, to change the default settings: FIRVisionObjectDetector *objectDetector = [[FIRVision vision] objectDetectorWithOptions:options];
2. הפעלת מזהה האובייקטים
כדי לזהות אובייקטים ולעקוב אחריהם, מבצעים את הפעולות הבאות בכל תמונה או פריים בסרטון.
אם הפעלתם את מצב הסטרימינג, עליכם ליצור אובייקטים מסוג VisionImage
מ-CMSampleBufferRef
.
יצירת אובייקט
VisionImage
באמצעותUIImage
אוCMSampleBufferRef
כדי להשתמש ב-
UIImage
:- במקרה הצורך, מסובבים את התמונה כך ש-
imageOrientation
הוא.up
. - יצירת אובייקט
VisionImage
באמצעות סיבוב נכוןUIImage
. אל תציינו מטא-נתונים של סבב, ברירת המחדל יש להשתמש בערך.topLeft
.Swift
let image = VisionImage(image: uiImage)
Objective-C
FIRVisionImage *image = [[FIRVisionImage alloc] initWithImage:uiImage];
כדי להשתמש ב-
CMSampleBufferRef
:-
יוצרים אובייקט
VisionImageMetadata
שמציין את הכיוון של נתוני התמונה שמכיל מאגר ה-CMSampleBufferRef
.כדי לקבל את כיוון התמונה:
Swift
func imageOrientation( deviceOrientation: UIDeviceOrientation, cameraPosition: AVCaptureDevice.Position ) -> VisionDetectorImageOrientation { switch deviceOrientation { case .portrait: return cameraPosition == .front ? .leftTop : .rightTop case .landscapeLeft: return cameraPosition == .front ? .bottomLeft : .topLeft case .portraitUpsideDown: return cameraPosition == .front ? .rightBottom : .leftBottom case .landscapeRight: return cameraPosition == .front ? .topRight : .bottomRight case .faceDown, .faceUp, .unknown: return .leftTop } }
Objective-C
- (FIRVisionDetectorImageOrientation) imageOrientationFromDeviceOrientation:(UIDeviceOrientation)deviceOrientation cameraPosition:(AVCaptureDevicePosition)cameraPosition { switch (deviceOrientation) { case UIDeviceOrientationPortrait: if (cameraPosition == AVCaptureDevicePositionFront) { return FIRVisionDetectorImageOrientationLeftTop; } else { return FIRVisionDetectorImageOrientationRightTop; } case UIDeviceOrientationLandscapeLeft: if (cameraPosition == AVCaptureDevicePositionFront) { return FIRVisionDetectorImageOrientationBottomLeft; } else { return FIRVisionDetectorImageOrientationTopLeft; } case UIDeviceOrientationPortraitUpsideDown: if (cameraPosition == AVCaptureDevicePositionFront) { return FIRVisionDetectorImageOrientationRightBottom; } else { return FIRVisionDetectorImageOrientationLeftBottom; } case UIDeviceOrientationLandscapeRight: if (cameraPosition == AVCaptureDevicePositionFront) { return FIRVisionDetectorImageOrientationTopRight; } else { return FIRVisionDetectorImageOrientationBottomRight; } default: return FIRVisionDetectorImageOrientationTopLeft; } }
לאחר מכן, יוצרים את אובייקט המטא-נתונים:
Swift
let cameraPosition = AVCaptureDevice.Position.back // Set to the capture device you used. let metadata = VisionImageMetadata() metadata.orientation = imageOrientation( deviceOrientation: UIDevice.current.orientation, cameraPosition: cameraPosition )
Objective-C
FIRVisionImageMetadata *metadata = [[FIRVisionImageMetadata alloc] init]; AVCaptureDevicePosition cameraPosition = AVCaptureDevicePositionBack; // Set to the capture device you used. metadata.orientation = [self imageOrientationFromDeviceOrientation:UIDevice.currentDevice.orientation cameraPosition:cameraPosition];
- יוצרים אובייקט
VisionImage
באמצעות אובייקטCMSampleBufferRef
והמטא-נתונים של הסבב:Swift
let image = VisionImage(buffer: sampleBuffer) image.metadata = metadata
Objective-C
FIRVisionImage *image = [[FIRVisionImage alloc] initWithBuffer:sampleBuffer]; image.metadata = metadata;
- במקרה הצורך, מסובבים את התמונה כך ש-
מעבירים את
VisionImage
לאחד מהשיטות של עיבוד התמונה של גלאי האובייקטים. אפשר להשתמש בשיטהprocess(image:)
האסינכרונית או ב- שיטתresults()
סינכרונית.כדי לזהות אובייקטים באופן אסינכרוני:
Swift
objectDetector.process(image) { detectedObjects, error in guard error == nil else { // Error. return } guard let detectedObjects = detectedObjects, !detectedObjects.isEmpty else { // No objects detected. return } // Success. Get object info here. // ... }
Objective-C
[objectDetector processImage:image completion:^(NSArray<FIRVisionObject *> * _Nullable objects, NSError * _Nullable error) { if (error == nil) { return; } if (objects == nil | objects.count == 0) { // No objects detected. return; } // Success. Get object info here. // ... }];
כדי לזהות אובייקטים באופן סינכרוני:
Swift
var results: [VisionObject]? = nil do { results = try objectDetector.results(in: image) } catch let error { print("Failed to detect object with error: \(error.localizedDescription).") return } guard let detectedObjects = results, !detectedObjects.isEmpty else { print("Object detector returned no results.") return } // ...
Objective-C
NSError *error; NSArray<FIRVisionObject *> *objects = [objectDetector resultsInImage:image error:&error]; if (error == nil) { return; } if (objects == nil | objects.count == 0) { // No objects detected. return; } // Success. Get object info here. // ...
אם הקריאה למעבד התמונות מצליחה, היא מעבירה רשימה של
VisionObject
לטיפול בהשלמה או מחזירה את הרשימה, בהתאם לקריאה לשיטה האסינכרונית או לקריאה לשיטה הסינכרונית.כל
VisionObject
מכיל את המאפיינים (properties) הבאים:frame
CGRect
שמציין את המיקום של האובייקט בתמונה.trackingID
מספר שלם שמזהה את האובייקט בתמונות. ערך אפס במצב תמונה יחידה. classificationCategory
הקטגוריה המשוערת של האובייקט. אם הסיווג לא מופעל בגלאי האובייקטים, הערך הוא תמיד .unknown
.confidence
ערך הסמך של סיווג האובייקט. אם הסיווג לא מופעל בזיהוי האובייקטים, או שהאובייקט מסווג כ'לא ידוע', הערך הוא nil
.Swift
// detectedObjects contains one item if multiple object detection wasn't enabled. for obj in detectedObjects { let bounds = obj.frame let id = obj.trackingID // If classification was enabled: let category = obj.classificationCategory let confidence = obj.confidence }
Objective-C
// The list of detected objects contains one item if multiple // object detection wasn't enabled. for (FIRVisionObject *obj in objects) { CGRect bounds = obj.frame; if (obj.trackingID) { NSInteger id = obj.trackingID.integerValue; } // If classification was enabled: FIRVisionObjectCategory category = obj.classificationCategory; float confidence = obj.confidence.floatValue; }
שיפור השימושיות והביצועים
כדי ליהנות מחוויית המשתמש הטובה ביותר, מומלץ לפעול לפי ההנחיות הבאות באפליקציה:
- ההצלחה של זיהוי אובייקטים תלויה במורכבות הוויזואלית של האובייקט. חפצים עם מספר קטן של תכונות חזותיות עשויה לתפוס חלק גדול יותר את התמונה שצריך לזהות. כדאי לספק למשתמשים הנחיות לצילום קלט שמתאים לסוג האובייקטים שאתם רוצים לזהות.
- כשמשתמשים בסיווג, אם רוצים לזהות אובייקטים שלא נכללים בקטגוריות הנתמכות, צריך להטמיע טיפול מיוחד לאובייקטים לא מוכרים.
בנוסף, כדאי לעיין [ML Kit Material Design Showcase][showcase-link]{: .external } וגם עיצוב חומר אוסף תבניות לתכונות מבוססות-למידת מכונה.
כשמשתמשים במצב סטרימינג באפליקציה בזמן אמת, מומלץ לפעול לפי ההנחיות הבאות כדי להגיע לשיעורי הפריימים הטובים ביותר:
אין להשתמש בזיהוי אובייקטים מרובים במצב סטרימינג, כי רוב המכשירים לא מסוגל להפיק קצבי פריימים מתאימים.
אפשר להשבית את הסיווג אם לא צריך אותו.
- צמצום מספר הקריאות למזהה. אם מסגרת וידאו חדשה זמינה בזמן שהגלאי פועל, צריך להסיר את המסגרת.
- אם אתם משתמשים בפלט של הגלאי כדי להוסיף שכבת-על של גרפיקה לתמונה הקלט, קודם צריך לקבל את התוצאה מ-ML Kit, ואז לבצע עיבוד (רנדור) של התמונה ושל שכבת-העל בשלב אחד. כך תוכלו להציג את משטח המסך פעם אחת בלבד לכל מסגרת קלט. אפשר לעיין ב-previewOverlayView ו-FIRDetectionOverlayView באפליקציה לדוגמה של Showcase.