Détecter des visages avec ML Kit sur iOS

Vous pouvez utiliser ML Kit pour détecter des visages dans des images et des vidéos.

Avant de commencer

  1. Si vous n'avez pas encore ajouté Firebase à votre application, suivez les les étapes décrites dans le guide de démarrage.
  2. Incluez les bibliothèques ML Kit dans votre 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'
    
    Après avoir installé ou mis à jour les pods de votre projet, ouvrez votre Xcode projet à l'aide de son .xcworkspace.
  3. Dans votre application, importez Firebase:

    Swift

    import Firebase

    Objective-C

    @import Firebase;

Consignes pour les images d'entrée

Pour que ML Kit détecte les visages avec précision, les images d'entrée doivent contenir des visages représentées par suffisamment de données de pixels. En général, chaque visage que vous souhaitez à détecter dans une image doivent être d'au moins 100 x 100 pixels. Si vous souhaitez détecter les contours des visages, ML Kit nécessite une entrée de résolution supérieure : chaque visage doit mesurer au moins 200 x 200 pixels.

Si vous détectez des visages dans une application en temps réel, vous pouvez également pour prendre en compte les dimensions globales des images d'entrée. Les images plus petites peuvent être sont traitées plus rapidement. Pour réduire la latence, capturez des images à des résolutions inférieures. (en tenant compte des critères de précision ci-dessus) et assurez-vous que le visage du sujet occupe le plus d'espace possible dans l'image. Consultez également Conseils pour améliorer les performances en temps réel.

Une mise au point médiocre peut nuire à la précision. Si vous n'obtenez pas de résultats acceptables, essayez de demander à l'utilisateur de reprendre l'image.

L'orientation d'un visage par rapport à l'appareil photo peut aussi avoir une incidence sur le comportement détecte les caractéristiques détectées par ML Kit. Consultez la section Concepts de la détection des visages.

1. Configurer le détecteur de visages

Avant d'appliquer la détection de visage à une image, si vous souhaitez modifier l'un des paramètres par défaut du détecteur de visage, spécifiez-le avec un objet VisionFaceDetectorOptions. Vous pouvez modifier les paramètres suivants:

Paramètres
performanceMode fast (par défaut) | accurate

Privilégiez la vitesse ou la précision lors de la détection des visages.

landmarkMode none (par défaut) | all

Essayer de détecter ou non les "points de repère" du visage (yeux, les oreilles, le nez, les joues, la bouche... de tous les visages détectés.

contourMode none (par défaut) | all

Indique s'il faut détecter les contours des traits du visage. Les contours sont détecté uniquement pour le visage le plus proéminent d'une image.

classificationMode none (par défaut) | all

Indique si les visages doivent être classés ou non en catégories telles que "sourire" et "yeux ouverts".

minFaceSize CGFloat (par défaut : 0.1)

Taille minimale des visages à détecter, par rapport à l'image.

isTrackingEnabled false (par défaut) | true

Permet d'attribuer ou non aux visages un ID qui peut être utilisé pour suivre visages sur les images.

Notez que lorsque la détection des contours est activée, un seul visage est détecté, le suivi des visages ne produit donc pas de résultats utiles. Pour cette et pour améliorer la vitesse de détection, n'activez pas les deux et le suivi des visages.

Par exemple, créez un VisionFaceDetectorOptions comme dans l'un des exemples suivants:

Swift

// 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. Lancer le détecteur de visages

Pour détecter des visages dans une image, transmettez l'image en tant que UIImage ou CMSampleBufferRef à la méthode detect(in:) de VisionFaceDetector :

  1. Obtenez une instance de VisionFaceDetector:

    Swift

    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. Créez un objet VisionImage à l'aide d'un UIImage ou d'un CMSampleBufferRef

    Pour utiliser un UIImage:

    1. Si nécessaire, faites pivoter l'image de sorte que son imageOrientation est .up.
    2. Créez un objet VisionImage à l'aide de l'UIImage correctement orienté. Ne spécifiez aucune métadonnées de rotation. La valeur par défaut, .topLeft, doit être utilisée.

      Swift

      let image = VisionImage(image: uiImage)

      Objective-C

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

    Pour utiliser une CMSampleBufferRef :

    1. Créez un objet VisionImageMetadata qui spécifie le l'orientation des données d'image contenues dans le Mémoire tampon CMSampleBufferRef.

      Pour obtenir l'orientation de l'image :

      Swift

      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;
        }
      }

      Créez ensuite l'objet de métadonnées :

      Swift

      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. Créez un objet VisionImage à l'aide de l'objet CMSampleBufferRef et des métadonnées de rotation :

      Swift

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

      Objective-C

      FIRVisionImage *image = [[FIRVisionImage alloc] initWithBuffer:sampleBuffer];
      image.metadata = metadata;
  3. Transmettez ensuite l'image à la méthode detect(in:):

    Swift

    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. Obtenir des informations sur les visages détectés

Si l'opération de détection de visage aboutit, le détecteur de visage transmet un tableau d'objets VisionFace au gestionnaire de finalisation. Chaque objet VisionFace représente un visage détecté dans l'image. Pour chaque face, vous pouvez obtenir ses coordonnées de délimitation dans l'image d'entrée, ainsi que toute autre information que vous avez configuré le détecteur de visages. Exemple :

Swift

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;
  }
}

Exemple de contours du visage

Lorsque la détection des contours du visage est activée, vous obtenez une liste de points pour chaque caractéristique du visage qui a été détectée. Ces points représentent la forme . Pour en savoir plus sur la représentation des contours, consultez la présentation des concepts de détection des visages.

L'image suivante illustre la correspondance entre ces points et une face (cliquez sur l'icône image à agrandir):

Détection de visages en temps réel

Si vous souhaitez utiliser la détection de visages dans une application en temps réel, suivez ces pour obtenir des fréquences d'images optimales:

  • Configurez le détecteur de visages pour utiliser la détection ou la classification du contour du visage et la détection de points de repère, mais pas les deux:

    Détection de contours
    Détection de points de repère
    Classification
    Détection et classification des points de repère
    Détection de contours et de points de repère
    Détection et classification de contours
    Détection de contours, détection de points de repère et classification

  • Activez le mode fast (activé par défaut).

  • Envisagez de capturer des images à une résolution plus faible. Cependant, gardez aussi à l'esprit aux exigences de cette API concernant les dimensions de l'image.

  • Limiter les appels au détecteur. Si une nouvelle image vidéo devient disponible pendant l'exécution du détecteur, supprimez la trame.
  • Si vous utilisez la sortie du détecteur pour superposer des images l'image d'entrée, récupérez d'abord le résultat à partir de ML Kit, puis effectuez le rendu de l'image. et les superposer en une seule étape. Cela vous permet d'afficher sur la surface d'affichage une seule fois pour chaque trame d'entrée. Consultez la vue previewOverlayView. et FIRDetectionOverlayView dans l'application exemple Showcase.