Buka konsol

Mendeteksi Wajah dengan ML Kit di Android

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

Lihat sampel panduan memulai ML Kit di GitHub untuk mengetahui contoh penggunaan API ini.

Sebelum memulai

  1. Tambahkan Firebase ke project Android jika Anda belum melakukannya.
  2. Pada file build.gradle level project, pastikan untuk menyertakan repositori Maven Google di bagian buildscript dan allprojects Anda.
  3. Tambahkan dependensi untuk library Android ML Kit ke file Gradle modul (level aplikasi) (biasanya app/build.gradle):
    dependencies {
      // ...
    
      implementation 'com.google.firebase:firebase-ml-vision:24.0.0'
      // If you want to detect face contours (landmark detection and classification
      // don't require this additional model):
      implementation 'com.google.firebase:firebase-ml-vision-face-model:19.0.0'
    }
    apply plugin: 'com.google.gms.google-services'
    
  4. Opsional tetapi direkomendasikan: Konfigurasikan aplikasi Anda untuk mendownload model ML secara otomatis ke perangkat setelah aplikasi diinstal dari Play Store.

    Untuk melakukannya, tambahkan deklarasi berikut ke file AndroidManifest.xml aplikasi Anda:

    <application ...>
      ...
      <meta-data
          android:name="com.google.firebase.ml.vision.DEPENDENCIES"
          android:value="face" />
      <!-- To use multiple models: android:value="face,model2,model3" -->
    </application>
    
    Jika Anda tidak mengaktifkan download model waktu-instal, model ini akan didownload saat pertama kali Anda menjalankan detektor. Permintaan yang Anda buat sebelum download selesai tidak akan memberikan hasil apa pun.

Input panduan gambar

Agar ML Kit dapat secara akurat mengenali wajah, gambar input harus berisi wajah yang diwakili oleh data piksel yang mencukupi. 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 Anda mendeteksi wajah dalam aplikasi real-time, Anda mungkin perlu mempertimbangkan dimensi gambar input secara keseluruhan. Gambar yang lebih kecil dapat diproses lebih cepat sehingga mengurangi latensi, mengambil gambar dengan resolusi yang lebih rendah (dengan tetap memperhatikan persyaratan akurasi di atas), dan memastikan bahwa wajah subjek menempati gambar seluas mungkin. Baca juga Tips untuk meningkatkan performa real-time.

Fokus gambar yang buruk dapat merusak akurasi. Jika Anda tidak mendapatkan 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 Anda ingin mengubah salah satu setelan default dari detektor wajah sebelum menerapkan deteksi wajah ke suatu gambar, tentukan setelan tersebut dengan objek FirebaseVisionFaceDetectorOptions. Anda dapat mengubah setelan berikut:

Setelan
Mode performa FAST (default) | ACCURATE

Mendukung kecepatan atau akurasi saat mendeteksi wajah.

Deteksi landmark NO_LANDMARKS (default) | ALL_LANDMARKS

Mencoba mengidentifikasi "landmark" wajah atau tidak: mata, telinga, hidung, pipi, mulut.

Deteksi kontur NO_CONTOURS (default) | ALL_CONTOURS

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

Klasifikasikan wajah NO_CLASSIFICATIONS (default) | ALL_CLASSIFICATIONS

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

Ukuran wajah minimum float (default: 0.1f)

Ukuran minimum wajah untuk dideteksi, yang bersifat relatif terhadap gambar.

Aktifkan pelacakan wajah false (default) | true

Menetapkan ID pada wajah atau tidak, yang dapat digunakan untuk melacak wajah di seluruh 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.

Contoh:

Java

// High-accuracy landmark detection and face classification
FirebaseVisionFaceDetectorOptions highAccuracyOpts =
        new FirebaseVisionFaceDetectorOptions.Builder()
                .setPerformanceMode(FirebaseVisionFaceDetectorOptions.ACCURATE)
                .setLandmarkMode(FirebaseVisionFaceDetectorOptions.ALL_LANDMARKS)
                .setClassificationMode(FirebaseVisionFaceDetectorOptions.ALL_CLASSIFICATIONS)
                .build();

