אפשר להשתמש ב-ML Kit כדי לזהות אובייקטים ולעקוב אחריהם בכמה פריימים של וידאו.
כשמעבירים תמונות ML Kit, מערכת ML Kit מחזירה רשימה של כל תמונה של עד חמישה אובייקטים שזוהו ואת המיקום שלהם בתמונה. כשאנחנו מזהים אובייקטים בסטרימינג של סרטונים, לכל אובייקט יש מזהה שאפשר להשתמש בו כדי לעקוב אחרי האובייקט בתמונות שונות. אפשר גם להפעיל אובייקט גס סיווג, שמוסיף תוויות לאובייקטים עם תיאורים רחבים של קטגוריות.
לפני שמתחילים
- אם עדיין לא הוספתם את Firebase לאפליקציה, צריך לבצע את הפעולות הבאות במדריך לתחילת העבודה.
- כוללים את ספריות ML Kit ב-Podfile:
אחרי שמתקינים או מעדכנים את קבוצות ה-Pod של הפרויקט, חשוב לפתוח את ה-Xcode באמצעות ה-pod 'Firebase/MLVision', '6.25.0' pod 'Firebase/MLVisionObjectDetection', '6.25.0'
.xcworkspace
שלו. - מייבאים את Firebase לאפליקציה:
import Firebase
@import Firebase;
1. הגדרת מזהה האובייקטים
כדי להתחיל לזהות אובייקטים ולעקוב אחריהם, קודם צריך ליצור מופע של
VisionObjectDetector
, אם רוצים לציין את כל הגדרות המזהה שרוצים
שינוי מברירת המחדל.
מגדירים את מזהה האובייקטים לתרחיש לדוגמה באמצעות מאפיין אובייקט
VisionObjectDetectorOptions
. אפשר לשנות את האפשרויות הבאות ההגדרות:הגדרות של מזהה אובייקטים מצב זיהוי .stream
(ברירת מחדל) |.singleImage
במצב סטרימינג (ברירת מחדל), מזהה האובייקטים פועל כשהטמפרטורה נמוכה מאוד אבל יכול להיות שהתוצאה תהיה תוצאות חלקיות (למשל, תיבות תוחמות (או קטגוריה)) בהפעלות הראשונות של את גלאי. בנוסף, במצב סטרימינג, הגלאי מקצה מזהי מעקב לאובייקטים, שאפשר להשתמש בהם כדי לעקוב אחר אובייקטים בפריימים שונים. כדאי להשתמש במצב הזה כשרוצים לעקוב אחרי אובייקטים, או כשזמן האחזור קצר הוא חשוב, למשל כשמעבדים זרמי וידאו בזמן האימון.
במצב תמונה יחידה, מזהה האובייקטים ימתין עד התיבה התוחמת של האובייקט והקטגוריה (אם הפעלתם סיווג) זמינים לפני החזרת תוצאה. כתוצאה מכך, זמן האחזור לזיהוי עלול להיות ארוך יותר. כמו כן, בתמונה אחת במצב הזה, לא מוקצים מזהים לצורכי מעקב. כדאי להשתמש במצב הזה אם זמן האחזור אינן קריטיות ואינך רוצה לטפל תוצאות.
זיהוי של מספר אובייקטים ומעקב אחריהם false
(ברירת מחדל) |true
האם לזהות ולעקוב אחר עד חמישה אובייקטים או רק את רובם אובייקט בולט (ברירת מחדל).
סיווג אובייקטים false
(ברירת מחדל) |true
האם לסווג את האובייקטים שזוהו לקטגוריות גסות. כשההגדרה מופעלת, מזהה האובייקטים מסווג את האובייקטים הקטגוריות הבאות: מוצרי אופנה, אוכל, מוצרים לבית, מקומות, צמחים ופרטים לא ידועים.
ממשק ה-API לזיהוי אובייקטים ולמעקב אחריהם מותאם לשני התרחישים הבאים לדוגמה:
- זיהוי בזמן אמת ומעקב אחרי האובייקט הבולט ביותר במצלמה עינית
- זיהוי של מספר אובייקטים בתמונה סטטית
כדי להגדיר את ה-API לתרחישים לדוגמה האלה:
// 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
// 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
:let objectDetector = Vision.vision().objectDetector() // Or, to change the default settings: let objectDetector = Vision.vision().objectDetector(options: options)
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
.let image = VisionImage(image: uiImage)
FIRVisionImage *image = [[FIRVisionImage alloc] initWithImage:uiImage];
כדי להשתמש ב-
CMSampleBufferRef
:-
יוצרים אובייקט
VisionImageMetadata
שמציין את של נתוני התמונה שכלולים מאגר נתונים זמני שלCMSampleBufferRef
.כדי לקבל את כיוון התמונה:
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 } }
- (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; } }
לאחר מכן, יוצרים את אובייקט המטא-נתונים:
let cameraPosition = AVCaptureDevice.Position.back // Set to the capture device you used. let metadata = VisionImageMetadata() metadata.orientation = imageOrientation( deviceOrientation: UIDevice.current.orientation, cameraPosition: cameraPosition )
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
והמטא-נתונים של הסבב:let image = VisionImage(buffer: sampleBuffer) image.metadata = metadata
FIRVisionImage *image = [[FIRVisionImage alloc] initWithBuffer:sampleBuffer]; image.metadata = metadata;
- במקרה הצורך, מסובבים את התמונה כך ש-
מעבירים את הערך
VisionImage
לאחד מעיבוד התמונה של מזהה האובייקטים שיטות. אפשר להשתמש בשיטהprocess(image:)
האסינכרונית או ב- שיטתresults()
סינכרונית.כדי לזהות אובייקטים באופן אסינכרוני:
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. // ... }
[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. // ... }];
כדי לזהות אובייקטים באופן סינכרוני:
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 } // ...
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
מכיל את המאפיינים הבאים:frame
CGRect
שמציין את המיקום של האובייקט תמונה.trackingID
מספר שלם שמזהה את האובייקט בתמונות. אפס במצב תמונה יחידה. classificationCategory
הקטגוריה גסה של האובייקט. אם מזהה האובייקטים לא יש סיווג מופעל. הערך הוא תמיד .unknown
.confidence
ערך הסמך של סיווג האובייקט. אם הסיווג לא מופעל בזיהוי האובייקטים, או שהאובייקט מסווג כ'לא ידוע', הערך הוא nil
.// 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 }
// 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-link]{: .external } ובאוסף דוגמאות לתכונות מבוססות-למידת מכונה של Material Design.
כשמשתמשים במצב סטרימינג באפליקציה בזמן אמת, צריך לפעול לפי ההנחיות הבאות כדי להשיג את קצבי הפריימים הטובים ביותר:
אין להשתמש בזיהוי אובייקטים מרובים במצב סטרימינג, כי רוב המכשירים לא יכולת להפיק קצבי פריימים מתאימים.
משביתים את הסיווג אם אין צורך בו.
- ויסות נתונים (throttle) קריאות לגלאי. אם פריים חדש בסרטון הופך בזמן שהגלאי פועל, משחררים את הפריים.
- אם משתמשים בפלט של הגלאי כדי להציג גרפיקה בשכבת-על מקבלים קודם את התוצאה מ-ML Kit ואז מעבדים את התמונה וליצור שכבת-על בשלב אחד. כך תוכלו לבצע עיבוד (רנדור) למשטח התצוגה רק פעם אחת לכל מסגרת קלט. אפשר לעיין ב-previewOverlayView ו-FIRDetectionOverlayView באפליקציה לדוגמה של Showcase.