מדריך לזיהוי פנים ל-iOS

המשימה 'זיהוי פנים' מאפשרת לך לזהות פנים בתמונה או בסרטון. אפשר להשתמש במשימה הזו מאתרים פנים ותווי פנים בתוך מסגרת. במשימה הזאת נעשה שימוש מודל למידת מכונה (ML) שעובד עם תמונות בודדות או עם שידור רציף של תמונות. פלט המשימה: מיקומים של זיהוי פנים ומפתח זיהוי הפנים הבא נקודות: עין שמאל, עין ימין, קצה אף, פה, טרגדיה של עין שמאל ועין ימין טרגיה.

דוגמת הקוד שמתוארת בהוראות האלה זמינה ב-GitHub. אפשר לראות את המשימה הזו באתר . לקבלת מידע נוסף מידע על היכולות, המודלים ואפשרויות התצורה של אפשרות זו במשימה, סקירה כללית

קוד לדוגמה

קוד הדוגמה למשימות MediaPipe הוא הטמעה פשוטה של גלאי פנים אפליקציה ל-iOS. בדוגמה, נעשה שימוש במצלמה במכשיר Android פיזי כדי לזהות פנים בשידור וידאו רציף. האפליקציה יכולה לזהות פנים גם בתמונות סרטונים מגלריית המכשיר.

אפשר להשתמש באפליקציה כנקודת התחלה של אפליקציה משלך ל-iOS, או להתייחס אליה כשמשנים אפליקציה קיימת. הקוד לדוגמה של 'זיהוי פנים' מתארח ב GitHub.

להורדת הקוד

בהוראות הבאות מוסבר איך ליצור עותק מקומי של הדוגמה באמצעות כלי שורת הפקודה git.

כדי להוריד את הקוד לדוגמה:

  1. משכפלים את מאגר ה-Git באמצעות הפקודה הבאה:

    git clone https://github.com/google-ai-edge/mediapipe-samples
    
  2. לחלופין, להגדיר את מכונת ה-Git שלך לשימוש בקופה עם היעדר תשלום, כדי רק הקבצים לאפליקציה לדוגמה של 'זיהוי פנים':

    cd mediapipe
    git sparse-checkout init --cone
    git sparse-checkout set examples/face_detector/ios/
    

אחרי שתיצרו גרסה מקומית של הקוד לדוגמה, תוכלו להתקין את ספריית המשימות של MediaPipe, פותחים את הפרויקט באמצעות Xcode ומריצים את האפליקציה. עבור ההוראות מפורטות במדריך ההגדרה ל-iOS.

רכיבים מרכזיים

הקבצים הבאים מכילים את הקוד החיוני לדוגמה של 'זיהוי פנים' יישום:

  • FaceDetectorService.swift: הפעלת הגלאי, טיפול בבחירת המודל והרצת ההסקה על נתוני הקלט.
  • CameraViewController: הטמעה של ממשק המשתמש עבור מצב הקלט של פיד המצלמה בשידור חי והצגת תוצאות הזיהוי באופן חזותי.
  • MediaLibraryViewController.swift: הטמעה של ממשק המשתמש עבור מצב הקלט של קובץ תמונה וקובץ וידאו והצגת תוצאות הזיהוי באופן חזותי.

הגדרה

בקטע הזה מתוארים השלבים העיקריים להגדרת סביבת הפיתוח פרויקטים של קוד לשימוש ב'זיהוי פנים'. לקבלת מידע כללי על הגדרת סביבת פיתוח לשימוש במשימות MediaPipe, כולל גרסת פלטפורמה מומלץ לעיין במדריך ההגדרה ל-iOS.

יחסי תלות

התכונה 'זיהוי פנים' משתמשת בספרייה MediaPipeTasksVision, שצריכה להיות מותקנת באמצעות CocoaPods. הספרייה תואמת גם לאפליקציות Swift ו-Objective-C ולא נדרשת הגדרה נוספת ספציפית לשפה.

הוראות להתקנת CocoaPods ב-macOS מפורטות במאמר CocoaPods במדריך ההתקנה. לקבלת הוראות ליצירת Podfile עם ה-pods שדרושים באפליקציה, קראו את המאמר שימוש CocoaPods.

מוסיפים את הרצף של MediaPipeTasksVision ב-Podfile באמצעות הקוד הבא:

target 'MyFaceDetectorApp' do
  use_frameworks!
  pod 'MediaPipeTasksVision'
end

אם האפליקציה שלך כוללת יעדים לבדיקת יחידות, יש לעיין במדריך ההגדרה של iOS למידע נוסף על ההגדרה Podfile.

