Erkennen Sie Gesichter mit ML Kit auf Android

Sie können ML Kit verwenden, um Gesichter in Bildern und Videos zu erkennen.

Bevor Sie beginnen

  1. Fügen Sie Ihrem Android-Projekt Firebase hinzu, falls Sie dies noch nicht getan haben .
  2. Fügen Sie die Abhängigkeiten für die ML Kit-Android-Bibliotheken zu Ihrer Modul-Gradle-Datei (auf App-Ebene) hinzu (normalerweise app/build.gradle ):
    apply plugin: 'com.android.application'
    apply plugin: 'com.google.gms.google-services'
    
    dependencies {
      // ...
    
      implementation 'com.google.firebase:firebase-ml-vision:24.0.3'
      // 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:20.0.1'
    }
    
  3. Optional, aber empfohlen : Konfigurieren Sie Ihre App so, dass das ML-Modell automatisch auf das Gerät heruntergeladen wird, nachdem Ihre App aus dem Play Store installiert wurde.

    Fügen Sie dazu die folgende Deklaration zur AndroidManifest.xml -Datei Ihrer App hinzu:

    <application ...>
      ...
      <meta-data
          android:name="com.google.firebase.ml.vision.DEPENDENCIES"
          android:value="face" />
      <!-- To use multiple models: android:value="face,model2,model3" -->
    </application>
    
    Wenn Sie das Herunterladen von Modellen während der Installation nicht aktivieren, wird das Modell heruntergeladen, wenn Sie den Detektor zum ersten Mal ausführen. Anfragen, die Sie stellen, bevor der Download abgeschlossen ist, führen zu keinen Ergebnissen.

Bildrichtlinien eingeben

Damit ML Kit Gesichter genau erkennen kann, müssen Eingabebilder Gesichter enthalten, die durch ausreichend Pixeldaten dargestellt werden. Im Allgemeinen sollte jedes Gesicht, das Sie in einem Bild erkennen möchten, mindestens 100 x 100 Pixel groß sein. Wenn Sie die Konturen von Gesichtern erkennen möchten, erfordert ML Kit eine Eingabe mit höherer Auflösung: Jedes Gesicht sollte mindestens 200 x 200 Pixel groß sein.

Wenn Sie Gesichter in einer Echtzeitanwendung erkennen, sollten Sie möglicherweise auch die Gesamtabmessungen der Eingabebilder berücksichtigen. Kleinere Bilder können schneller verarbeitet werden. Um die Latenz zu reduzieren, nehmen Sie Bilder mit niedrigeren Auflösungen auf (unter Berücksichtigung der oben genannten Genauigkeitsanforderungen) und stellen Sie sicher, dass das Gesicht des Motivs so viel wie möglich vom Bild einnimmt. Siehe auch Tipps zur Verbesserung der Echtzeitleistung .

Ein schlechter Bildfokus kann die Genauigkeit beeinträchtigen. Wenn Sie keine akzeptablen Ergebnisse erzielen, bitten Sie den Benutzer, das Bild erneut aufzunehmen.

Die Ausrichtung eines Gesichts relativ zur Kamera kann sich auch darauf auswirken, welche Gesichtsmerkmale das ML Kit erkennt. Siehe Gesichtserkennungskonzepte .

1. Konfigurieren Sie den Gesichtsdetektor

Wenn Sie die Standardeinstellungen der Gesichtserkennung ändern möchten, bevor Sie die Gesichtserkennung auf ein Bild anwenden, geben Sie diese Einstellungen mit einem FirebaseVisionFaceDetectorOptions -Objekt an. Sie können die folgenden Einstellungen ändern:

Einstellungen
Leistungsmodus FAST (Standard) | ACCURATE

Bevorzugen Sie Geschwindigkeit oder Genauigkeit bei der Erkennung von Gesichtern.

Wahrzeichen erkennen NO_LANDMARKS (Standard) | ALL_LANDMARKS

Ob versucht werden soll, Gesichtsmerkmale zu identifizieren: Augen, Ohren, Nase, Wangen, Mund usw.

Konturen erkennen NO_CONTOURS (Standard) | ALL_CONTOURS

