ערכת ML Kit כוללת שתי ערכות SDK שעברו אופטימיזציה לזיהוי תנוחות.
| שם ה-SDK | PoseDetection | PoseDetectionAccurate |
|---|---|---|
| הטמעה | הנכסים של הגלאי הבסיסי מקושרים באופן סטטי לאפליקציה בזמן ה-build. | נכסים של גלאי מדויק מקושרים באופן סטטי לאפליקציה בזמן ה-build. |
| גודל האפליקציה | עד 29.6MB | עד 33.2MB |
| ביצועים | iPhone X: ~45FPS | iPhone X: ~29FPS |
רוצה לנסות?
- כדי לראות דוגמה לשימוש ב-API הזה, אתם יכולים להתנסות באפליקציה לדוגמה.
לפני שמתחילים
מוסיפים את ה-pods הבאים של ML Kit ל-Podfile:
# If you want to use the base implementation: pod 'GoogleMLKit/PoseDetection', '8.0.0' # If you want to use the accurate implementation: pod 'GoogleMLKit/PoseDetectionAccurate', '8.0.0'אחרי שמתקינים או מעדכנים את ה-pods של הפרויקט, פותחים את פרויקט Xcode באמצעות
xcworkspace. ML Kit נתמך ב-Xcode בגרסה 13.2.1 ואילך.
1. יצירת מופע של PoseDetector
כדי לזהות תנוחה בתמונה, קודם צריך ליצור מופע של PoseDetector ואפשר גם לציין את הגדרות הגלאי.
PoseDetector אפשרויות
מצב זיהוי
ה-PoseDetector פועל בשני מצבי זיהוי. חשוב לבחור את האפשרות שמתאימה לתרחיש לדוגמה שלכם.
-
stream(ברירת מחדל) - גלאי התנוחות יזהה קודם את האדם הבולט ביותר בתמונה ואז יפעיל את זיהוי התנוחות. בפריימים הבאים, שלב זיהוי האדם לא יתבצע, אלא אם האדם מוסתר או שכבר לא מזוהה ברמת ודאות גבוהה. גלאי התנוחה ינסה לעקוב אחרי האדם הבולט ביותר ולהחזיר את התנוחה שלו בכל הסקה. כך אפשר לצמצם את זמן האחזור ולשפר את הזיהוי. השתמשו במצב הזה כשאתם רוצים לזהות תנוחה בסטרימינג של וידאו.
singleImage- גלאי התנוחה יזהה אדם ואז יפעיל את זיהוי התנוחה. שלב זיהוי האנשים יפעל בכל תמונה, כך שהזמן שלוקח לזהות אנשים יהיה ארוך יותר, ולא יהיה מעקב אחרי אנשים. כדאי להשתמש במצב הזה כשמשתמשים בזיהוי תנוחה בתמונות סטטיות או כשלא רוצים להשתמש במעקב.
מגדירים את האפשרויות של גלאי התנוחות:
Swift
// Base pose detector with streaming, when depending on the PoseDetection SDK let options = PoseDetectorOptions() options.detectorMode = .stream // Accurate pose detector on static images, when depending on the // PoseDetectionAccurate SDK let options = AccuratePoseDetectorOptions() options.detectorMode = .singleImage
Objective-C
// Base pose detector with streaming, when depending on the PoseDetection SDK MLKPoseDetectorOptions *options = [[MLKPoseDetectorOptions alloc] init]; options.detectorMode = MLKPoseDetectorModeStream; // Accurate pose detector on static images, when depending on the // PoseDetectionAccurate SDK MLKAccuratePoseDetectorOptions *options = [[MLKAccuratePoseDetectorOptions alloc] init]; options.detectorMode = MLKPoseDetectorModeSingleImage;
בסיום, מקבלים מופע של PoseDetector. מעבירים את האפשרויות שציינתם:
Swift
let poseDetector = PoseDetector.poseDetector(options: options)
Objective-C
MLKPoseDetector *poseDetector = [MLKPoseDetector poseDetectorWithOptions: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
var results: [Pose] do { results = try poseDetector.results(in: image) } catch let error { print("Failed to detect pose with error: \(error.localizedDescription).") return } guard let detectedPoses = results, !detectedPoses.isEmpty else { print("Pose detector returned no results.") return } // Success. Get pose landmarks here.
Objective-C
NSError *error; NSArray*poses = [poseDetector resultsInImage:image error:&error]; if (error != nil) { // Error. return; } if (poses.count == 0) { // No pose detected. return; } // Success. Get pose landmarks here.
כדי לזהות אובייקטים באופן אסינכרוני:
Swift
poseDetector.process(image) { detectedPoses, error in guard error == nil else { // Error. return } guard !detectedPoses.isEmpty else { // No pose detected. return } // Success. Get pose landmarks here. }
Objective-C
[poseDetector processImage:image completion:^(NSArray* _Nullable poses, NSError * _Nullable error) { if (error != nil) { // Error. return; } if (poses.count == 0) { // No pose detected. return; } // Success. Get pose landmarks here. }];
4. קבלת מידע על התנוחה שזוהתה
אם מזוהה אדם בתמונה, ה-API לזיהוי תנוחות מעביר מערך של אובייקטים מסוג Pose ל-completion handler או מחזיר את המערך, בהתאם לשיטה שבה השתמשתם – אסינכרונית או סינכרונית.
אם האדם לא היה לגמרי בתוך התמונה, המודל מקצה לנקודות הציון החסרות קואורדינטות מחוץ למסגרת ונותן להן ערכי InFrameConfidence נמוכים.
אם לא זוהה אדם, המערך ריק.
Swift
for pose in detectedPoses { let leftAnkleLandmark = pose.landmark(ofType: .leftAnkle) if leftAnkleLandmark.inFrameLikelihood > 0.5 { let position = leftAnkleLandmark.position } }
Objective-C
for (MLKPose *pose in detectedPoses) { MLKPoseLandmark *leftAnkleLandmark = [pose landmarkOfType:MLKPoseLandmarkTypeLeftAnkle]; if (leftAnkleLandmark.inFrameLikelihood > 0.5) { MLKVision3DPoint *position = leftAnkleLandmark.position; } }
טיפים לשיפור הביצועים
איכות התוצאות תלויה באיכות של תמונת המקור:
- כדי ש-ML Kit יזהה את התנוחה בצורה מדויקת, האדם בתמונה צריך להיות מיוצג על ידי מספיק נתוני פיקסלים. כדי להשיג את הביצועים הטובים ביותר, האובייקט צריך להיות בגודל של לפחות 256x256 פיקסלים.
- אם אתם מזהים תנוחה באפליקציה בזמן אמת, כדאי גם להביא בחשבון את המידות הכוללות של תמונות הקלט. תמונות קטנות יותר מעובדות מהר יותר, אז כדי לצמצם את זמן האחזור, כדאי לצלם תמונות ברזולוציות נמוכות יותר, אבל חשוב לזכור את דרישות הרזולוציה שלמעלה ולוודא שהאובייקט תופס כמה שיותר מהתמונה.
- גם תמונה לא ממוקדת יכולה להשפיע על הדיוק. אם לא מקבלים תוצאות קבילות, מבקשים מהמשתמש לצלם את התמונה מחדש.
אם אתם רוצים להשתמש בזיהוי תנוחה באפליקציה בזמן אמת, כדאי לפעול לפי ההנחיות הבאות כדי להשיג את קצב הפריימים הטוב ביותר:
- משתמשים ב-SDK הבסיסי של PoseDetection ובמצב הזיהוי
stream. - כדאי לצלם תמונות ברזולוציה נמוכה יותר. עם זאת, חשוב לזכור גם את הדרישות של ה-API הזה לגבי מידות התמונה.
- כדי לעבד פריימים של וידאו, משתמשים ב-API הסינכרוני
results(in:)של הגלאי. קוראים ל-method הזה מהפונקציה captureOutput(_, didOutput:from:) של AVCaptureVideoDataOutputSampleBufferDelegate כדי לקבל תוצאות באופן סינכרוני מהפריים הנתון. כדי להגביל את הקריאות לגלאי, צריך להשאיר את הערך של alwaysDiscardsLateVideoFrames של AVCaptureVideoDataOutput כ-true. אם פריים חדש של סרטון יהיה זמין בזמן שהגלאי פועל, הוא יושמט. - אם אתם משתמשים בפלט של הגלאי כדי להוסיף שכבת-על של גרפיקה לתמונת הקלט, קודם צריך לקבל את התוצאה מ-ML Kit, ואז לעבד את התמונה ואת שכבת-העל בשלב אחד. כך, העיבוד של משטח התצוגה מתבצע רק פעם אחת לכל פריים קלט שעבר עיבוד. כדי לראות דוגמה, עיינו במחלקות previewOverlayView ו-MLKDetectionOverlayView באפליקציה לדוגמה.
השלבים הבאים
- במאמר טיפים לסיווג תנוחות מוסבר איך משתמשים בנקודות ציון של תנוחות כדי לסווג תנוחות.
- ב-GitHub יש דוגמה למדריך למתחילים של ML Kit שממחישה איך משתמשים ב-API הזה.