Mendeteksi Wajah dengan ML Kit di iOS

Anda dapat menggunakan ML Kit untuk mendeteksi wajah dalam gambar dan video.

Sebelum memulai

  1. Jika belum menambahkan Firebase ke aplikasi, lakukan dengan mengikuti langkah-langkah di panduan memulai.
  2. Sertakan library ML Kit di Podfile Anda:
    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'
    
    Setelah menginstal atau mengupdate Pod project, pastikan untuk membuka project Xcode menggunakan .xcworkspace-nya.
  3. Di aplikasi Anda, impor Firebase:

    Swift

    import Firebase

    Objective-C

    @import Firebase;

Pedoman gambar input

Agar ML Kit dapat secara akurat mengenali wajah, gambar input harus berisi wajah yang diwakili oleh data piksel yang memadai. Secara umum, setiap wajah yang ingin dideteksi dalam suatu gambar harus berukuran minimal 100x100 piksel. Jika Anda ingin mendeteksi kontur wajah, ML Kit membutuhkan input resolusi yang lebih tinggi: setiap wajah harus berukuran minimal 200x200 piksel.

Jika ingin mendeteksi wajah dalam aplikasi real-time, Anda mungkin perlu mempertimbangkan dimensi gambar input secara keseluruhan. Gambar yang lebih kecil dapat diproses lebih cepat. Jadi, untuk mengurangi latensi, ambil gambar dengan resolusi yang lebih rendah (dengan tetap memperhatikan persyaratan akurasi di atas), dan pastikan bahwa wajah subjek menempati gambar seluas mungkin. Baca juga Tips untuk meningkatkan performa real-time.

Fokus gambar yang buruk dapat mengurangi akurasi. Jika tidak memperoleh hasil yang dapat diterima, coba minta pengguna untuk mengambil ulang gambar.

Orientasi wajah terhadap arah kamera juga dapat memengaruhi fitur wajah yang terdeteksi oleh ML Kit. Baca Konsep Deteksi Wajah.

1. Mengonfigurasi detektor wajah

Jika ingin mengubah salah satu setelan default detektor wajah sebelum menerapkan deteksi wajah ke suatu gambar, tentukan setelan tersebut dengan objek VisionFaceDetectorOptions. Anda dapat mengubah setelan berikut:

Setelan
performanceMode fast (default) | accurate

Mendukung kecepatan atau akurasi saat mendeteksi wajah.

landmarkMode none (default) | all

Mencoba mendeteksi "struktur" wajah (mata, telinga, hidung, pipi, mulut) pada semua wajah yang terdeteksi atau tidak.

contourMode none (default) | all

Mencoba mendeteksi kontur fitur wajah atau tidak. Kontur dideteksi hanya untuk wajah yang paling tampil beda dalam suatu gambar.

classificationMode none (default) | all

Mengklasifikasi wajah menjadi beberapa kategori atau tidak, seperti "tersenyum" dan "mata terbuka".

minFaceSize CGFloat (default: 0.1)

Ukuran minimum wajah yang ingin dideteksi dibandingkan ukuran gambar.

isTrackingEnabled false (default) | true

Menetapkan ID pada wajah atau tidak, yang dapat digunakan untuk melacak wajah di banyak gambar.

Perlu diperhatikan bahwa hanya satu wajah yang terdeteksi jika deteksi kontur diaktifkan, sehingga pelacakan wajah tidak memberikan hasil yang memuaskan. Karena alasan ini, dan untuk meningkatkan kecepatan deteksi, jangan aktifkan deteksi kontur maupun pelacakan wajah.

Misalnya, buat objek VisionFaceDetectorOptions seperti salah satu contoh berikut:

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. Menjalankan detektor wajah

Untuk mendeteksi wajah dalam gambar, teruskan gambar tersebut sebagai UIImage atau CMSampleBufferRef ke metode detect(in:) VisionFaceDetector:

  1. Dapatkan instance 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. Buat objek VisionImage menggunakan UIImage atau CMSampleBufferRef.

    Untuk menggunakan UIImage:

    1. Jika perlu, putar gambar sehingga properti imageOrientation-nya adalah .up.
    2. Buat objek VisionImage menggunakan UIImage yang sudah diputar dengan benar. Jangan tentukan metadata rotasi apa pun—yang harus digunakan adalah nilai default, yaitu .topLeft.

      Swift

      let image = VisionImage(image: uiImage)

      Objective-C

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

    Untuk menggunakan CMSampleBufferRef:

    1. Buat objek VisionImageMetadata yang menentukan orientasi data gambar yang terdapat dalam buffering CMSampleBufferRef.

      Untuk mendapatkan orientasi gambar:

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

      Kemudian, buat objek metadata:

      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. Buat objek VisionImage menggunakan objek CMSampleBufferRef dan metadata rotasi:

      Swift

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

      Objective-C

      FIRVisionImage *image = [[FIRVisionImage alloc] initWithBuffer:sampleBuffer];
      image.metadata = metadata;
  3. Lalu, teruskan gambar ke metode 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. Mendapatkan informasi tentang wajah yang terdeteksi

Jika operasi deteksi wajah berhasil, detektor wajah meneruskan array objek VisionFace ke pengendali penyelesaian. Setiap objek VisionFace mewakili wajah yang terdeteksi dalam gambar. Untuk setiap wajah, Anda bisa mendapatkan koordinat pembatasnya di gambar input, serta informasi lain yang dapat ditemukan oleh detektor wajah sesuai dengan konfigurasi yang Anda tetapkan. Contoh:

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

Contoh kontur wajah

Ketika mengaktifkan deteksi kontur wajah, Anda juga akan melihat sekumpulan titik untuk setiap fitur wajah yang terdeteksi Titik-titik ini mengikuti bentuk fitur wajah. Baca Ringkasan Konsep Deteksi Wajah untuk mengetahui informasi detail tentang cara kontur direpresentasikan.

Gambar berikut mengilustrasikan bagaimana titik-titik ini dipetakan ke wajah (klik gambar untuk memperbesar):

Deteksi wajah real-time

Jika ingin menggunakan deteksi wajah dalam aplikasi real-time, ikuti pedoman ini untuk mencapai frekuensi frame terbaik:

  • Konfigurasi detektor wajah untuk menggunakan deteksi kontur wajah atau klasifikasi dan deteksi struktur, tetapi tidak kedua-duanya:

    Deteksi kontur
    Deteksi struktur
    Klasifikasi
    Deteksi struktur dan klasifikasi
    Deteksi kontur dan deteksi struktur
    Deteksi kontur dan klasifikasi
    Deteksi kontur, deteksi struktur, dan klasifikasi

  • Aktifkan mode fast (diaktifkan secara default).

  • Pertimbangkan untuk mengambil foto dengan resolusi lebih rendah. Namun, perhatikan juga persyaratan dimensi gambar API ini.

  • Batasi panggilan ke detektor. Jika frame video baru tersedia saat detektor sedang berjalan, hapus frame tersebut.
  • Jika Anda menggunakan output detektor untuk menempatkan grafis pada gambar input, pertama-tama dapatkan hasilnya dari ML Kit, lalu render gambar dan tempatkan grafis dalam satu langkah. Dengan demikian, Anda hanya merender ke permukaan tampilan sekali untuk setiap frame input. Lihat class previewOverlayView dan FIRDetectionOverlayView dalam aplikasi contoh showcase untuk mengetahui contohnya.