Ob die Konturen von Gesichtszügen erkannt werden sollen. Konturen werden nur für das markanteste Gesicht in einem Bild erkannt.

Gesichter klassifizieren NO_CLASSIFICATIONS (Standard) | ALL_CLASSIFICATIONS

Ob Gesichter in Kategorien wie „lächelnd“ und „offene Augen“ eingeteilt werden sollen oder nicht.

Minimale Gesichtsgröße float (Standard: 0.1f )

Die Mindestgröße der zu erkennenden Gesichter im Verhältnis zum Bild.

Gesichtsverfolgung aktivieren false (Standard) | true

Ob Gesichtern eine ID zugewiesen werden soll oder nicht, die verwendet werden kann, um Gesichter über Bilder hinweg zu verfolgen.

Beachten Sie, dass bei aktivierter Konturerkennung nur ein Gesicht erkannt wird, sodass die Gesichtsverfolgung keine brauchbaren Ergebnisse liefert. Aktivieren Sie aus diesem Grund und zur Verbesserung der Erkennungsgeschwindigkeit nicht sowohl die Konturerkennung als auch die Gesichtsverfolgung.

Zum Beispiel:

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+KTX

// 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. Führen Sie den Gesichtsdetektor aus

Um Gesichter in einem Bild zu erkennen, erstellen Sie ein FirebaseVisionImage -Objekt entweder aus einem Bitmap , media.Image , ByteBuffer , einem Byte-Array oder einer Datei auf dem Gerät. Übergeben Sie dann das FirebaseVisionImage -Objekt an die Methode detectInImage von FirebaseVisionFaceDetector .

Für die Gesichtserkennung sollten Sie ein Bild mit Abmessungen von mindestens 480 x 360 Pixel verwenden. Wenn Sie Gesichter in Echtzeit erkennen, kann das Erfassen von Frames mit dieser Mindestauflösung dazu beitragen, die Latenzzeit zu verringern.

  1. Erstellen Sie ein FirebaseVisionImage -Objekt aus Ihrem Bild.

    • Um ein FirebaseVisionImage -Objekt aus einem media.Image Objekt zu erstellen, beispielsweise beim Erfassen eines Bildes von der Kamera eines Geräts, übergeben Sie das media.Image Objekt und die Drehung des Bilds an FirebaseVisionImage.fromMediaImage() .

      Wenn Sie die CameraX- Bibliothek verwenden, berechnen die Klassen OnImageCapturedListener und ImageAnalysis.Analyzer den Rotationswert für Sie, sodass Sie die Rotation nur in eine der ROTATION_ -Konstanten von ML Kit konvertieren müssen, bevor Sie FirebaseVisionImage.fromMediaImage() aufrufen:

      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+KTX

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

      Wenn Sie keine Kamerabibliothek verwenden, die Ihnen die Drehung des Bildes liefert, können Sie sie aus der Drehung des Geräts und der Ausrichtung des Kamerasensors im Gerät berechnen:

      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+KTX

      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
      }

      Übergeben Sie dann das media.Image Objekt und den Rotationswert an FirebaseVisionImage.fromMediaImage() :

      Java

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

      Kotlin+KTX

      val image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation)
    • Um ein FirebaseVisionImage -Objekt aus einem Datei-URI zu erstellen, übergeben Sie den App-Kontext und den Datei-URI an FirebaseVisionImage.fromFilePath() . Dies ist nützlich, wenn Sie einen ACTION_GET_CONTENT -Intent verwenden, um den Benutzer aufzufordern, ein Bild aus seiner Galerie-App auszuwählen.

      Java

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

      Kotlin+KTX

      val image: FirebaseVisionImage
      try {
          image = FirebaseVisionImage.fromFilePath(context, uri)
      } catch (e: IOException) {
          e.printStackTrace()
      }
    • Um ein FirebaseVisionImage -Objekt aus einem ByteBuffer oder einem Byte-Array zu erstellen, berechnen Sie zunächst die Bilddrehung wie oben für die media.Image Eingabe beschrieben.

      Erstellen Sie dann ein FirebaseVisionImageMetadata -Objekt, das die Höhe, Breite, das Farbcodierungsformat und die Drehung des Bilds enthält:

      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+KTX

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

      Verwenden Sie den Puffer oder das Array und das Metadatenobjekt, um ein FirebaseVisionImage -Objekt zu erstellen:

      Java

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

      Kotlin+KTX

      val image = FirebaseVisionImage.fromByteBuffer(buffer, metadata)
      // Or: val image = FirebaseVisionImage.fromByteArray(byteArray, metadata)
    • So erstellen Sie ein FirebaseVisionImage Objekt aus einem Bitmap Objekt:

      Java

      FirebaseVisionImage image = FirebaseVisionImage.fromBitmap(bitmap);

      Kotlin+KTX

      val image = FirebaseVisionImage.fromBitmap(bitmap)
      Das vom Bitmap -Objekt dargestellte Bild muss aufrecht stehen, ohne dass eine zusätzliche Drehung erforderlich ist.
  2. Rufen Sie eine Instanz von FirebaseVisionFaceDetector :

    Java

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

    Kotlin+KTX

    val detector = FirebaseVision.getInstance()
            .getVisionFaceDetector(options)
  3. Übergeben Sie das Bild schließlich an die Methode 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+KTX

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