// Real-time contour detection of multiple faces
FirebaseVisionFaceDetectorOptions realTimeOpts =
        new FirebaseVisionFaceDetectorOptions.Builder()
                .setContourMode(FirebaseVisionFaceDetectorOptions.ALL_CONTOURS)
                .build();

Kotlin

// High-accuracy landmark detection and face classification
val highAccuracyOpts = FirebaseVisionFaceDetectorOptions.Builder()
        .setPerformanceMode(FirebaseVisionFaceDetectorOptions.ACCURATE)
        .setLandmarkMode(FirebaseVisionFaceDetectorOptions.ALL_LANDMARKS)
        .setClassificationMode(FirebaseVisionFaceDetectorOptions.ALL_CLASSIFICATIONS)
        .build()

// Real-time contour detection of multiple faces
val realTimeOpts = FirebaseVisionFaceDetectorOptions.Builder()
        .setContourMode(FirebaseVisionFaceDetectorOptions.ALL_CONTOURS)
        .build()

2. Menjalankan detektor wajah

Untuk mendeteksi wajah dalam gambar, buat objek FirebaseVisionImage dari Bitmap, media.Image, ByteBuffer, array byte, atau file pada perangkat. Lalu, teruskan objek FirebaseVisionImage ke metode detectInImage FirebaseVisionFaceDetector.

