Wykryj twarze za pomocą ML Kit na iOS

Za pomocą zestawu ML Kit możesz wykrywać twarze na zdjęciach i filmach.

Zanim zaczniesz

  1. Jeśli nie dodałeś jeszcze Firebase do swojej aplikacji, zrób to, wykonując czynności opisane w przewodniku wprowadzającym .
  2. Dołącz biblioteki ML Kit do swojego 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'
    
    Po zainstalowaniu lub zaktualizowaniu Podów swojego projektu pamiętaj o otwarciu projektu Xcode przy użyciu jego .xcworkspace .
  3. W swojej aplikacji zaimportuj Firebase:

    Szybki

    import Firebase

    Cel C

    @import Firebase;

Wytyczne dotyczące obrazu wejściowego

Aby zestaw ML Kit mógł dokładnie wykrywać twarze, obrazy wejściowe muszą zawierać twarze reprezentowane przez wystarczającą ilość danych w pikselach. Ogólnie rzecz biorąc, każda twarz, którą chcesz wykryć na obrazie, powinna mieć wymiary co najmniej 100 x 100 pikseli. Jeśli chcesz wykryć kontury twarzy, ML Kit wymaga wyższej rozdzielczości: każda twarz powinna mieć co najmniej 200x200 pikseli.

Jeśli wykrywasz twarze w aplikacji czasu rzeczywistego, możesz również rozważyć ogólne wymiary obrazów wejściowych. Mniejsze obrazy można przetwarzać szybciej, dlatego aby zmniejszyć opóźnienia, należy rejestrować obrazy w niższych rozdzielczościach (pamiętając o powyższych wymaganiach dotyczących dokładności) i upewnić się, że twarz obiektu zajmuje jak największą część obrazu. Zobacz także Wskazówki dotyczące poprawy wydajności w czasie rzeczywistym .

Słaba ostrość obrazu może zaszkodzić dokładności. Jeśli wyniki nie są akceptowalne, spróbuj poprosić użytkownika o ponowne wykonanie zdjęcia.

Orientacja twarzy względem aparatu może również mieć wpływ na to, jakie cechy twarzy wykrywa ML Kit. Zobacz Pojęcia dotyczące wykrywania twarzy .

1. Skonfiguruj detektor twarzy

Jeśli przed zastosowaniem wykrywania twarzy do obrazu chcesz zmienić dowolne ustawienia domyślne detektora twarzy, określ te ustawienia za pomocą obiektu VisionFaceDetectorOptions . Możesz zmienić następujące ustawienia:

Ustawienia
performanceMode fast (domyślny) | accurate

Preferuj szybkość lub dokładność podczas wykrywania twarzy.

landmarkMode none (domyślnie) | all

Czy podjąć próbę wykrycia „punktów orientacyjnych” twarzy — oczu, uszu, nosa, policzków i ust — wszystkich wykrytych twarzy.

contourMode none (domyślnie) | all

Czy wykrywać kontury rysów twarzy. Kontury są wykrywane tylko dla najbardziej widocznej twarzy na obrazie.

classificationMode none (domyślnie) | all

Określa, czy klasyfikować twarze w kategorie takie jak „uśmiechnięte” i „otwarte oczy”.

minFaceSize CGFloat (domyślnie: 0.1 )

Minimalny rozmiar wykrywanych twarzy w stosunku do obrazu.

isTrackingEnabled false (domyślnie) | true

Określa, czy przypisać twarzom identyfikator, którego można używać do śledzenia twarzy na obrazach.

Należy pamiętać, że gdy włączone jest wykrywanie konturów, wykrywana jest tylko jedna twarz, więc śledzenie twarzy nie daje użytecznych wyników. Z tego powodu oraz w celu zwiększenia szybkości wykrywania nie włączaj jednocześnie wykrywania konturów i śledzenia twarzy.

Na przykład utwórz obiekt VisionFaceDetectorOptions , jak w jednym z poniższych przykładów:

Szybki

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

Cel 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. Uruchom detektor twarzy