דגם

למשימה 'זיהוי פנים של MediaPipe' נדרש מודל מאומן שתואם ל- במשימה הזו. לקבלת מידע נוסף על המודלים הזמינים המאומנים עבור ב'זיהוי פנים', אפשר לעיין בסקירה הכללית של המשימה מודלים .

בוחרים מודל ומורידים אותו, ומוסיפים אותו לספריית הפרויקט באמצעות Xcode. לקבלת הוראות להוספת קבצים לפרויקט Xcode, קראו את המאמר ניהול קבצים ותיקיות ב-Xcode. project.

משתמשים במאפיין BaseOptions.modelAssetPath כדי לציין את הנתיב למודל ב-App Bundle. בקטע הבא מופיע קוד לדוגמה.

יצירת המשימה

כדי ליצור את המשימה 'זיהוי פנים', צריך להפעיל אחד מהמאתחלים שלה. המאתחל של FaceDetector(options:) מקבל ערכים להגדרה אפשרויות.

אם אין לך צורך בגלאי פנים שאותחלו עם הגדרות בהתאמה אישית אפשר להשתמש במאתחל של FaceDetector(modelPath:) כדי ליצור גלאי פנים עם אפשרויות ברירת המחדל. מידע נוסף על הגדרה אפשרויות נוספות, ראו סקירה כללית של ההגדרות.

במשימה של 'זיהוי פנים' יש תמיכה ב-3 סוגים של נתוני קלט: תמונות סטילס וקובצי וידאו בסטרימינג של וידאו בשידור חי. כברירת מחדל, FaceDetector(modelPath:) מאתחל לתמונות סטילס. אם רוצים שהמשימה תופעל כדי לעבד סרטון קבצים או שידורים חיים, צריך להשתמש ב-FaceDetector(options:) כדי לציין את הסרטון או במצב ריצה בשידור חי. במצב השידור החי נדרשות גם פעולות נוספות את אפשרות ההגדרה של faceDetectorLiveStreamDelegate, שמאפשרת גלאי פנים יספק למקבל הגישה באופן אסינכרוני את תוצאות זיהוי הפנים.

כדי לראות איך יוצרים את המשימה, צריך לבחור את הכרטיסייה שמתאימה למצב הריצה ולהריץ את ההסקה.

Swift

תמונה

import MediaPipeTasksVision

let modelPath = Bundle.main.path(forResource: "model",
                                      ofType: "tflite")

let options = FaceDetectorOptions()
options.baseOptions.modelAssetPath = modelPath
options.runningMode = .image

let faceDetector = try FaceDetector(options: options)
    

וידאו

import MediaPipeTasksVision

let modelPath = Bundle.main.path(forResource: "model",
                                      ofType: "tflite")

let options = FaceDetectorOptions()
options.baseOptions.modelAssetPath = modelPath
options.runningMode = .video

let faceDetector = try FaceDetector(options: options)
    

שידור חי

import MediaPipeTasksVision

// Class that conforms to the `FaceDetectorLiveStreamDelegate` protocol and
// implements the method that the face detector calls once it finishes
// detecting faces in each input frame.
class FaceDetectorResultProcessor: NSObject, FaceDetectorLiveStreamDelegate {

  func faceDetector(
    _ faceDetector: FaceDetector,
    didFinishDetection result: FaceDetectorResult?,
    timestampInMilliseconds: Int,
    error: Error?) {

    // Process the face detection result or errors here.

  }
}

let modelPath = Bundle.main.path(
  forResource: "model",
  ofType: "tflite")

let options = FaceDetectorOptions()
options.baseOptions.modelAssetPath = modelPath
options.runningMode = .liveStream

// Assign an object of the class to the `faceDetectorLiveStreamDelegate`
// property.
let processor = FaceDetectorResultProcessor()
options.faceDetectorLiveStreamDelegate = processor

let faceDetector = try FaceDetector(options: options)
    

Objective-C

תמונה

@import MediaPipeTasksVision;

NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"model"
                                                      ofType:@"tflite"];

MPPFaceDetectorOptions *options = [[MPPFaceDetectorOptions alloc] init];
options.baseOptions.modelAssetPath = modelPath;
options.runningMode = MPPRunningModeImage;

MPPFaceDetector *faceDetector =
      [[MPPFaceDetector alloc] initWithOptions:options error:nil];
    

וידאו

@import MediaPipeTasksVision;

NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"model"
                                                      ofType:@"tflite"];

MPPFaceDetectorOptions *options = [[MPPFaceDetectorOptions alloc] init];
options.baseOptions.modelAssetPath = modelPath;
options.runningMode = MPPRunningModeVideo;