Untuk pengenalan wajah, Anda harus menggunakan gambar dengan dimensi yang berukuran minimal 480x360 piksel. Jika Anda mengenali wajah dalam aplikasi real-time, pengambilan frame pada resolusi minimum ini dapat membantu mengurangi latensi.

  1. Buat objek FirebaseVisionImage dari gambar Anda.

    • Untuk membuat objek FirebaseVisionImage dari objek media.Image, misalnya saat mengambil gambar dari kamera perangkat, teruskan objek media.Image dan rotasi gambar ke FirebaseVisionImage.fromMediaImage().

      Jika Anda menggunakan library CameraX, class OnImageCapturedListener dan ImageAnalysis.Analyzer akan menghitung nilai rotasi untuk Anda. Jadi, Anda hanya perlu mengubah rotasi ke salah satu konstanta ROTATION_ ML Kit sebelum memanggil FirebaseVisionImage.fromMediaImage():

      Java

      private class YourAnalyzer implements ImageAnalysis.Analyzer {
      
          private int degreesToFirebaseRotation(int degrees) {
              switch (degrees) {
                  case 0:
                      return FirebaseVisionImageMetadata.ROTATION_0;
                  case 90:
                      return FirebaseVisionImageMetadata.ROTATION_90;
                  case 180:
                      return FirebaseVisionImageMetadata.ROTATION_180;
                  case 270:
                      return FirebaseVisionImageMetadata.ROTATION_270;
                  default:
                      throw new IllegalArgumentException(
                              "Rotation must be 0, 90, 180, or 270.");
              }
          }
      
          @Override
          public void analyze(ImageProxy imageProxy, int degrees) {
              if (imageProxy == null || imageProxy.getImage() == null) {
                  return;
              }
              Image mediaImage = imageProxy.getImage();
              int rotation = degreesToFirebaseRotation(degrees);
              FirebaseVisionImage image =
                      FirebaseVisionImage.fromMediaImage(mediaImage, rotation);
              // Pass image to an ML Kit Vision API
              // ...
          }
      }
      

      Kotlin

      private class YourImageAnalyzer : ImageAnalysis.Analyzer {
          private fun degreesToFirebaseRotation(degrees: Int): Int = when(degrees) {
              0 -> FirebaseVisionImageMetadata.ROTATION_0
              90 -> FirebaseVisionImageMetadata.ROTATION_90
              180 -> FirebaseVisionImageMetadata.ROTATION_180
              270 -> FirebaseVisionImageMetadata.ROTATION_270
              else -> throw Exception("Rotation must be 0, 90, 180, or 270.")
          }
      
          override fun analyze(imageProxy: ImageProxy?, degrees: Int) {
              val mediaImage = imageProxy?.image
              val imageRotation = degreesToFirebaseRotation(degrees)
              if (mediaImage != null) {
                  val image = FirebaseVisionImage.fromMediaImage(mediaImage, imageRotation)
                  // Pass image to an ML Kit Vision API
                  // ...
              }
          }
      }
      

      Jika Anda tidak menggunakan library kamera yang memberi rotasi gambar, Anda dapat menghitungnya dari rotasi perangkat dan orientasi sensor kamera pada perangkat:

      Java

      private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
      static {
          ORIENTATIONS.append(Surface.ROTATION_0, 90);
          ORIENTATIONS.append(Surface.ROTATION_90, 0);
          ORIENTATIONS.append(Surface.ROTATION_180, 270);
          ORIENTATIONS.append(Surface.ROTATION_270, 180);
      }
      
      /**
       * Get the angle by which an image must be rotated given the device's current
       * orientation.
       */
      @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
      private int getRotationCompensation(String cameraId, Activity activity, Context context)
              throws CameraAccessException {
          // Get the device's current rotation relative to its "native" orientation.
          // Then, from the ORIENTATIONS table, look up the angle the image must be
          // rotated to compensate for the device's rotation.
          int deviceRotation = activity.getWindowManager().getDefaultDisplay().getRotation();
          int rotationCompensation = ORIENTATIONS.get(deviceRotation);
      
          // On most devices, the sensor orientation is 90 degrees, but for some
          // devices it is 270 degrees. For devices with a sensor orientation of
          // 270, rotate the image an additional 180 ((270 + 270) % 360) degrees.
          CameraManager cameraManager = (CameraManager) context.getSystemService(CAMERA_SERVICE);
          int sensorOrientation = cameraManager
                  .getCameraCharacteristics(cameraId)
                  .get(CameraCharacteristics.SENSOR_ORIENTATION);
          rotationCompensation = (rotationCompensation + sensorOrientation + 270) % 360;
      
          // Return the corresponding FirebaseVisionImageMetadata rotation value.
          int result;
          switch (rotationCompensation) {
              case 0:
                  result = FirebaseVisionImageMetadata.ROTATION_0;
                  break;
              case 90:
                  result = FirebaseVisionImageMetadata.ROTATION_90;
                  break;
              case 180:
                  result = FirebaseVisionImageMetadata.ROTATION_180;
                  break;
              case 270:
                  result = FirebaseVisionImageMetadata.ROTATION_270;
                  break;
              default:
                  result = FirebaseVisionImageMetadata.ROTATION_0;
                  Log.e(TAG, "Bad rotation value: " + rotationCompensation);
          }
          return result;
      }

      Kotlin

      private val ORIENTATIONS = SparseIntArray()
      
      init {
          ORIENTATIONS.append(Surface.ROTATION_0, 90)
          ORIENTATIONS.append(Surface.ROTATION_90, 0)
          ORIENTATIONS.append(Surface.ROTATION_180, 270)
          ORIENTATIONS.append(Surface.ROTATION_270, 180)
      }/**
       * Get the angle by which an image must be rotated given the device's current
       * orientation.
       */
      @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
      @Throws(CameraAccessException::class)
      private fun getRotationCompensation(cameraId: String, activity: Activity, context: Context): Int {
          // Get the device's current rotation relative to its "native" orientation.
          // Then, from the ORIENTATIONS table, look up the angle the image must be
          // rotated to compensate for the device's rotation.
          val deviceRotation = activity.windowManager.defaultDisplay.rotation
          var rotationCompensation = ORIENTATIONS.get(deviceRotation)
      
          // On most devices, the sensor orientation is 90 degrees, but for some
          // devices it is 270 degrees. For devices with a sensor orientation of
          // 270, rotate the image an additional 180 ((270 + 270) % 360) degrees.
          val cameraManager = context.getSystemService(CAMERA_SERVICE) as CameraManager
          val sensorOrientation = cameraManager
                  .getCameraCharacteristics(cameraId)
                  .get(CameraCharacteristics.SENSOR_ORIENTATION)!!
          rotationCompensation = (rotationCompensation + sensorOrientation + 270) % 360
      
          // Return the corresponding FirebaseVisionImageMetadata rotation value.
          val result: Int
          when (rotationCompensation) {
              0 -> result = FirebaseVisionImageMetadata.ROTATION_0
              90 -> result = FirebaseVisionImageMetadata.ROTATION_90
              180 -> result = FirebaseVisionImageMetadata.ROTATION_180
              270 -> result = FirebaseVisionImageMetadata.ROTATION_270
              else -> {
                  result = FirebaseVisionImageMetadata.ROTATION_0
                  Log.e(TAG, "Bad rotation value: $rotationCompensation")
              }
          }
          return result
      }

      Kemudian, teruskan objek media.Image dan nilai rotasi ke FirebaseVisionImage.fromMediaImage():

      Java

      FirebaseVisionImage image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation);

      Kotlin

      val image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation)
    • Untuk membuat objek FirebaseVisionImage dari URI file, teruskan konteks aplikasi dan URI file ke FirebaseVisionImage.fromFilePath(). Hal ini berguna saat Anda menggunakan intent ACTION_GET_CONTENT untuk meminta pengguna memilih gambar dari aplikasi galeri mereka.

      Java

      FirebaseVisionImage image;
      try {
          image = FirebaseVisionImage.fromFilePath(context, uri);
      } catch (IOException e) {
          e.printStackTrace();
      }

      Kotlin

      val image: FirebaseVisionImage
      try {
          image = FirebaseVisionImage.fromFilePath(context, uri)
      } catch (e: IOException) {
          e.printStackTrace()
      }
    • Untuk membuat objek FirebaseVisionImage dari ByteBuffer atau array byte, pertama-tama hitung rotasi gambar seperti yang dijelaskan di atas untuk input media.Image.

      Lalu, buat objek FirebaseVisionImageMetadata yang berisi tinggi, lebar, format encoding warna, dan rotasi gambar:

      Java

      FirebaseVisionImageMetadata metadata = new FirebaseVisionImageMetadata.Builder()
              .setWidth(480)   // 480x360 is typically sufficient for
              .setHeight(360)  // image recognition
              .setFormat(FirebaseVisionImageMetadata.IMAGE_FORMAT_NV21)
              .setRotation(rotation)
              .build();

      Kotlin

      val metadata = FirebaseVisionImageMetadata.Builder()
              .setWidth(480) // 480x360 is typically sufficient for
              .setHeight(360) // image recognition
              .setFormat(FirebaseVisionImageMetadata.IMAGE_FORMAT_NV21)
              .setRotation(rotation)
              .build()

      Gunakan buffer atau array, dan objek metadata, untuk membuat objek FirebaseVisionImage:

      Java

      FirebaseVisionImage image = FirebaseVisionImage.fromByteBuffer(buffer, metadata);// Or: FirebaseVisionImage image = FirebaseVisionImage.fromByteArray(byteArray, metadata);

      Kotlin

      val image = FirebaseVisionImage.fromByteBuffer(buffer, metadata)// Or: val image = FirebaseVisionImage.fromByteArray(byteArray, metadata)
    • Untuk membuat objek FirebaseVisionImage dari objek Bitmap:

      Java

      FirebaseVisionImage image = FirebaseVisionImage.fromBitmap(bitmap);

      Kotlin

      val image = FirebaseVisionImage.fromBitmap(bitmap)
      Gambar yang diwakili oleh objek Bitmap harus berposisi tegak, tanpa perlu rotasi tambahan.
  2. Dapatkan instance FirebaseVisionFaceDetector:

    Java

    FirebaseVisionFaceDetector detector = FirebaseVision.getInstance()
            .getVisionFaceDetector(options);

    Kotlin

    val detector = FirebaseVision.getInstance()
            .getVisionFaceDetector(options)
  3. Terakhir, teruskan gambar ke metode detectInImage:

    Java

    Task<List<FirebaseVisionFace>> result =
            detector.detectInImage(image)
                    .addOnSuccessListener(
                            new OnSuccessListener<List<FirebaseVisionFace>>() {
                                @Override
                                public void onSuccess(List<FirebaseVisionFace> faces) {
                                    // Task completed successfully
                                    // ...
                                }
                            })
                    .addOnFailureListener(
                            new OnFailureListener() {
                                @Override
                                public void onFailure(@NonNull Exception e) {
                                    // Task failed with an exception
                                    // ...
                                }
                            });

    Kotlin

    val result = detector.detectInImage(image)
            .addOnSuccessListener { faces ->
                // Task completed successfully
                // ...
            }
            .addOnFailureListener { e ->
                // Task failed with an exception
                // ...
            }

