Wykrywanie twarzy za pomocą ML Kit na iOS

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

Wypróbuj

Zanim zaczniesz

  1. W pliku Podfile uwzględnij te pody ML Kit:
    pod 'GoogleMLKit/FaceDetection', '3.2.0'
    
  2. Po zainstalowaniu lub zaktualizowaniu podów w projekcie otwórz projekt Xcode, korzystając z jego polecenia .xcworkspace. ML Kit obsługuje Xcode w wersji 12.4 lub nowszej.

Zalecenia dotyczące obrazu wejściowego

Do rozpoznawania twarzy użyj obrazu o wymiarach co najmniej 480 x 360 pikseli. Aby narzędzie ML Kit mogło dokładnie wykrywać twarze, obrazy wejściowe muszą zawierać twarze reprezentowane przez wystarczającą ilość danych pikseli. Ogólnie każda twarz, którą chcesz wykryć na obrazie, powinna mieć rozmiar co najmniej 100 x 100 pikseli. Jeśli chcesz wykrywać kontury twarzy, ML Kit wymaga danych wejściowych o wyższej rozdzielczości: każda twarz powinna mieć co najmniej 200 x 200 pikseli.

W przypadku wykrywania twarzy w aplikacji rejestrującej dane w czasie rzeczywistym warto też wziąć pod uwagę ogólne wymiary obrazów wejściowych. Mniejsze obrazy mogą być przetwarzane szybciej, więc jeśli chcesz zmniejszyć opóźnienia, zrób zdjęcia w niższej rozdzielczości, pamiętając o powyższych wymaganiach dotyczących dokładności i upewnij się, że twarz osoby, która znajduje się na zdjęciu, będzie zajmować jak najwięcej miejsca. Zapoznaj się też ze wskazówkami dotyczącymi zwiększania skuteczności w czasie rzeczywistym.

Słaba ostrość obrazu również może wpływać na dokładność. Jeśli nie uzyskasz zadowalających wyników, poproś użytkownika o ponowne zdjęcie obrazu.

Orientacja twarzy względem kamery może też wpływać na to, jakie cechy twarzy wykryje ML Kit. Zobacz Pojęcia związane z wykrywaniem twarzy.

1. Skonfiguruj wykrywanie twarzy

Jeśli chcesz zmienić domyślne ustawienia funkcji wykrywania twarzy, określ je za pomocą obiektu FaceDetectorOptions, zanim zastosujesz wykrywanie twarzy do zdjęcia. Możesz zmienić te ustawienia:

Ustawienia
performanceMode fast (domyślnie) | accurate

Wykrywaj twarze z większą szybkością i dokładnością.

landmarkMode none (domyślnie) | all

Określa, czy ma być podejmowana próba wykrycia „charakterystycznych” elementów twarzy – oczu, uszu, nosa, policzków i ust – wszystkich wykrytych twarzy.

contourMode none (domyślnie) | all

Określa, czy ma wykrywać kontury twarzy. Wykrywanie konturów jest wykrywanych tylko w przypadku najbardziej rzucających się w oczy twarzy na zdjęciu.

classificationMode none (domyślnie) | all

Określa, czy klasyfikować twarze w kategoriach takich jak „uśmiechnięta” i „otwarte oczy”.

minFaceSize CGFloat (domyślnie: 0.1)

Ustawia najmniejszy wymagany rozmiar twarzy wyrażony jako stosunek szerokości głowy do szerokości obrazu.

isTrackingEnabled false (domyślnie) | true

Określa, czy przypisać twarzom identyfikator, który może służyć do śledzenia twarzy na obrazach.

Pamiętaj, że gdy wykrywanie konturu jest włączone, wykrywana jest tylko 1 twarz, więc śledzenie twarzy nie dostarcza przydatnych wyników. Dlatego, aby zwiększyć szybkość wykrywania, nie włączaj jednocześnie wykrywania konturu i śledzenia twarzy.

Utwórz na przykład obiekt FaceDetectorOptions podobny do tych:

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. Przygotuj obraz wejściowy

