זיהוי פנים עם ערכת ML ב- iOS

ניתן להשתמש בערכת ML לאיתור פנים בתמונות ובווידיאו.

לפני שאתה מתחיל

  1. אם לא כבר הוסיף Firebase באפליקציה, לעשות זאת על ידי ביצוע השלבים במדריך להפעלה .
  2. כלול את הספריות קיט ML ב Podfile שלך:
    pod 'Firebase/MLVision', '6.25.0'
    # If you want to detect face contours (landmark detection and classification
    # don't require this additional model):
    pod 'Firebase/MLVisionFaceModel', '6.25.0'
    
    לאחר להתקין או לעדכן שקיקים של הפרויקט שלך, להיות בטוח כדי לפתוח פרויקט Xcode שלך באמצעות שלה .xcworkspace .
  3. באפליקציה שלך, ייבא את Firebase:

    מָהִיר

    import Firebase

    Objective-C

    @import Firebase;

הקלט הנחיות לתמונות

כדי ש- ML Kit יזהה פנים מדויקות, תמונות הקלט חייבות להכיל פרצופים המיוצגים על ידי נתוני פיקסל מספיקים. באופן כללי, כל פנים שאתה רוצה לזהות בתמונה צריך להיות לפחות 100x100 פיקסלים. אם ברצונך לזהות את קווי המתאר של הפנים, ערכת ML דורשת קלט ברזולוציה גבוהה יותר: כל פנים צריך להיות לפחות 200x200 פיקסלים.

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

מיקוד לקוי של התמונה עלול לפגוע בדיוק. אם אינך מקבל תוצאות מקובלות, נסה לבקש מהמשתמש לצלם מחדש את התמונה.

כיוון הפנים יחסית למצלמה יכול להשפיע גם על אילו תכונות פנים ML Kit מזהה. ראה מושגים זיהוי פנים .

1. הגדר את גלאי הפנים

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

הגדרות
performanceMode fast (ברירת מחדל) | accurate

העדיפו מהירות או דיוק בעת זיהוי פנים.

landmarkMode none (ברירת מחדל) | all

האם לנסות לזהות את "ציוני הדרך" בפנים - עיניים, אוזניים, אף, לחיים, פה - של כל הפנים שזוהו.

contourMode none (ברירת מחדל) | all

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

classificationMode none (ברירת מחדל) | all

אם לסווג פנים לקטגוריות כמו "מחייך" ו"עיניים פקוחות ".

minFaceSize CGFloat (ברירת מחדל: 0.1 )

הגודל המינימלי, יחסית לתמונה, של פנים לאיתור.

isTrackingEnabled false (ברירת מחדל) | true

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

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

לדוגמה, לבנות VisionFaceDetectorOptions אובייקט כמו אחת הדוגמאות הבאות:

מָהִיר

// High-accuracy landmark detection and face classification
let options = VisionFaceDetectorOptions()
options.performanceMode = .accurate
options.landmarkMode = .all
options.classificationMode = .all

// Real-time contour detection of multiple faces
let options = VisionFaceDetectorOptions()
options.contourMode = .all

Objective-C

// High-accuracy landmark detection and face classification
FIRVisionFaceDetectorOptions *options = [[FIRVisionFaceDetectorOptions alloc] init];
options.performanceMode = FIRVisionFaceDetectorPerformanceModeAccurate;
options.landmarkMode = FIRVisionFaceDetectorLandmarkModeAll;
options.classificationMode = FIRVisionFaceDetectorClassificationModeAll;

// Real-time contour detection of multiple faces
FIRVisionFaceDetectorOptions *options = [[FIRVisionFaceDetectorOptions alloc] init];
options.contourMode = FIRVisionFaceDetectorContourModeAll;

2. הפעל את גלאי הפנים