3. Mendapatkan informasi tentang wajah yang terdeteksi

Jika operasi pengenalan wajah berhasil, daftar objek FirebaseVisionFace akan diteruskan ke pemroses yang berhasil. Setiap objek FirebaseVisionFace mewakili wajah yang terdeteksi di 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:

Java

for (FirebaseVisionFace face : faces) {
    Rect bounds = face.getBoundingBox();
    float rotY = face.getHeadEulerAngleY();  // Head is rotated to the right rotY degrees
    float rotZ = face.getHeadEulerAngleZ();  // Head is tilted sideways rotZ degrees

    // If landmark detection was enabled (mouth, ears, eyes, cheeks, and
    // nose available):
    FirebaseVisionFaceLandmark leftEar = face.getLandmark(FirebaseVisionFaceLandmark.LEFT_EAR);
    if (leftEar != null) {
        FirebaseVisionPoint leftEarPos = leftEar.getPosition();
    }

    // If contour detection was enabled:
    List<FirebaseVisionPoint> leftEyeContour =
            face.getContour(FirebaseVisionFaceContour.LEFT_EYE).getPoints();
    List<FirebaseVisionPoint> upperLipBottomContour =
            face.getContour(FirebaseVisionFaceContour.UPPER_LIP_BOTTOM).getPoints();

    // If classification was enabled:
    if (face.getSmilingProbability() != FirebaseVisionFace.UNCOMPUTED_PROBABILITY) {
        float smileProb = face.getSmilingProbability();
    }
    if (face.getRightEyeOpenProbability() != FirebaseVisionFace.UNCOMPUTED_PROBABILITY) {
        float rightEyeOpenProb = face.getRightEyeOpenProbability();
    }

    // If face tracking was enabled:
    if (face.getTrackingId() != FirebaseVisionFace.INVALID_ID) {
        int id = face.getTrackingId();
    }
}

