Gesichter mit ML Kit auf Android erkennen

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

Bevor Sie beginnen

  1. Wenn Sie nicht bereits haben, fügen Sie Firebase zu dem Android - Projekt .
  2. Fügen Sie die Abhängigkeiten für die ML Kit Android - Bibliotheken zu Ihrem Modul (app-Ebene) Gradle Datei ( in der Regel 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 , um automatisch das ML - Modell auf das Gerät herunterzuladen , nachdem die App aus dem Play Store installiert ist.

    Dazu fügen Sie die folgende Erklärung zu Ihrer App AndroidManifest.xml Datei:

    <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 nicht aktivieren installieren Zeitmodell Downloads, wird das Modell das erste Mal , wenn Sie den Detektor laufen heruntergeladen werden. Anfragen, die Sie vor Abschluss des Downloads stellen, führen zu keinen Ergebnissen.

Richtlinien für die Eingabe von Bildern

Damit ML Kit Gesichter genau erkennen kann, müssen die eingegebenen Bilder Gesichter enthalten, die durch ausreichende 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 auch die Gesamtabmessungen der eingegebenen Bilder berücksichtigen. Kleinere Bilder können schneller verarbeitet werden. Um die Latenz zu reduzieren, nehmen Sie Bilder mit niedrigeren Auflösungen auf (beachten Sie die oben genannten Genauigkeitsanforderungen) und stellen Sie sicher, dass das Gesicht des Motivs so viel wie möglich vom Bild einnimmt. Siehe auch Tipps Echtzeit - Performance zu verbessern .

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

Die Ausrichtung eines Gesichts relativ zur Kamera kann sich auch auf die von ML Kit erkannten Gesichtsmerkmale auswirken. Siehe Gesichtserkennung Konzepte .

1. Konfigurieren Sie den Gesichtsdetektor

Bevor Sie die Gesichtserkennung auf ein Bild anwenden, wenn Sie eines der Gesichtsdetektor Standardeinstellungen ändern möchten, geben Sie diese Einstellungen mit einem FirebaseVisionFaceDetectorOptions Objekt. Sie können die folgenden Einstellungen ändern:

Einstellungen
Leistungsmodus FAST (Standard) | ACCURATE

Bevorzugen Sie Geschwindigkeit oder Genauigkeit beim Erkennen von Gesichtern.

Sehenswürdigkeiten erkennen NO_LANDMARKS (default) | ALL_LANDMARKS

Ob versucht werden soll, "Wahrzeichen" im Gesicht zu identifizieren: Augen, Ohren, Nase, Wangen, Mund usw.

Konturen erkennen NO_CONTOURS (default) | ALL_CONTOURS

Ob die Konturen der Gesichtszüge erkannt werden sollen. Konturen werden nur für das prominenteste Gesicht in einem Bild erkannt.

Gesichter klassifizieren NO_CLASSIFICATIONS (default) | ALL_CLASSIFICATIONS

Ob Gesichter in Kategorien wie "Lächeln" und "Augen offen" eingeteilt werden sollen oder nicht.

Mindestgesichtsgröße float (Standard: 0.1f )

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

Gesichtsverfolgung aktivieren false (default) | true

Ob Gesichtern eine ID zugewiesen werden soll, mit der Gesichter über Bilder hinweg verfolgt werden können.

Beachten Sie, dass bei aktivierter Konturerkennung nur ein Gesicht erkannt wird, sodass die Gesichtsverfolgung keine nützlichen Ergebnisse liefert. Aus diesem Grund und um die Erkennungsgeschwindigkeit zu verbessern, aktivieren Sie 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

Zum Nachweis von Gesichtern in einem Bild, schafft ein FirebaseVisionImage Objekt entweder aus einer Bitmap , media.Image , ByteBuffer , Byte - Array oder eine Datei auf dem Gerät. Dann passiert das FirebaseVisionImage Objekt des FirebaseVisionFaceDetector ‚s detectInImage Methode.

Für die Gesichtserkennung, sollten Sie ein Bild mit einer Größe von mindestens 480x360 Pixeln verwenden. Wenn Sie Gesichter in Echtzeit erkennen, kann die Aufnahme von Bildern mit dieser Mindestauflösung dazu beitragen, die Latenz zu reduzieren.

  1. Erstellen Sie ein FirebaseVisionImage Objekt aus dem Bild.

    • Um ein erstellen FirebaseVisionImage Objekt aus einem media.Image Objekt, beispielsweise , wenn von einem Gerät der Kamera ein Bild aufzeichnen, vorbei an das media.Image Objekt und die Bildrotation zu FirebaseVisionImage.fromMediaImage() .

      Wenn Sie die Verwendung CameraX Bibliothek, die OnImageCapturedListener und ImageAnalysis.Analyzer berechnen Klassen den Rotationswert für Sie, so dass Sie nur die Drehung zu einem der ML Kits müssen konvertieren ROTATION_ Konstanten vor dem Aufruf 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+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
      }

      Dann passiert das media.Image Objekt und den Drehwert FirebaseVisionImage.fromMediaImage() :

      Java

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

      Kotlin+KTX

      val image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation)
    • So erstellen Sie ein FirebaseVisionImage Objekt aus einer Datei URI, übergeben Sie die App Kontext und Datei - URI zu FirebaseVisionImage.fromFilePath() . Dies ist nützlich , wenn Sie eine verwenden ACTION_GET_CONTENT Absicht , den Benutzer aufzufordern , ein Bild aus ihrer Galerie App auswä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 zu erstellen FirebaseVisionImage Objekt aus einem ByteBuffer oder einem Byte - Array, berechnet zuerst die Bilddrehung , wie oben beschrieben für media.Image Eingabe.

      Dann erstellen FirebaseVisionImageMetadata Objekt, das die Bildhöhe, Breite enthält, Farbcodierungsformat, und die Rotation:

      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 Array und das Metadatenobjekt, eine erstellen FirebaseVisionImage Objekt:

      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)
    • Um ein zu erstellen FirebaseVisionImage Objekt aus einem Bitmap - Objekt:

      Java

      FirebaseVisionImage image = FirebaseVisionImage.fromBitmap(bitmap);

      Kotlin+KTX

      val image = FirebaseVisionImage.fromBitmap(bitmap)
      Das Bild , das durch das dargestellte Bitmap - Objekt muss aufrecht sein, ohne zusätzliche Drehung erforderlich.
  2. Erhalten Sie eine Instanz von FirebaseVisionFaceDetector :

    Java

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

    Kotlin+KTX

    val detector = FirebaseVision.getInstance()
            .getVisionFaceDetector(options)
  3. Schließlich passiert das Bild auf die detectInImage Methode:

    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. Holen Sie sich Informationen über erkannte Gesichter

