ערכת ML Kit מספקת שתי ערכות SDK שעברו אופטימיזציה לזיהוי תנוחה.
שם ה-SDK | PoseDetection | PoseDetectionAccurate |
---|---|---|
הטמעה | הנכסים של מזהה הבסיס מקושרים באופן סטטי לאפליקציה בזמן ה-build. | נכסים לזיהוי מדויק מקושרים באופן סטטי לאפליקציה בזמן ה-build. |
גודל האפליקציה | עד 29.6MB | עד 33.2MB |
ביצועים | iPhone X: ~45FPS | iPhone X: ~29FPS |
אני רוצה לנסות
- אפשר לנסות את האפליקציה לדוגמה כדי לראות דוגמה לשימוש ב-API הזה.
לפני שמתחילים
יש לכלול את הפודים הבאים של ערכת ML ב-Podfile:
# 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'
אחרי שמתקינים או מעדכנים את רכיבי ה-pod של הפרויקט, פותחים את פרויקט Xcode באמצעות ה-
xcworkspace
שלו. ערכת ML נתמכת ב-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 להשלמה או מחזיר את המערך, בהתאם לשיטה האסינכרונית או הסינכרונית שנקראה.
אם האדם לא היה בתוך התמונה, המודל מקצה את הקואורדינטות החסרות מחוץ למסגרת וערכי 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 כדי לקבל באופן סינכרוני תוצאות מהפריים הנתון. חשוב לשמור על AVCaptureVideoDataOutput alwaysDiscardsLateVideoFrames כנכון כדי לווסת קריאות לגלאי. אם מתאפשרת פריים חדש לסרטון בזמן שהמזהה פועל, היא תוסר. - אם משתמשים בפלט של הגלאי כדי להציג גרפיקה כשכבת-על בתמונת הקלט, קודם צריך לקבל את התוצאה מ-ML Kit, ואז לעבד את התמונה ושכבת-העל בשלב אחד. כך, עיבוד הנתונים מתבצע על פני המסך פעם אחת בלבד לכל מסגרת קלט מעובדת. לדוגמה, אפשר לעיין במחלקות previewOverlayView ו-MLKDetectionOverlayView באפליקציה לדוגמה של חלון הראווה.
השלבים הבאים
- אפשר לקרוא מידע נוסף על איך להשתמש בציוני דרך של תנוחה כדי לסווג תנוחות. אפשר לקרוא את המאמר טיפים לסיווג תנוחה.
- כדי לראות דוגמה לשימוש ב-API הזה, עיינו בדוגמה לשימוש במדריך למתחילים של ML Kit ב-GitHub.