Aby wykryć twarze na obrazie, przekaż obraz jako UIImage lub CMSampleBufferRef do metody detect(in:) klasy VisionFaceDetector :

  1. Pobierz instancję VisionFaceDetector :

    Szybki

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

    Cel C

    FIRVision *vision = [FIRVision vision];
    FIRVisionFaceDetector *faceDetector = [vision faceDetector];
    // Or, to change the default settings:
    // FIRVisionFaceDetector *faceDetector =
    //     [vision faceDetectorWithOptions:options];
    
  2. Utwórz obiekt VisionImage przy użyciu UIImage lub CMSampleBufferRef .

    Aby użyć UIImage :

    1. W razie potrzeby obróć obraz tak, aby jego właściwość imageOrientation miała .up .
    2. Utwórz obiekt VisionImage , używając poprawnie obróconego UIImage . Nie określaj żadnych metadanych rotacji — należy użyć wartości domyślnej .topLeft .

      Szybki

      let image = VisionImage(image: uiImage)

      Cel C

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

    Aby użyć CMSampleBufferRef :

    1. Utwórz obiekt VisionImageMetadata , który określa orientację danych obrazu zawartych w buforze CMSampleBufferRef .

      Aby uzyskać orientację obrazu:

      Szybki

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

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

      Następnie utwórz obiekt metadanych:

      Szybki

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

      Cel 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. Utwórz obiekt VisionImage przy użyciu obiektu CMSampleBufferRef i metadanych rotacji:

      Szybki

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

      Cel C

      FIRVisionImage *image = [[FIRVisionImage alloc] initWithBuffer:sampleBuffer];
      image.metadata = metadata;
  3. Następnie przekaż obraz do metody detect(in:) :

    Szybki

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

    Cel C

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

3. Uzyskaj informacje o wykrytych twarzach

Jeśli operacja wykrywania twarzy powiedzie się, detektor twarzy przekazuje tablicę obiektów VisionFace do procedury obsługi zakończenia. Każdy obiekt VisionFace reprezentuje twarz wykrytą na obrazie. Dla każdej twarzy możesz uzyskać współrzędne ograniczające na obrazie wejściowym, a także wszelkie inne informacje, które skonfigurowałeś do wyszukiwania przez wykrywacz twarzy. Na przykład:

Szybki

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

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

Przykład konturów twarzy

Jeśli masz włączone wykrywanie konturu twarzy, otrzymasz listę punktów za każdą wykrytą cechę twarzy. Punkty te reprezentują kształt obiektu. Aby uzyskać szczegółowe informacje na temat sposobu przedstawiania konturów, zobacz Przegląd koncepcji wykrywania twarzy .

Poniższy obraz ilustruje sposób, w jaki te punkty są przypisane do twarzy (kliknij obraz, aby powiększyć):

Wykrywanie twarzy w czasie rzeczywistym

Jeśli chcesz używać wykrywania twarzy w aplikacji czasu rzeczywistego, postępuj zgodnie z poniższymi wskazówkami, aby uzyskać najlepszą liczbę klatek na sekundę:

  • Skonfiguruj wykrywacz twarzy tak, aby korzystał z wykrywania konturu twarzy lub wykrywania klasyfikacji i punktów orientacyjnych, ale nie obu jednocześnie:

    Wykrywanie konturu
    Wykrywanie punktów orientacyjnych
    Klasyfikacja
    Wykrywanie i klasyfikacja zabytków
    Wykrywanie konturów i wykrywanie punktów orientacyjnych
    Wykrywanie i klasyfikacja konturów
    Wykrywanie konturów, wykrywanie punktów orientacyjnych i klasyfikacja

  • Włącz tryb fast (domyślnie włączony).

  • Rozważ przechwytywanie obrazów w niższej rozdzielczości. Należy jednak pamiętać o wymaganiach dotyczących wymiarów obrazu tego interfejsu API.

  • Przepustnica wzywa do detektora. Jeżeli w trakcie działania detektora pojawi się nowa klatka wideo, usuń ją.
  • Jeśli używasz wyjścia detektora do nakładania grafiki na obraz wejściowy, najpierw uzyskaj wynik z ML Kit, a następnie wyrenderuj obraz i nakładkę w jednym kroku. W ten sposób renderujesz na powierzchnię wyświetlacza tylko raz dla każdej klatki wejściowej. Zobacz przykładowe klasy PreviewOverlayView i FIRDetectionOverlayView w przykładowej aplikacji prezentacyjnej.