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.

Essayer

Avant de commencer

  1. Incluez les pods ML Kit suivants dans votre Podfile :
    pod 'GoogleMLKit/FaceDetection', '3.2.0'
    
  2. Après avoir installé ou mis à jour les pods de votre projet, ouvrez votre projet Xcode à l'aide de son .xcworkspace. ML Kit est compatible avec Xcode version 12.4 ou ultérieure.

Consignes pour les images d'entrée

Pour la reconnaissance faciale, utilisez une image d'au moins 480 x 360 pixels. Pour que ML Kit puisse détecter 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 pouvez également prendre en compte les dimensions globales des images d'entrée. Les images de petite taille peuvent être traitées plus rapidement. Par conséquent, pour réduire la latence, capturez les images avec des résolutions inférieures, mais tenez compte des exigences de précision ci-dessus et assurez-vous que le visage du sujet occupe autant d'images que possible. Consultez également nos conseils pour améliorer les performances en temps réel.

Une image floue peut également nuire à la précision de cette dernière. Si vous n'obtenez pas de résultats acceptables, demandez à l'utilisateur de recréer l'image.

L'orientation d'un visage par rapport à l'appareil photo peut également influer sur les traits du visage détectés par ML Kit. Consultez la page Concepts de détection des visages.

1. Configurer le détecteur de visage

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

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

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

landmarkMode none (par défaut) | all

Permet d'essayer de détecter les « points de repère » du visage (yeux, oreilles, nez, joues, bouche) sur tous les visages détectés.

contourMode none (par défaut) | all

Permet de détecter les contours des traits du visage. Les contours ne sont détectés que pour le visage le plus visible d'une image.

classificationMode none (par défaut) | all

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

minFaceSize CGFloat (par défaut: 0.1)

Définit la plus petite taille souhaitée de visage, exprimée en tant que ratio de la largeur de la tête par rapport à la largeur de l'image.

isTrackingEnabled false (par défaut) | true

Attribuer ou non un identifiant aux visages, qui permet de suivre les visages dans les images.

Sachez que lorsque la détection de contour est activée, un seul visage est détecté. Le suivi des visages ne produit donc pas de résultats utiles. C'est pourquoi, pour améliorer la vitesse de détection, n'activez pas à la fois la détection des contours et le suivi des visages.

Par exemple, créez un objet FaceDetectorOptions semblable à l'un des exemples suivants:

Swift

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

// Real-time contour detection of multiple faces
// options.contourMode = .all

Objective-C

// High-accuracy landmark detection and face classification
MLKFaceDetectorOptions *options = [[MLKFaceDetectorOptions alloc] init];
options.performanceMode = MLKFaceDetectorPerformanceModeAccurate;
options.landmarkMode = MLKFaceDetectorLandmarkModeAll;
options.classificationMode = MLKFaceDetectorClassificationModeAll;

// Real-time contour detection of multiple faces
// options.contourMode = MLKFaceDetectorContourModeAll;

2. Préparer l'image d'entrée

Pour détecter les visages dans une image, transmettez l'image en tant que UIImage ou CMSampleBufferRef au FaceDetector à l'aide de la méthode process(_:completion:) ou results(in:):

Créez un objet VisionImage à l'aide d'un objet UIImage ou CMSampleBuffer.

Si vous utilisez un UIImage, procédez comme suit:

  • Créez un objet VisionImage avec UIImage. Veillez à indiquer le bon .orientation.

    Swift

    let image = VisionImage(image: UIImage)
    visionImage.orientation = image.imageOrientation

    Objective-C

    MLKVisionImage *visionImage = [[MLKVisionImage alloc] initWithImage:image];
    visionImage.orientation = image.imageOrientation;

Si vous utilisez un CMSampleBuffer, procédez comme suit:

  • Spécifiez l'orientation des données d'image contenues dans CMSampleBuffer.

    Pour obtenir l'orientation de l'image:

    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;
      }
    }
          
  • Créez un objet VisionImage à l'aide de l'objet et de l'orientation 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. Obtenir une instance de FaceDetector