Aby wykrywać twarze na obrazie, przekaż zdjęcie jako UIImage lub CMSampleBufferRef do funkcji FaceDetector, korzystając z metody process(_:completion:) lub results(in:):

Utwórz obiekt VisionImage za pomocą UIImage lub CMSampleBuffer.

Jeśli używasz urządzenia UIImage, wykonaj te czynności:

  • Utwórz obiekt VisionImage za pomocą UIImage. Pamiętaj, aby podać prawidłową wartość .orientation.

    Swift

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

    Objective-C

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

Jeśli używasz urządzenia CMSampleBuffer, wykonaj te czynności:

  • Określ orientację danych obrazu w elemencie CMSampleBuffer.

    Aby pobrać orientację:

    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;
      }
    }
          
  • Utwórz obiekt VisionImage, używając obiektu i orientacji 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. Pobieranie wystąpienia funkcji FaceDetector

Pobierz wystąpienie FaceDetector:

Swift

let faceDetector = FaceDetector.faceDetector(options: options)

Objective-C

MLKFaceDetector *faceDetector = [MLKFaceDetector faceDetectorWithOptions:options];
      

4. Przetwarzanie obrazu

Następnie przekaż obraz do metody 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. Uzyskiwanie informacji o wykrytych twarzach

Jeśli operacja wykrywania twarzy zakończy się powodzeniem, wzorzec do wykrywania twarzy przekaże do modułu obsługi tablicy liczbę obiektów Face. Każdy obiekt Face reprezentuje twarz wykrytą na obrazie. W przypadku każdej twarzy współrzędne ograniczające są podane na zdjęciu wejściowym oraz wszelkie inne informacje, które zostały wyszukane przez czujnik. Na przykład:

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

Przykład konturów twarzy

Gdy wykrywanie konturów twarzy jest włączone, otrzymujesz listę punktów za każdą wykrytą cechę twarzy. Te punkty reprezentują kształt obiektu. Szczegółowe informacje o tym, jak są przedstawiane kontury, znajdziesz w artykule Pojęcia związane z wykrywaniem twarzy.

Poniższa ilustracja przedstawia sposób mapowania tych punktów na twarz. Kliknij obraz, aby go powiększyć:

przykładowa siatka konturu twarzy

Wykrywanie twarzy w czasie rzeczywistym

Jeśli chcesz używać wykrywania twarzy w aplikacji w czasie rzeczywistym, postępuj zgodnie z tymi wskazówkami, aby uzyskać najlepszą liczbę klatek:

  • Skonfiguruj wykrywacz twarzy tak, aby używał wykrywania konturów twarzy lub klasyfikacji i wykrywania punktów orientacyjnych, ale nie obu naraz:

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

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

  • Rozważ robienie zdjęć w niższej rozdzielczości. Pamiętaj też o wymaganiach dotyczących wymiarów obrazu w tym interfejsie API.

  • Do przetwarzania klatek wideo użyj synchronicznego interfejsu API results(in:) wzorca. Wywołaj tę metodę z funkcji captureOutput(_, didOutput:from:) obiektu AVCaptureVideoDataOutputSampleBufferDelegate, aby synchronicznie pobierać wyniki z danej klatki wideo. Pozostaw alwaysDiscardsLateVideoFrames obiektu AVCaptureVideoDataOutput jako true, aby ograniczać wywołania do wzorca. Jeśli podczas działania wzorca pojawi się nowa ramka wideo, zostanie ona usunięta.
  • Jeśli używasz danych wyjściowych wzorca do nakładania grafiki na obraz wejściowy, najpierw pobierz wynik z ML Kit, a następnie wyrenderuj obraz i nakładkę w jednym kroku. Dzięki temu na każdą przetworzoną klatkę wejściową renderujesz się tylko raz. Przykład znajdziesz w sekcji updatePreviewOverlayViewWithLastFrame w przykładowym krótkim wprowadzeniu do ML Kit.