כדי לזהות פרצופים בתמונה, להעביר את התמונה כקובץ UIImage או CMSampleBufferRef אל VisionFaceDetector של detect(in:) השיטה:

  1. קבל מופע של VisionFaceDetector :

    מָהִיר

    lazy var vision = Vision.vision()
    
    let faceDetector = vision.faceDetector(options: options)
    

    Objective-C

    FIRVision *vision = [FIRVision vision];
    FIRVisionFaceDetector *faceDetector = [vision faceDetector];
    // Or, to change the default settings:
    // FIRVisionFaceDetector *faceDetector =
    //     [vision faceDetectorWithOptions:options];
    
  2. צור VisionImage אובייקט באמצעות UIImage או CMSampleBufferRef .

    כדי להשתמש UIImage :

    1. במידת הצורך, לסובב את התמונה כך שלה imageOrientation הנכס הוא .up .
    2. צור VisionImage אובייקט באמצעות כראוי-המסובב UIImage . לא ציין סיבוב מטה-ערך ברירת המחדל, .topLeft , חייב לשמש.

      מָהִיר

      let image = VisionImage(image: uiImage)

      Objective-C

      FIRVisionImage *image = [[FIRVisionImage alloc] initWithImage:uiImage];

    כדי להשתמש CMSampleBufferRef :

    1. צור VisionImageMetadata אובייקט המציין את הכיוון של נתוני תמונה הכלול CMSampleBufferRef חיץ.

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

      מָהִיר

      func imageOrientation(
          deviceOrientation: UIDeviceOrientation,
          cameraPosition: AVCaptureDevice.Position
          ) -> VisionDetectorImageOrientation {
          switch deviceOrientation {
          case .portrait:
              return cameraPosition == .front ? .leftTop : .rightTop
          case .landscapeLeft:
              return cameraPosition == .front ? .bottomLeft : .topLeft
          case .portraitUpsideDown:
              return cameraPosition == .front ? .rightBottom : .leftBottom
          case .landscapeRight:
              return cameraPosition == .front ? .topRight : .bottomRight
          case .faceDown, .faceUp, .unknown:
              return .leftTop
          }
      }

      Objective-C

      - (FIRVisionDetectorImageOrientation)
          imageOrientationFromDeviceOrientation:(UIDeviceOrientation)deviceOrientation
                                 cameraPosition:(AVCaptureDevicePosition)cameraPosition {
        switch (deviceOrientation) {
          case UIDeviceOrientationPortrait:
            if (cameraPosition == AVCaptureDevicePositionFront) {
              return FIRVisionDetectorImageOrientationLeftTop;
            } else {
              return FIRVisionDetectorImageOrientationRightTop;
            }
          case UIDeviceOrientationLandscapeLeft:
            if (cameraPosition == AVCaptureDevicePositionFront) {
              return FIRVisionDetectorImageOrientationBottomLeft;
            } else {
              return FIRVisionDetectorImageOrientationTopLeft;
            }
          case UIDeviceOrientationPortraitUpsideDown:
            if (cameraPosition == AVCaptureDevicePositionFront) {
              return FIRVisionDetectorImageOrientationRightBottom;
            } else {
              return FIRVisionDetectorImageOrientationLeftBottom;
            }
          case UIDeviceOrientationLandscapeRight:
            if (cameraPosition == AVCaptureDevicePositionFront) {
              return FIRVisionDetectorImageOrientationTopRight;
            } else {
              return FIRVisionDetectorImageOrientationBottomRight;
            }
          default:
            return FIRVisionDetectorImageOrientationTopLeft;
        }
      }

      לאחר מכן, צור את אובייקט המטא -נתונים:

      מָהִיר

      let cameraPosition = AVCaptureDevice.Position.back  // Set to the capture device you used.
      let metadata = VisionImageMetadata()
      metadata.orientation = imageOrientation(
          deviceOrientation: UIDevice.current.orientation,
          cameraPosition: cameraPosition
      )

      Objective-C

      FIRVisionImageMetadata *metadata = [[FIRVisionImageMetadata alloc] init];
      AVCaptureDevicePosition cameraPosition =
          AVCaptureDevicePositionBack;  // Set to the capture device you used.
      metadata.orientation =
          [self imageOrientationFromDeviceOrientation:UIDevice.currentDevice.orientation
                                       cameraPosition:cameraPosition];
    2. צור VisionImage אובייקט באמצעות CMSampleBufferRef האובייקט ואת מטה סיבוב:

      מָהִיר

      let image = VisionImage(buffer: sampleBuffer)
      image.metadata = metadata

      Objective-C

      FIRVisionImage *image = [[FIRVisionImage alloc] initWithBuffer:sampleBuffer];
      image.metadata = metadata;
  3. ואז, להעביר את התמונה detect(in:) השיטה:

    מָהִיר

    faceDetector.process(visionImage) { faces, error in
      guard error == nil, let faces = faces, !faces.isEmpty else {
        // ...
        return
      }
    
      // Faces detected
      // ...
    }
    

    Objective-C

    [faceDetector detectInImage:image
                     completion:^(NSArray<FIRVisionFace *> *faces,
                                  NSError *error) {
      if (error != nil) {
        return;
      } else if (faces != nil) {
        // Recognized faces
      }
    }];
    