Kotlin

for (face in faces) {
    val bounds = face.boundingBox
    val rotY = face.headEulerAngleY // Head is rotated to the right rotY degrees
    val rotZ = face.headEulerAngleZ // Head is tilted sideways rotZ degrees

    // If landmark detection was enabled (mouth, ears, eyes, cheeks, and
    // nose available):
    val leftEar = face.getLandmark(FirebaseVisionFaceLandmark.LEFT_EAR)
    leftEar?.let {
        val leftEarPos = leftEar.position
    }

    // If contour detection was enabled:
    val leftEyeContour = face.getContour(FirebaseVisionFaceContour.LEFT_EYE).points
    val upperLipBottomContour = face.getContour(FirebaseVisionFaceContour.UPPER_LIP_BOTTOM).points

    // If classification was enabled:
    if (face.smilingProbability != FirebaseVisionFace.UNCOMPUTED_PROBABILITY) {
        val smileProb = face.smilingProbability
    }
    if (face.rightEyeOpenProbability != FirebaseVisionFace.UNCOMPUTED_PROBABILITY) {
        val rightEyeOpenProb = face.rightEyeOpenProbability
    }

    // If face tracking was enabled:
    if (face.trackingId != FirebaseVisionFace.INVALID_ID) {
        val id = 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 Anda ingin menggunakan deteksi wajah dalam aplikasi real-time, ikuti panduan ini untuk mencapai frekuensi gambar terbaik:

  • Konfigurasikan detektor wajah untuk menggunakan deteksi kontur wajah atau klasifikasi dan deteksi landmark, tetapi tidak keduanya:

    Deteksi kontur
    Deteksi landmark
    Klasifikasi
    Deteksi landmark dan klasifikasi
    Deteksi kontur dan deteksi landmark
    Deteksi kontur dan klasifikasi
    Deteksi kontur, deteksi landmark, 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. Lihat class VisionProcessorBase dalam aplikasi sampel panduan memulai sebagai contoh.
  • 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 CameraSourcePreview dan GraphicOverlay dalam aplikasi sampel panduan memulai sebagai contoh.
  • Jika Anda menggunakan Camera2 API, ambil gambar dalam format ImageFormat.YUV_420_888.

    Jika Anda menggunakan Camera API versi lama, ambil gambar dalam format ImageFormat.NV21.

Langkah berikutnya

Lihat sampel panduan memulai ML Kit di GitHub untuk contoh penggunaan API ini.