Obtenez une instance de FaceDetector:

Swift

let faceDetector = FaceDetector.faceDetector(options: options)

Objective-C

MLKFaceDetector *faceDetector = [MLKFaceDetector faceDetectorWithOptions:options];
      

4. Traiter l'image

Transmettez ensuite l'image à la méthode process():

Swift

weak var weakSelf = self
faceDetector.process(visionImage) { faces, error in
  guard let strongSelf = weakSelf else {
    print("Self is nil!")
    return
  }
  guard error == nil, let faces = faces, !faces.isEmpty else {
    // ...
    return
  }

  // Faces detected
  // ...
}

Objective-C

[faceDetector processImage:image
                completion:^(NSArray<MLKFace *> *faces,
                             NSError *error) {
  if (error != nil) {
    return;
  }
  if (faces.count > 0) {
    // Recognized faces
  }
}];

5. Obtenir des informations sur les visages détectés

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

Swift

for face in faces {
  let frame = face.frame
  if face.hasHeadEulerAngleX {
    let rotX = face.headEulerAngleX  // Head is rotated to the uptoward rotX degrees
  }
  if face.hasHeadEulerAngleY {
    let rotY = face.headEulerAngleY  // Head is rotated to the right rotY degrees
  }
  if face.hasHeadEulerAngleZ {
    let rotZ = face.headEulerAngleZ  // Head is tilted sideways 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 (MLKFace *face in faces) {
  // Boundaries of face in image
  CGRect frame = face.frame;
  if (face.hasHeadEulerAngleX) {
    CGFloat rotX = face.headEulerAngleX;  // Head is rotated to the upward rotX degrees
  }
  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):
  MLKFaceLandmark *leftEar = [face landmarkOfType:FIRFaceLandmarkTypeLeftEar];
  if (leftEar != nil) {
    MLKVisionPoint *leftEarPosition = leftEar.position;
  }

  // If contour detection was enabled:
  MLKFaceContour *upperLipBottomContour = [face contourOfType:FIRFaceContourTypeUpperLipBottom];
  if (upperLipBottomContour != nil) {
    NSArray<MLKVisionPoint *> *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 de visage

Lorsque la détection du contour du visage est activée, vous obtenez une liste de points pour chaque visage détecté. Ces points représentent la forme de l'élément géographique. Pour en savoir plus sur la représentation des contours, consultez la page Concepts de détection des visages.

L'image suivante montre comment ces points sont mappés à une face. Cliquez sur l'image pour l'agrandir:

exemple de maillage de contours de visage détecté

Détection des visages en temps réel

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

  • Configurez le détecteur de visage de sorte qu'il utilise la détection ou le classement des contours du visage et la détection des points de repère, mais pas les deux:

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

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

  • Envisagez de capturer des images avec une résolution inférieure. Gardez également à l'esprit les exigences de cette API concernant les dimensions d'image.

  • Pour traiter les images vidéo, utilisez l'API synchrone results(in:) du détecteur. Appelez cette méthode à partir de la fonction captureOutput(_, didOutput:from:) de AVCaptureVideoDataOutputSampleBufferDelegate pour obtenir les résultats de manière synchrone à partir d'une image vidéo donnée. Conservez la propriété alwaysDiscardsLateVideoFrames de AVCaptureVideoDataOutput comme true pour limiter les appels au détecteur. Si une nouvelle image vidéo devient disponible pendant l'exécution du détecteur, elle sera supprimée.
  • Si vous utilisez la sortie du détecteur pour superposer des graphiques sur l'image d'entrée, commencez par obtenir le résultat de ML Kit, puis effectuez le rendu de l'image et de la superposition en une seule étape. Ainsi, vous n'affichez la surface d'affichage qu'une seule fois pour chaque trame d'entrée traitée. Pour obtenir un exemple, consultez la section updatePreviewOverlayViewWithLastFrame dans l'exemple de démarrage rapide de ML Kit.