ML Kit מספק שתי ערכות SDK שעברו אופטימיזציה לזיהוי תנוחה.
שם ה-SDK | PoseDetection | PoseDetectionAccurate |
---|---|---|
הטמעה | הנכסים של המזהה הבסיסי מקושרים לאפליקציה באופן סטטי בזמן ה-build. | נכסים לזיהוי מדויק מקושרים באופן סטטי לאפליקציה בזמן ה-build. |
גודל האפליקציה | עד 29.6MB | עד 33.2MB |
ביצועים | iPhone X: כ-45FPS | iPhone X: כ-29FPS |
אני רוצה לנסות
- מומלץ להתנסות באפליקציה לדוגמה כדי לראות דוגמה לשימוש ב-API הזה.
לפני שמתחילים
כוללים ב-Podfile את רצפי ה-ML Kit הבאים:
# If you want to use the base implementation: pod 'GoogleMLKit/PoseDetection', '3.2.0' # If you want to use the accurate implementation: pod 'GoogleMLKit/PoseDetectionAccurate', '3.2.0'
אחרי שמתקינים או מעדכנים את רצף המודעות של הפרויקט, פותחים את פרויקט 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
ל-handler של ההשלמה או מחזיר את המערך, בהתאם לשיטה שבה השתמשתם כדי לקרוא לשיטה האסינכרונית או הסינכרונית.
אם האדם לא היה בתוך התמונה, המודל מקצה לציוני הדרך החסרים את הקואורדינטות החסרות מחוץ למסגרת, ונותן להם ערכים נמוכים של ודאות InFrame.
אם לא זוהה אדם, המערך ריק.
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 פיקסלים.
- אם אתם מזהים תנוחה באפליקציה בזמן אמת, כדאי גם לקחת בחשבון את המידות הכוללות של תמונות הקלט. אפשר לעבד תמונות קטנות יותר מהר יותר. לכן, כדי לצמצם את זמן האחזור, לצלם תמונות ברזולוציות נמוכות יותר, אבל חשוב לשים לב לדרישות הרזולוציה שצוינו למעלה ולוודא שהנושא תופס מקום רב ככל האפשר מהתמונה.
- גם מיקוד תמונה לא טוב יכול להשפיע על רמת הדיוק. אם לא מתקבלות תוצאות מקובלות, בקשו מהמשתמש לצלם מחדש את התמונה.
אם אתם רוצים להשתמש בזיהוי תנוחה באפליקציה בזמן אמת, צריך לפעול לפי ההנחיות הבאות כדי להשיג את קצב הפריימים הטוב ביותר:
- שימוש ב-Base PoseDetection SDK ובמצב זיהוי
stream
. - כדאי לצלם תמונות ברזולוציה נמוכה יותר. עם זאת, חשוב לזכור גם את הדרישות בנוגע למידות תמונה ב-API הזה.
- כדי לעבד פריימים של וידאו, צריך להשתמש ב-API הסינכרוני
results(in:)
של הגלאי. קוראים לשיטה הזו מהפונקציה captureOutput(_, didOutput:from:) בפונקציה AVCaptureVideoDataOutputSampleBufferDelegate כדי לקבל באופן סינכרוני תוצאות ממסגרת הווידאו הנתונה. יש להשאיר את AVCaptureVideoDataOutputשל alwaysDiscardsLateVideoFrames כאמין כדי לווסת קריאות לגלאי. אם פריים חדש לסרטון יהפוך לזמין בזמן שהגלאי פועל, היא תוסר. - אם משתמשים בפלט של הגלאי כדי ליצור שכבת-על של גרפיקה בתמונת הקלט, מקבלים קודם את התוצאה מ-ML Kit ואז מעבדים את התמונה ושכבת-העל בשלב אחד. כך תוכלו לעבד את משטח המסך פעם אחת בלבד עבור כל מסגרת קלט מעובדת. כדוגמה, אפשר לעיין בכיתות previewOverlayView ו-MLKDetectionOverlayView באפליקציה לדוגמה לדוגמה.
השלבים הבאים
- כדי ללמוד איך להשתמש בציוני דרך שמבוססים על ציוני דרך שמבוססים על תנוחות, כדאי לעיין בטיפים לסיווג פוזה.
- כדי לראות דוגמה לשימוש ב-API הזה, אפשר לעיין בדוגמה של המדריך למתחילים ל-ML Kit ב-GitHub.