MPPFaceDetector *faceDetector =
      [[MPPFaceDetector alloc] initWithOptions:options error:nil];
    

שידור חי

@import MediaPipeTasksVision;

// Class that conforms to the `MPPFaceDetectorLiveStreamDelegate` protocol
// and implements the method that the face detector calls once it finishes
// detecting faces in each input frame.

@interface APPFaceDetectorResultProcessor : NSObject 

@end

@implementation APPFaceDetectorResultProcessor

-   (void)faceDetector:(MPPFaceDetector *)faceDetector
    didFinishDetectionWithResult:(MPPFaceDetectorResult *)faceDetectorResult
         timestampInMilliseconds:(NSInteger)timestampInMilliseconds
                           error:(NSError *)error {

    // Process the face detector result or errors here.

}

@end

NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"model"
                                                      ofType:@"tflite"];

MPPFaceDetectorOptions *options = [[MPPFaceDetectorOptions alloc] init];
options.baseOptions.modelAssetPath = modelPath;
options.runningMode = MPPRunningModeLiveStream;

// Assign an object of the class to the `faceDetectorLiveStreamDelegate`
// property.
APPFaceDetectorResultProcessor *processor = [APPFaceDetectorResultProcessor new];
options.faceDetectorLiveStreamDelegate = processor;

MPPFaceDetector *faceDetector =
      [[MPPFaceDetector alloc] initWithOptions:options error:nil];
    

הערה: אם משתמשים במצב סרטון או במצב שידור חי, התכונה 'זיהוי פנים' משתמשת כדי להימנע מהפעלת מודל הזיהוי בכל פריים, וכך להפחית את זמן האחזור.

אפשרויות תצורה

המשימה הזו כוללת את אפשרויות ההגדרה הבאות לאפליקציות ל-iOS:

שם האפשרות תיאור טווח ערכים ערך ברירת מחדל
runningMode מגדיר את מצב הריצה של המשימה. יש שלושה סוגים מצבים:

IMAGE: המצב לקלט של תמונה יחידה.

סרטון: המצב של פריימים מפוענחים בסרטון.

LIVE_STREAM: המצב לשידור חי של קלט נתונים ממצלמה, במצב הזה, resultListener חייב להיות נשלחה קריאה כדי להגדיר אוזן כדי לקבל תוצאות באופן אסינכרוני.
{RunningMode.image, RunningMode.video, RunningMode.liveStream} RunningMode.image
minDetectionConfidence ציון הסמך המינימלי כדי שזיהוי הפנים ייחשב כמוצלח. Float [0,1] 0.5
minSuppressionThreshold סף המינימום שאינו מקסימלי כדי לזהות פנים, ייחשב כחופף. Float [0,1] 0.3

הגדרות השידור החי

כשמצב ריצה מוגדר כשידור חי, גלאי הפנים דורש אפשרות הגדרה נוספת של faceDetectorLiveStreamDelegate, שמאפשרת את גלאי הפנים כדי לספק תוצאות זיהוי באופן אסינכרוני. בעל/ת הגישה מטמיעים את אמצעי תשלום אחד (faceDetector(_:didFinishDetection:timestampInMilliseconds:error:)), שאליו מתבצעת קריאה ב'גלאי הפנים' אחרי עיבוד התוצאות של זיהוי הפנים בכל מסגרת.

שם האפשרות תיאור טווח ערכים ערך ברירת מחדל
faceDetectorLiveStreamDelegate ההגדרה הזו מאפשרת לקבל תוצאות של זיהוי פנים באופן אסינכרוני באמצעות התכונה 'זיהוי פנים' במצב סטרימינג בשידור חי. המחלקה שהמופע שלה מוגדר לנכס הזה חייבת להטמיע את faceDetector(_:didFinishDetection:timestampInMilliseconds:error:) . לא רלוונטי לא מוגדר

הכנת נתונים

צריך להמיר את תמונת הקלט או המסגרת לאובייקט MPImage לפני ומעבירים אותו לגלאי הפנים. ב-MPImage יש תמיכה בסוגים שונים של קובצי תמונה ב-iOS ויכולים להשתמש בהם בכל מצב ריצה לצורך הסקת מסקנות. לקבלת מידע נוסף מידע על MPImage, מתייחס MPImage API

צריך לבחור פורמט תמונה ל-iOS בהתאם לתרחיש לדוגמה שלכם ולמצב הריצה מחייב.MPImage מקבל את UIImage, CVPixelBuffer, CMSampleBuffer פורמטים של תמונות ל-iOS.