3. Erhalten Sie Informationen über erkannte Gesichter

Wenn der Gesichtserkennungsvorgang erfolgreich ist, wird eine Liste von FirebaseVisionFace Objekten an den Erfolgs-Listener übergeben. Jedes FirebaseVisionFace -Objekt stellt ein Gesicht dar, das im Bild erkannt wurde. Für jedes Gesicht können Sie seine Begrenzungskoordinaten im Eingabebild sowie alle anderen Informationen abrufen, die Sie für die Suche des Gesichtsdetektors konfiguriert haben. Zum Beispiel:

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+KTX

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

Beispiel für Gesichtskonturen

Wenn Sie die Gesichtskonturerkennung aktiviert haben, erhalten Sie eine Liste mit Punkten für jedes erkannte Gesichtsmerkmal. Diese Punkte repräsentieren die Form des Features. Einzelheiten zur Darstellung von Konturen finden Sie in der Übersicht über Gesichtserkennungskonzepte .

Das folgende Bild zeigt, wie diese Punkte einem Gesicht zugeordnet werden (zum Vergrößern auf das Bild klicken):

Gesichtserkennung in Echtzeit

Wenn Sie die Gesichtserkennung in einer Echtzeitanwendung verwenden möchten, befolgen Sie diese Richtlinien, um die besten Frameraten zu erzielen:

  • Konfigurieren Sie den Gesichtsdetektor so, dass er entweder die Gesichtskonturerkennung oder die Klassifizierung und Landmarkenerkennung verwendet, aber nicht beides:

    Konturerkennung
    Landmarkenerkennung
    Einstufung
    Orientierungspunkterkennung und -klassifizierung
    Konturerkennung und Landmarkenerkennung
    Konturerkennung und -klassifizierung
    Konturerkennung, Orientierungspunkterkennung und Klassifizierung

  • Aktivieren Sie den FAST -Modus (standardmäßig aktiviert).

  • Erwägen Sie, Bilder mit einer niedrigeren Auflösung aufzunehmen. Beachten Sie jedoch auch die Anforderungen an die Bildgröße dieser API.

  • Drosselrufe an den Detektor. Wenn ein neuer Videoframe verfügbar wird, während der Detektor läuft, löschen Sie den Frame.
  • Wenn Sie die Ausgabe des Detektors verwenden, um Grafiken auf das Eingabebild zu legen, rufen Sie zuerst das Ergebnis von ML Kit ab, rendern Sie dann das Bild und überlagern Sie es in einem einzigen Schritt. Dadurch rendern Sie für jeden Eingabeframe nur einmal auf der Anzeigeoberfläche.
  • Wenn Sie die Camera2-API verwenden, erfassen Sie Bilder im Format ImageFormat.YUV_420_888 .

    Wenn Sie die ältere Kamera-API verwenden, erfassen Sie Bilder im Format ImageFormat.NV21 .