Wenn die Gesichtserkennung Operation erfolgreich, wird eine Liste von FirebaseVisionFace werden Objekte zum Erfolg Zuhörer weitergegeben werden. Jedes FirebaseVisionFace Objekt repräsentiert ein Gesicht , das in dem Bild festgestellt wurde. Für jedes Gesicht können Sie seine Begrenzungskoordinaten im Eingabebild sowie alle anderen Informationen abrufen, für die Sie den Gesichtsdetektor 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 von Punkten für jedes erkannte Gesichtsmerkmal. Diese Punkte repräsentieren die Form des Features. Siehe die Gesichtserkennung Konzepte Übersicht für Einzelheiten darüber , wie Konturen dargestellt werden.

Die folgende Abbildung 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 des Gesichtsdetektor entweder Gesichtskonturerkennung und Klassifizierung und Wahrzeichen Erkennung zu verwenden, aber nicht beides:

    Konturerkennung
    Erkennung von Wahrzeichen
    Einstufung
    Erkennung und Klassifizierung von Wahrzeichen
    Konturerkennung und Landmarkenerkennung
    Konturerkennung und -klassifizierung
    Konturerkennung, Landmarkenerkennung und Klassifizierung

  • Aktivieren FAST - Modus (Standardeinstellung).

  • Ziehen Sie in Erwägung, Bilder mit einer niedrigeren Auflösung aufzunehmen. Beachten Sie jedoch auch die Anforderungen an die Bildabmessungen dieser API.

  • Throttle-Anrufe an den Detektor. Wenn ein neues Videobild verfügbar wird, während der Detektor läuft, lassen Sie das Bild fallen.
  • Wenn Sie die Ausgabe des Detektors verwenden, um Grafiken auf dem Eingabebild zu überlagern, rufen Sie zuerst das Ergebnis von ML Kit ab und rendern Sie dann das Bild und die Überlagerung in einem einzigen Schritt. Auf diese Weise rendern Sie für jeden Eingabeframe nur einmal auf der Anzeigeoberfläche.
  • Wenn Sie die Camera2 API, die Aufnahmen in verwenden ImageFormat.YUV_420_888 Format.

    Wenn Sie den älteren Kamera - API, die Aufnahmen in verwenden ImageFormat.NV21 Format.