3. קבל מידע על פרצופים שזוהו

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

מָהִיר

for face in faces {
  let frame = face.frame
  if face.hasHeadEulerAngleY {
    let rotY = face.headEulerAngleY  // Head is rotated to the right rotY degrees
  }
  if face.hasHeadEulerAngleZ {
    let rotZ = face.headEulerAngleZ  // Head is rotated upward rotZ degrees
  }

  // If landmark detection was enabled (mouth, ears, eyes, cheeks, and
  // nose available):
  if let leftEye = face.landmark(ofType: .leftEye) {
    let leftEyePosition = leftEye.position
  }

  // If contour detection was enabled:
  if let leftEyeContour = face.contour(ofType: .leftEye) {
    let leftEyePoints = leftEyeContour.points
  }
  if let upperLipBottomContour = face.contour(ofType: .upperLipBottom) {
    let upperLipBottomPoints = upperLipBottomContour.points
  }

  // If classification was enabled:
  if face.hasSmilingProbability {
    let smileProb = face.smilingProbability
  }
  if face.hasRightEyeOpenProbability {
    let rightEyeOpenProb = face.rightEyeOpenProbability
  }

  // If face tracking was enabled:
  if face.hasTrackingID {
    let trackingId = face.trackingID
  }
}

Objective-C

for (FIRVisionFace *face in faces) {
  // Boundaries of face in image
  CGRect frame = face.frame;

  if (face.hasHeadEulerAngleY) {
    CGFloat rotY = face.headEulerAngleY;  // Head is rotated to the right rotY degrees
  }
  if (face.hasHeadEulerAngleZ) {
    CGFloat rotZ = face.headEulerAngleZ;  // Head is tilted sideways rotZ degrees
  }

  // If landmark detection was enabled (mouth, ears, eyes, cheeks, and
  // nose available):
  FIRVisionFaceLandmark *leftEar = [face landmarkOfType:FIRFaceLandmarkTypeLeftEar];
  if (leftEar != nil) {
    FIRVisionPoint *leftEarPosition = leftEar.position;
  }

  // If contour detection was enabled:
  FIRVisionFaceContour *upperLipBottomContour = [face contourOfType:FIRFaceContourTypeUpperLipBottom];
  if (upperLipBottomContour != nil) {
    NSArray<FIRVisionPoint *> *upperLipBottomPoints = upperLipBottomContour.points;
    if (upperLipBottomPoints.count > 0) {
      NSLog("Detected the bottom contour of the subject's upper lip.")
    }
  }

  // If classification was enabled:
  if (face.hasSmilingProbability) {
    CGFloat smileProb = face.smilingProbability;
  }
  if (face.hasRightEyeOpenProbability) {
    CGFloat rightEyeOpenProb = face.rightEyeOpenProbability;
  }

  // If face tracking was enabled:
  if (face.hasTrackingID) {
    NSInteger trackingID = face.trackingID;
  }
}

דוגמה לקווי מתאר פנים

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

התמונה הבאה ממחישה כיצד נקודות אלה ממפות לפנים (לחץ על התמונה להגדלה):

זיהוי פנים בזמן אמת

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

  • הגדר את גלאי הפנים להשתמש או איתור קונטור הפנים או איתור סיווג ציון דרך, אך לא את שניהם:

    זיהוי קווי מתאר
    איתור ציון דרך
    מִיוּן
    איתור וסיווג ציוני דרך
    איתור קווי מתאר וזיהוי ציון דרך
    איתור וסיווג קווי המתאר
    זיהוי קווי מתאר, איתור ציון דרך וסיווג

  • אפשר fast מצב (מופעל כברירת מחדל).

  • שקול לצלם תמונות ברזולוציה נמוכה יותר. עם זאת, זכור גם את דרישות מימד התמונה של ה- API הזה.

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