UIImage

הפורמט UIImage מתאים במיוחד למצבי הריצה הבאים:

  • תמונות: תמונות מ-App Bundle, מגלריית משתמשים או ממערכת קבצים בפורמט אפשר להמיר UIImage תמונות לאובייקט MPImage.

  • סרטונים: משתמשים ב-AVAssetImageGenerator כדי לחלץ פריימים של וידאו CGImage וממירים אותן ל-UIImage תמונות.

Swift

// Load an image on the user's device as an iOS `UIImage` object.

// Convert the `UIImage` object to a MediaPipe's Image object having the default
// orientation `UIImage.Orientation.up`.
let image = try MPImage(uiImage: image)
    

Objective-C

// Load an image on the user's device as an iOS `UIImage` object.

// Convert the `UIImage` object to a MediaPipe's Image object having the default
// orientation `UIImageOrientationUp`.
MPImage *image = [[MPPImage alloc] initWithUIImage:image error:nil];
    

הדוגמה מאתחלת MPImage עם ברירת המחדל UIImage.Orientation.Up לכיוון מסוים. אפשר לאתחל MPImage עם כל אחד מהפורמטים הנתמכים UIImage.Orientation ערכים. התכונה 'זיהוי פנים' לא תומכת בכיוונים מסונכרנים כמו .upMirrored, .downMirrored, .leftMirrored, .rightMirrored.

למידע נוסף על UIImage, יש לעיין ב-UIImage Apple Developer מסמכים.

CVPixelBuffer

הפורמט CVPixelBuffer מתאים מאוד לאפליקציות שיוצרות פריימים ולהשתמש ב-CoreImage של iOS לעיבוד טקסט.

הפורמט CVPixelBuffer מתאים במיוחד למצבי הריצה הבאים:

  • תמונות: אפליקציות שיוצרות CVPixelBuffer תמונות לאחר עיבוד מסוים באמצעות המסגרת CoreImage של iOS ניתן לשלוח אל 'גלאי הפנים' ב מצב הרצת התמונות.

  • סרטונים: ניתן להמיר פריימים של וידאו לפורמט CVPixelBuffer עבור מתבצע עיבוד ולאחר מכן נשלחים ל'גלאי הפנים' במצב וידאו.

  • בשידור חי: אפליקציות שמשתמשות במצלמת iOS ליצירת פריימים עשויים לעבור המרה בפורמט CVPixelBuffer לעיבוד לפני השליחה גלאי פנים במצב שידור חי.

Swift

// Obtain a CVPixelBuffer.

// Convert the `CVPixelBuffer` object to a MediaPipe's Image object having the default
// orientation `UIImage.Orientation.up`.
let image = try MPImage(pixelBuffer: pixelBuffer)
    

Objective-C

// Obtain a CVPixelBuffer.

// Convert the `CVPixelBuffer` object to a MediaPipe's Image object having the
// default orientation `UIImageOrientationUp`.
MPImage *image = [[MPPImage alloc] initWithUIImage:image error:nil];
    

כדי לקבל מידע נוסף על CVPixelBuffer, אפשר לעיין ב-CVPixelBuffer Apple מפתחי המשחק מסמכים.

CMSampleBuffer

הפורמט CMSampleBuffer מאחסן דוגמאות מדיה מסוג מדיה אחיד, הוא גבוה מאוד למצב ההרצה של השידור החי. הפריימים בשידור חי ממצלמות iOS מועברים באופן אסינכרוני בפורמט CMSampleBuffer על ידי iOS AVCaptureVideoDataOutput.

Swift

// Obtain a CMSampleBuffer.

// Convert the `CMSampleBuffer` object to a MediaPipe's Image object having the default
// orientation `UIImage.Orientation.up`.
let image = try MPImage(sampleBuffer: sampleBuffer)
    

Objective-C

// Obtain a `CMSampleBuffer`.

// Convert the `CMSampleBuffer` object to a MediaPipe's Image object having the
// default orientation `UIImageOrientationUp`.
MPImage *image = [[MPPImage alloc] initWithSampleBuffer:sampleBuffer error:nil];
    

מידע נוסף על CMSampleBuffer זמין ב-CMSampleBuffer Apple מפתחי המשחק מסמכים.

הרצת המשימה

כדי להפעיל את גלאי הפנים, צריך להשתמש בשיטה detect() הספציפית שהוקצתה מצב ריצה:

  • תמונת סטילס: detect(image:)
  • סרטון: detect(videoFrame:timestampInMilliseconds:)
  • צפייה בשידור חי: detectAsync(image:timestampInMilliseconds:)

