באמצעות למידת מכונה, תוכלו לזהות אובייקטים במסגרות וידאו עוקבות ולעקוב אחריהן.
כשמעבירים תמונה לערכת ה-ML, המערכת מזהה עד חמישה אובייקטים בתמונה יחד עם המיקום של כל אובייקט בתמונה. כשמזהים אובייקטים בסטרימינג של וידאו, לכל אובייקט יש מזהה ייחודי שבו אפשר להשתמש כדי לעקוב אחרי האובייקט בין פריים. בנוסף, אפשר להפעיל סיווג של אובייקט גס, שמתייג אובייקטים בתיאורי קטגוריות רחבים.
רוצה לנסות?
- כדאי לשחק עם האפליקציה לדוגמה כדי לראות שימוש לדוגמה ב-API הזה.
- כדי לבצע הטמעה מקצה לקצה של ה-API הזה, אפשר להיעזר באפליקציה של Material Design.
לפני שמתחילים
- יש לכלול את ה-pods הבאים ב-ML Kit ב-Podfile:
pod 'GoogleMLKit/ObjectDetection', '3.2.0'
- אחרי ההתקנה או העדכון של ה-Pods של הפרויקט, פותחים את פרויקט Xcode באמצעות
.xcworkspace
שלו. ערכת ה-ML נתמכת ב-Xcode מגרסה 12.4 ואילך.
1. הגדרה של מזהה האובייקט
כדי לזהות אובייקטים ולעקוב אחריהם, קודם צריך ליצור מכונה של ObjectDetector
עם זאת, ולבחור אם להשתמש בהגדרות של מזהה ברירת המחדל כברירת מחדל.
מגדירים את מזהה האובייקט בתרחיש לדוגמה באמצעות אובייקט
ObjectDetectorOptions
. תוכלו לשנות את ההגדרות הבאות:הגדרות של מזהה אובייקטים מצב זיהוי .stream
(ברירת מחדל) |.singleImage
במצב הסטרימינג (ברירת המחדל), מזהה האובייקט פועל עם זמן אחזור נמוך מאוד, אבל יכול להיות שיתקבלו תוצאות חלקיות (כמו קטגוריות או תחומים שאינם מוגדרים) בהפעלה הראשונה של המזהה. בנוסף, במצב שידור, המזהה מקצה מזהים לצורכי מעקב לאובייקטים, שאפשר להשתמש בהם כדי לעקוב אחר אובייקטים במסגרות. כדאי להשתמש במצב הזה כשרוצים לעקוב אחר אובייקטים, או כשיש חשיבות לזמן אחזור קצר, כמו בעיבוד זרמי סרטונים בזמן אמת.
במצב של תמונה יחידה, מזהה האובייקט מחזיר את התוצאה אחרי שתיבת התיקוף של האובייקט נקבעת. אם מפעילים גם סיווג, התוצאה מוחזרת אחרי שהתיבה תוחמת והתווית של הקטגוריה זמינות. כתוצאה מכך, זמן האחזור לזיהוי עשוי להיות ארוך יותר. כמו כן, במצב תמונה יחידה לא מוקצים מזהי מעקב. מומלץ להשתמש במצב הזה אם זמן האחזור הוא קריטי ולא רוצים לטפל בתוצאות חלקיות.
זיהוי ומעקב אחר אובייקטים מרובים false
(ברירת מחדל) |true
אם לזהות ולעקוב אחר עד חמישה אובייקטים או רק את האובייקט הבולט ביותר (ברירת מחדל).
סיווג אובייקטים false
(ברירת מחדל) |true
האם לסווג אובייקטים מזוהים לקטגוריות גסות או לא. כשהאפשרות הזו מופעלת, מזהה האובייקט מחולק לקטגוריות הבאות: מוצרי אופנה, מזון, מוצרים לבית, מקומות וצמחים.
ה-API לזיהוי ולמעקב אחר אובייקטים מותאם לשני התרחישים העיקריים הבאים:
- זיהוי חי ומעקב של האובייקט הבולט ביותר בעינית המצלמה.
- זיהוי של אובייקטים מרובים בתמונה סטטית.
כדי להגדיר את ה-API לתרחישים הבאים:
Swift
// Live detection and tracking let options = ObjectDetectorOptions() options.shouldEnableClassification = true // Multiple object detection in static images let options = ObjectDetectorOptions() options.detectorMode = .singleImage options.shouldEnableMultipleObjects = true options.shouldEnableClassification = true
Objective-C
// Live detection and tracking MLKObjectDetectorOptions *options = [[MLKObjectDetectorOptions alloc] init]; options.shouldEnableClassification = YES; // Multiple object detection in static images MLKObjectDetectorOptions *options = [[MLKOptions alloc] init]; options.detectorMode = MLKObjectDetectorModeSingleImage; options.shouldEnableMultipleObjects = YES; options.shouldEnableClassification = YES;
- לקבלת מכונה של
ObjectDetector
:
Swift
let objectDetector = ObjectDetector.objectDetector() // Or, to change the default settings: let objectDetector = ObjectDetector.objectDetector(options: options)
Objective-C
MLKObjectDetector *objectDetector = [MLKObjectDetector objectDetector]; // Or, to change the default settings: MLKObjectDetector *objectDetector = [MLKObjectDetector objectDetectorWithOptions: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
לאחת משיטות עיבוד התמונות של מזהה האובייקט. ניתן להשתמש בשיטה האסינכרונית process(image:)
או בשיטת results()
הסינכרונית.
כדי לזהות אובייקטים באופן אסינכרוני:
Swift
objectDetector.process(image) { objects, error in guard error == nil else { // Error. return } guard !objects.isEmpty else { // No objects detected. return } // Success. Get object info here. // ... }
Objective-C
[objectDetector processImage:image completion:^(NSArray* _Nullable objects, NSError * _Nullable error) { if (error == nil) { return; } if (objects.count == 0) { // No objects detected. return; } // Success. Get object info here. }];
כדי לזהות אובייקטים באופן סינכרוני:
Swift
var objects: [Object] do { objects = try objectDetector.results(in: image) } catch let error { print("Failed to detect object with error: \(error.localizedDescription).") return } guard !objects.isEmpty else { print("Object detector returned no results.") return } // Success. Get object info here.
Objective-C
NSError *error; NSArray*objects = [objectDetector resultsInImage:image error:&error]; if (error == nil) { return; } if (objects.count == 0) { // No objects detected. return; } // Success. Get object info here.
4. קבלת מידע על אובייקטים שזוהו
אם הקריאה למעבד התמונות מצליחה, היא מעבירה רשימה שלObject
s ל-handler של ההשלמה או מחזירה את הרשימה, בהתאם לקריאה לשיטה האסינכרונית או הסינכרונית.
כל Object
מכיל את המאפיינים הבאים:
frame |
CGRect שמציין את מיקום האובייקט בתמונה. |
trackingID |
מספר שלם שמזהה את האובייקט בתמונות, או 'nil' במצב תמונה יחידה. |
labels |
מערך של תוויות המתאר את האובייקט שהוחזר על ידי המזהה.
המאפיין ריק אם אפשרות הזיהוי
shouldEnableClassification מוגדרת ל-false .
|
Swift
// objects contains one item if multiple object detection wasn't enabled. for object in objects { let frame = object.frame let trackingID = object.trackingID // If classification was enabled: let description = object.labels.enumerated().map { (index, label) in "Label \(index): \(label.text), \(label.confidence)" }.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]; ... } }
שיפור נוחות השימוש והביצועים
כדי ליהנות מחוויית המשתמש הטובה ביותר, מומלץ לפעול לפי ההנחיות הבאות באפליקציה:
- זיהוי אובייקט מוצלח תלוי במורכבות החזותית של האובייקט. כדי שאובייקטים יזוהו, ייתכן שאובייקטים עם מספר קטן של תכונות ויזואליות יתפסו חלק גדול יותר מהתמונה. עליכם לספק למשתמשים הנחיות לצילום הקלט שמתאים היטב לסוג האובייקטים שרוצים לזהות.
- במהלך השימוש בסיווג, אם אתם רוצים לזהות אובייקטים שלא שייכים בקלות לקטגוריות הנתמכות, כדאי להשתמש בטיפול מיוחד באובייקטים לא ידועים.
כדאי גם לבדוק את האוסף Material Design תבניות עבור תכונות מבוססות-למידת מכונה.
כשאתם משתמשים במצב סטרימינג באפליקציה בזמן אמת, פעלו לפי ההנחיות הבאות כדי להשיג את קצב הפריימים הטוב ביותר:
- אין להשתמש בזיהוי אובייקטים מרובים במצב סטרימינג, כי רוב המכשירים לא יוכלו ליצור קצבי פריימים מתאימים.
- אם אין צורך, אפשר להשבית את הסיווג.
- לעיבוד מסגרות וידאו, יש להשתמש ב-
results(in:)
ב-API הסינכרוני של המזהה. ניתן לקרוא לשיטה הזו באמצעות הפונקציהAVCaptureVideoDataOutputSampleBufferDelegate
captureOutput(_, didOutput:from:)
כדי לקבל תוצאות סינכרוניות מהפריים של הווידאו. צריך להשאיר את ה-alwaysDiscardsLateVideoFrames
שלAVCaptureVideoDataOutput
בתורtrue
כדי לווסת את השיחות. אם יהפוך לפריים חדש של סרטון בזמן שהמזהה פועל, הוא יוסר. - אם משתמשים בפלט של המזהה כשכבת-על של גרפיקה בתמונת הקלט, קודם צריך לקבל את התוצאה מ-ML Kit, ואז לעבד את התמונה ואת שכבת-העל בפעולה אחת. אם עושים זאת, מתבצע רינדור של התצוגה למשטח התצוגה רק פעם אחת בכל מסגרת קלט שעברה עיבוד. כדי לקבל דוגמה, אפשר לעיין בupdatePreviewLayerViewWithLastFrame שבדוגמה למתחילים של ML.