ב-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', '7.0.0' # If you want to use the accurate implementation: pod 'GoogleMLKit/PoseDetectionAccurate', '7.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
למטפל בהשלמה או מחזיר את המערך, בהתאם לשיטה שהפעלתם – אסינכרוני או סינכרוני.
אם האדם לא נמצא בתמונה במלואו, המערכת מקצה את הקואורדינטות של נקודות הציון החסרות מחוץ למסגרת ומקצה להן ערכים נמוכים של 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:)
של הגלאי. כדי לקבל תוצאות מסונכרנות מהפריים הנתון של הסרטון, צריך להפעיל את השיטה הזו מהפונקציה captureOutput(_, didOutput:from:) של AVCaptureVideoDataOutputSampleBufferDelegate. כדי להגביל את הקריאות לגלאי, משאירים את הערך של alwaysDiscardsLateVideoFrames ב-AVCaptureVideoDataOutput כ-true. אם פריים חדש של סרטון יהפוך לזמין בזמן שהגלאי פועל, הוא יידחה. - אם משתמשים בפלט של הגלאי כדי להוסיף שכבת-על של גרפיקה לתמונה הקלט, קודם צריך לקבל את התוצאה מ-ML Kit ואז לבצע עיבוד (רנדור) של התמונה והשכבה העליונה בשלב אחד. כך מבצעים רינדור למשטח התצוגה רק פעם אחת לכל מסגרת קלט שעברה עיבוד. לדוגמה, אפשר לעיין במחלקות previewOverlayView ו-MLKDetectionOverlayView באפליקציית הדוגמה.
השלבים הבאים
- במאמר טיפים לסיווג תנוחות מוסבר איך משתמשים בנקודות ציון של תנוחות כדי לסווג תנוחות.
- דוגמה למדריך למתחילים ב-ML Kit ב-GitHub, עם דוגמה לשימוש ב-API הזה.