חיישן הפנים מחזיר את הפנים שזוהו בתמונת הקלט או בפריים.

דוגמאות הקוד הבאות מראות פשוטות להרצת גלאי פנים מצבי הריצה השונים הבאים:

Swift

תמונה

let result = try faceDetector.detect(image: image)
    

וידאו

let result = try faceDetector.detect(
  videoFrame: image,
  timestampInMilliseconds: timestamp)
    

שידור חי

try faceDetector.detectAsync(
  image: image,
  timestampInMilliseconds: timestamp)
    

Objective-C

תמונה

MPPFaceDetectorResult *result = [faceDetector detectInImage:image
                                                      error:nil];
    

וידאו

MPPFaceDetectorResult *result = [faceDetector detectInVideoFrame:image
                                         timestampInMilliseconds:timestamp
                                                           error:nil];
    

שידור חי

BOOL success = [faceDetector detectAsyncInImage:image
                        timestampInMilliseconds:timestamp
                                          error:nil];
    

בדוגמה של הקוד של 'זיהוי פנים' אפשר לראות את ההטמעה של כל אחד מהמצבים האלה בצורה מפורטת יותר detect(image:), detect(videoFrame:timestampInMilliseconds:), ו-detectAsync(image:timestampInMilliseconds:). הקוד לדוגמה מאפשר המשתמש יצטרך לעבור בין מצבי עיבוד שייתכן שהם לא נדרשים לשימוש שלך מותאמת אישית.

שימו לב לנקודות הבאות:

  • כשמפעילים במצב וידאו או במצב שידור חי, צריך גם לספק את הפרטים הבאים: חותמת הזמן של מסגרת הקלט למשימה 'זיהוי פנים'.

  • כשמפעילים את התכונה 'זיהוי פנים', היא חוסמת את את ה-thread הנוכחי עד לסיום העיבוד של תמונת הקלט או המסגרת. שפת תרגום לא לחסום את השרשור הנוכחי, צריך לבצע את העיבוד ברקע שרשור באמצעות iOS שליחה או NSOperation של מסגרות.

  • כשפועלים במצב שידור חי, המשימה 'זיהוי פנים' חוזרת באופן מיידי והיא לא חוסמת את השרשור הנוכחי. היא מפעילה את אמצעי תשלום אחד (faceDetector(_:didFinishDetection:timestampInMilliseconds:error:)) בתוצאת זיהוי הפנים לאחר העיבוד של כל פריים הקלט. חיישן הפנים מפעיל את השיטה הזו באופן אסינכרוני במספר סידורי ייעודי תור השליחה. להצגת תוצאות בממשק המשתמש, יש לשלוח את יוצגו לתור הראשי אחרי עיבוד התוצאות. אם detectAsync מתבצעת קריאה לפונקציה כאשר משימת 'זיהוי פנים' עסוקה בעיבוד אחר מסגרת הקלט, 'זיהוי פנים' מתעלם ממסגרת הקלט החדשה.

טיפול בתוצאות והצגתן

כשמריצים את ההסקה, המשימה 'זיהוי פנים' מחזירה FaceDetectorResult שמכיל את התיבות התוחמות את הפנים שזוהו וסימן מהימנות על כל פנים שזוהו.

בדוגמה הבאה אפשר לראות את נתוני הפלט מהמשימה:

FaceDetectionResult:
  Detections:
    Detection #0:
      BoundingBox:
        origin_x: 126
        origin_y: 100
        width: 463
        height: 463
      Categories:
        Category #0:
          index: 0
          score: 0.9729152917861938
      NormalizedKeypoints:
        NormalizedKeypoint #0:
          x: 0.18298381567001343
          y: 0.2961040139198303
        NormalizedKeypoint #1:
          x: 0.3302789330482483
          y: 0.29289937019348145
        ... (6 keypoints for each face)
    Detection #1:
      BoundingBox:
        origin_x: 616
        origin_y: 193
        width: 430
        height: 430
      Categories:
        Category #0:
          index: 0
          score: 0.9251380562782288
      NormalizedKeypoints:
        NormalizedKeypoint #0:
          x: 0.6151331663131714
          y: 0.3713381886482239
        NormalizedKeypoint #1:
          x: 0.7460576295852661
          y: 0.38825345039367676
        ... (6 keypoints for each face)

בתמונה הזו אפשר לראות את פלט המשימה:

לתמונה שאין בה תיבות תוחמות, יש לעיין בתמונה המקורית.

הקוד לדוגמה של 'זיהוי פנים' מדגים איך להציג את התוצאות. לצפייה דוגמה לקוד לפרטים.