Catch up on highlights from Firebase at Google I/O 2023. Learn more

Rileva 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, fallo seguendo i passaggi nella Guida introduttiva .
  2. Includi le librerie ML Kit 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 tuo progetto, assicurati di aprire il tuo progetto Xcode usando il suo .xcworkspace .
  3. Nella tua app, importa Firebase:

    Veloce

    import Firebase

    Obiettivo-C

    @import Firebase;

Linee guida per l'immagine di input

Affinché ML Kit rilevi accuratamente i volti, le immagini di input devono contenere volti rappresentati da dati pixel sufficienti. In generale, ogni volto che desideri rilevare in un'immagine deve essere di almeno 100x100 pixel. Se si desidera rilevare i contorni dei volti, ML Kit richiede un input di risoluzione più elevato: ogni volto deve essere di almeno 200x200 pixel.

Se stai rilevando i volti in un'applicazione in tempo reale, potresti anche voler considerare le dimensioni complessive delle immagini di input. Le immagini più piccole possono essere elaborate più velocemente, quindi per ridurre la latenza, acquisire immagini a risoluzioni inferiori (tenendo presente i requisiti di precisione di cui sopra) e assicurarsi che il viso del soggetto occupi la maggior parte dell'immagine possibile. Vedi anche Suggerimenti per migliorare le prestazioni 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 acquisire nuovamente l'immagine.

L'orientamento di un viso rispetto alla fotocamera può anche influenzare le caratteristiche del viso rilevate da ML Kit. Vedere Concetti di rilevamento dei volti .

1. Configurare il rilevatore facciale

Prima di applicare il rilevamento del volto a un'immagine, se si desidera modificare una delle impostazioni predefinite del rilevatore di volti, specificare tali impostazioni con un oggetto VisionFaceDetectorOptions . È possibile modificare le seguenti impostazioni:

Impostazioni
performanceMode fast (predefinito) | accurate

Favorisci velocità o precisione quando rilevi i 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 (predefinito) | all

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

classificationMode none (predefinito) | all

Se classificare o meno i volti in categorie come "sorridenti" e "occhi aperti".

minFaceSize CGFloat (predefinito: 0.1 )

La dimensione minima, relativa all'immagine, dei volti da rilevare.

isTrackingEnabled false (predefinito) | true

Se assegnare o meno ai volti un ID, che può essere utilizzato per tracciare i volti attraverso le immagini.

Si noti che quando il rilevamento del contorno è abilitato, viene rilevata solo una faccia, quindi il rilevamento della faccia non produce risultati utili. Per questo motivo, e per migliorare la velocità di rilevamento, non abilitare sia il rilevamento del contorno che il rilevamento del volto.

Ad esempio, crea un oggetto VisionFaceDetectorOptions come uno dei seguenti esempi:

Veloce

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

Obiettivo-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. Avviare il rilevatore facciale

Per rilevare i volti in un'immagine, passa l'immagine come UIImage o CMSampleBufferRef al VisionFaceDetector di detect(in:) di VisionFaceDetector:

  1. Ottieni un'istanza di VisionFaceDetector :

    Veloce

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

    Obiettivo-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 usando un UIImage o un CMSampleBufferRef .

    Per utilizzare UIImage :

    1. Se necessario, ruota l'immagine in modo che la sua proprietà imageOrientation sia .up .
    2. Crea un oggetto VisionImage utilizzando l' UIImage ruotato correttamente. Non specificare metadati di rotazione: è necessario utilizzare il valore predefinito, .topLeft .

      Veloce

      let image = VisionImage(image: uiImage)

      Obiettivo-C

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

    Per utilizzare un CMSampleBufferRef :

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

      Per ottenere l'orientamento dell'immagine:

      Veloce

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

      Obiettivo-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 metadati:

      Veloce

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

      Obiettivo-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 l'oggetto CMSampleBufferRef e i metadati di rotazione:

      Veloce

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

      Obiettivo-C

      FIRVisionImage *image = [[FIRVisionImage alloc] initWithBuffer:sampleBuffer];
      image.metadata = metadata;
  3. Quindi, passa l'immagine al metodo detect(in:) :

    Veloce

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

    Obiettivo-C

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

3. Ottieni informazioni sui volti rilevati

Se l'operazione di rilevamento del volto ha esito positivo, il rilevatore facciale trasmette una serie di oggetti VisionFace al gestore di completamento. Ogni oggetto VisionFace rappresenta un volto che è stato rilevato nell'immagine. Per ogni volto, puoi ottenere le coordinate di delimitazione nell'immagine di input, così come qualsiasi altra informazione che hai configurato per trovare il rilevatore di volti. Per esempio:

Veloce

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

Obiettivo-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 hai abilitato il rilevamento del contorno del viso, ottieni un elenco di punti per ogni caratteristica del viso che è stata rilevata. Questi punti rappresentano la forma dell'elemento. Consulta la Panoramica sui concetti di rilevamento dei volti per i dettagli su come vengono rappresentati i contorni.

L'immagine seguente illustra come questi punti si associano a una faccia (fare clic sull'immagine per ingrandirla):

Rilevamento dei volti in tempo reale

Se desideri utilizzare il rilevamento dei volti in un'applicazione in tempo reale, segui queste linee guida per ottenere i framerate migliori:

  • Configurare il rilevatore facciale per utilizzare il rilevamento del contorno del viso o la classificazione e il rilevamento del punto di riferimento, ma non entrambi:

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

  • Abilita la modalità fast (abilitata per impostazione predefinita).

  • Prendi in considerazione l'acquisizione di immagini a una risoluzione inferiore. Tuttavia, tieni anche a mente i requisiti della dimensione dell'immagine di questa API.

  • Accelera le chiamate al rilevatore. Se un nuovo fotogramma video diventa disponibile mentre il rilevatore è in funzione, rilasciare il fotogramma.
  • Se si utilizza l'output del rilevatore per sovrapporre la grafica all'immagine di input, ottenere prima il risultato da ML Kit, quindi eseguire il rendering dell'immagine e sovrapporre in un unico passaggio. In questo modo, si esegue il rendering sulla superficie di visualizzazione solo una volta per ciascun frame di input. Per un esempio, vedere le classi previewOverlayView e FIRDetectionOverlayView nell'app di esempio della vetrina.