Détecter les visages avec ML Kit sur iOS

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

Avant que tu commences

  1. Si vous n'avez pas encore ajouté Firebase à votre application, faites-le en suivant les étapes du 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, assurez-vous d'ouvrir votre projet Xcode à l'aide de son .xcworkspace .
  3. Dans votre application, importez Firebase :

    Rapide

    import Firebase

    Objectif c

    @import Firebase;

Directives relatives aux images d'entrée

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

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

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

L'orientation d'un visage par rapport à la caméra peut également affecter les caractéristiques du visage détectées par ML Kit. Voir Concepts de détection de visage .

1. Configurez le détecteur de visage

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 ces paramètres avec un objet VisionFaceDetectorOptions . Vous pouvez modifier les paramètres suivants :

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

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

landmarkMode none (par défaut) | all

S'il faut tenter de détecter les « repères » faciaux (yeux, oreilles, nez, joues, bouche) de tous les visages détectés.

contourMode none (par défaut) | all

Que ce soit pour détecter les contours des traits du visage. Les contours sont détectés uniquement pour le visage le plus visible d'une image.

classificationMode none (par défaut) | all

S'il faut ou non classer les visages en catégories telles que « souriant » et « yeux ouverts ».

minFaceSize CGFloat (par défaut : 0.1 )

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

isTrackingEnabled false (par défaut) | true

S'il faut ou non attribuer aux visages un identifiant, qui peut être utilisé pour suivre les visages sur les images.

Notez que lorsque la détection de contour est activée, un seul visage est détecté, le suivi du visage ne produit donc pas de résultats utiles. Pour cette raison, et pour améliorer la vitesse de détection, n’activez pas à la fois la détection des contours et le suivi du visage.

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

Rapide

// 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

Objectif 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. Exécutez le détecteur de visage

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 :

    Rapide

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

    Objectif 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 une UIImage :

    1. Si nécessaire, faites pivoter l'image pour que sa propriété imageOrientation soit .up .
    2. Créez un objet VisionImage à l'aide du UIImage correctement pivoté. Ne spécifiez aucune métadonnée de rotation : la valeur par défaut, .topLeft , doit être utilisée.

      Rapide

      let image = VisionImage(image: uiImage)

      Objectif c

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

    Pour utiliser un CMSampleBufferRef :

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

      Pour obtenir l'orientation de l'image :

      Rapide

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

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

      Ensuite, créez l'objet de métadonnées :

      Rapide

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

      Objectif 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 :

      Rapide

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

      Objectif c

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

    Rapide

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

    Objectif c

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

3. Obtenez des informations sur les visages détectés

Si l’opération de détection de visage réussit, le détecteur de visage transmet un tableau d’objets VisionFace au gestionnaire d’achèvement. Chaque objet VisionFace représente un visage détecté dans l'image. Pour chaque visage, vous pouvez obtenir ses coordonnées limites dans l'image d'entrée, ainsi que toute autre information que vous avez configurée pour rechercher le détecteur de visage. Par exemple:

Rapide

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

Objectif 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 du contour du visage est activée, vous obtenez une liste de points pour chaque caractéristique du visage détectée. Ces points représentent la forme de l'entité. Consultez la présentation des concepts de détection de visage pour plus de détails sur la façon dont les contours sont représentés.

L'image suivante illustre comment ces points correspondent à un visage (cliquez sur l'image pour l'agrandir) :

Détection des visages en temps réel

Si vous souhaitez utiliser la détection de visage dans une application en temps réel, suivez ces directives pour obtenir les meilleures fréquences d'images :

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

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

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

  • Pensez à capturer des images à une résolution inférieure. Cependant, gardez également à l’esprit les exigences de dimension d’image de cette API.

  • Accélérez les appels au détecteur. Si une nouvelle image vidéo devient disponible pendant le fonctionnement du détecteur, supprimez l'image.
  • Si vous utilisez la sortie du détecteur pour superposer des graphiques sur l'image d'entrée, obtenez d'abord le résultat de ML Kit, puis effectuez le rendu de l'image et la superposition en une seule étape. Ce faisant, vous effectuez le rendu sur la surface d'affichage une seule fois pour chaque image d'entrée. Consultez les classes previewOverlayView et FIRDetectionOverlayView dans l’exemple d’application de présentation pour un exemple.