Rileva i volti con ML Kit su iOS

Puoi utilizzare ML Kit per rilevare i volti nelle immagini e nei video.

Prima di iniziare

  1. Se non hai già aggiunto Firebase alla tua app, puoi farlo seguendo le istruzioni riportate in passaggi nella Guida introduttiva.
  2. Includi le librerie del kit ML nel tuo 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'
    
    Dopo aver installato o aggiornato i pod del progetto, assicurati di aprire Xcode utilizzando il suo .xcworkspace.
  3. Nell'app, importa Firebase:

    Swift

    import Firebase

    Objective-C

    @import Firebase;

Linee guida per l'immagine di input

Affinché ML Kit possa rilevare accuratamente i volti, le immagini di input devono contenere volti rappresentate da dati pixel sufficienti. In generale, ogni volto che vuoi da rilevare in un'immagine devono essere di almeno 100 x 100 pixel. Se vuoi rilevare i contorni delle facce, ML Kit richiede un input di risoluzione più alta: ogni faccia deve essere di almeno 200 x 200 pixel.

Se rilevi i volti in un'applicazione in tempo reale, potresti anche per considerare le dimensioni complessive delle immagini di input. Le immagini più piccole possono essere elaborati più velocemente. In questo modo, per ridurre la latenza, acquisisci immagini a risoluzioni più basse (tieni presenti i requisiti di accuratezza di cui sopra) e assicurati che il il volto del soggetto occupa la maggior quantità possibile dell'immagine. Consulta anche Suggerimenti per migliorare il rendimento in tempo reale.

Una scarsa messa a fuoco dell'immagine può compromettere la precisione. Se non ottieni risultati accettabili, prova a chiedere all'utente di recuperare l'immagine.

L'orientamento di un volto rispetto alla fotocamera può influire anche sul viso rileva le funzionalità di ML Kit. Consulta Rilevamento facciale Concetti.

1. Configura il rilevatore di volti

Prima di applicare il rilevamento dei volti a un'immagine, se vuoi modificare una delle impostazioni predefinite del rilevatore di volti, specifica tali impostazioni con un VisionFaceDetectorOptions. Puoi modificare le seguenti impostazioni:

Impostazioni
performanceMode fast (predefinito) | accurate

Prediligi la velocità o la precisione nel rilevamento dei volti.

landmarkMode none (predefinito) | all

Se tentare di rilevare i "punti di riferimento" facciali: occhi, orecchie, naso, guance, bocca... di tutti i volti rilevati.

contourMode none (valore predefinito) | all

Se rilevare i contorni dei tratti del viso. I contorni vengono rilevati solo per il volto più prominente in un'immagine.

classificationMode none (predefinito) | all

Se classificare o meno i volti in categorie come "sorriso", e "con gli occhi aperti".

minFaceSize CGFloat (valore predefinito: 0.1)

La dimensione minima dei volti da rilevare in relazione all'immagine.

isTrackingEnabled false (valore predefinito) | true

Se assegnare o meno un ID ai volti, che può essere utilizzato per monitorarli nelle immagini.

Tieni presente che quando il rilevamento del contorno è attivo, viene selezionato un solo volto viene rilevato, quindi il rilevamento dei volti non produce risultati utili. Per questo motivo, e per migliorare la velocità di rilevamento, non attivare sia il rilevamento dei contorni sia il monitoraggio del volto.

Ad esempio, crea una VisionFaceDetectorOptions come in uno dei seguenti esempi:

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. Usa il rilevatore di volti

Per rilevare i volti in un'immagine, passala come UIImage o come CMSampleBufferRef a detect(in:) di VisionFaceDetector :

  1. Recupera un'istanza di 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. Crea un oggetto VisionImage utilizzando un UIImage o un CMSampleBufferRef.

    Per usare un UIImage:

    1. Se necessario, ruota l'immagine in modo che imageOrientation è .up.
    2. Crea un oggetto VisionImage utilizzando il UIImage ruotato correttamente. Non specificare alcun metadato di rotazione (l'impostazione predefinita) è necessario utilizzare il valore .topLeft.

      Swift

      let image = VisionImage(image: uiImage)

      Objective-C

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

    Per usare un CMSampleBufferRef:

    1. Crea un oggetto VisionImageMetadata che specifichi l'orientamento dei dati dell'immagine contenuti buffer CMSampleBufferRef.

      Per ottenere l'orientamento dell'immagine:

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

      Quindi, crea l'oggetto dei metadati:

      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. Crea un oggetto VisionImage utilizzando il metodo Oggetto CMSampleBufferRef e metadati di rotazione:

      Swift

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

      Objective-C

      FIRVisionImage *image = [[FIRVisionImage alloc] initWithBuffer:sampleBuffer];
      image.metadata = metadata;
  3. Quindi, passa l'immagine al metodo 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. Ricevere informazioni sui volti rilevati

Se il rilevamento dei volti ha esito positivo, il rilevatore passa un array di oggetti VisionFace al gestore del completamento. Ogni VisionFace oggetto rappresenta un volto rilevato nell'immagine. Per per ogni faccia, puoi ottenere le coordinate di delimitazione nell'immagine di input, qualsiasi altra informazione trovata dal rilevatore di volti. Ad esempio:

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

Esempio di contorni del viso

Quando il rilevamento del contorno del volto è attivo, viene visualizzato un elenco di punti per ogni caratteristica del volto rilevata. Questi punti rappresentano la forma della caratteristica. Per informazioni dettagliate su come vengono rappresentati i contorni, consulta la Panoramica dei concetti di rilevamento dei volti.

La seguente immagine mostra come questi punti mappano a un volto (fai clic sull'icona immagine da ingrandire):

Rilevamento dei volti in tempo reale

Se vuoi utilizzare il rilevamento dei volti in un'applicazione in tempo reale, segui queste istruzioni linee guida per ottenere le migliori frequenze fotogrammi:

  • Configura il rilevatore di volti in modo da utilizzare il rilevamento del contorno del viso o la classificazione e il rilevamento di punti di riferimento, ma non entrambi:

    Rilevamento contorno
    Rilevamento dei punti di riferimento
    Classificazione
    Rilevamento e classificazione dei punti di riferimento
    Rilevamento dei contorni e dei punti di riferimento
    Rilevamento e classificazione del contorno
    Rilevamento contorni, rilevamento dei punti di riferimento e classificazione

  • Attiva la modalità fast (attiva per impostazione predefinita).

  • Valuta la possibilità di acquisire le immagini a una risoluzione inferiore. Tuttavia, tieni presente requisiti per le dimensioni immagine di questa API.

  • Limita le chiamate al rilevatore. Se un nuovo frame video diventa disponibile mentre il rilevatore è in esecuzione, inseriscilo.
  • Se utilizzi l'output del rilevatore per sovrapporre la grafica all'immagine di input, ottieni prima il risultato da ML Kit, poi esegui il rendering dell'immagine e la sovrapposizione in un unico passaggio. In questo modo, puoi visualizzare i contenuti solo una volta per ogni frame di input. Guarda previewOverlayView. e FIRDetectionOverlayView nell'app di esempio Showcase.