Mit ML Kit können Sie Gesichter in Bildern und Videos erkennen.
Hinweis
- Fügen Sie Ihrem Android-Projekt Firebase hinzu, falls noch nicht geschehen.
- Fügen Sie der Gradle-Datei des Moduls (auf Anwendungsebene, in der Regel
app/build.gradle
) die Abhängigkeiten für die ML Kit-Android-Bibliotheken hinzu: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' }
-
Optional, aber empfohlen: Konfigurieren Sie Ihre App so, dass das ML-Modell automatisch auf das Gerät heruntergeladen wird, nachdem Ihre App über den Play Store installiert wurde.
Fügen Sie dazu der Datei
AndroidManifest.xml
Ihrer App die folgende Erklärung hinzu: Wenn Sie den Download von Modellen bei der Installation nicht aktivieren, wird das Modell beim ersten Ausführen des Detectors heruntergeladen. Anfragen, die Sie vor Abschluss des Downloads stellen, führen zu keinen Ergebnissen.<application ...> ... <meta-data android:name="com.google.firebase.ml.vision.DEPENDENCIES" android:value="face" /> <!-- To use multiple models: android:value="face,model2,model3" --> </application>
Richtlinien für Eingabebilder
Damit ML Kit Gesichter genau erkennen kann, müssen die Eingabebilder Gesichter enthalten, die durch ausreichende Pixeldaten dargestellt werden. Im Allgemeinen sollte jedes Gesicht, das in einem Bild erkannt werden soll, mindestens 100 × 100 Pixel groß sein. Wenn Sie die Konturen von Gesichtern erkennen möchten, benötigt ML Kit eine höhere Auflösung: Jedes Gesicht sollte mindestens 200 × 200 Pixel groß sein.
Wenn Sie Gesichter in einer Echtzeitanwendung erkennen, sollten Sie auch die Gesamtabmessungen der Eingabebilder berücksichtigen. Kleinere Bilder können schneller verarbeitet werden. Um die Latenz zu verringern, sollten Sie Bilder mit niedrigerer Auflösung aufnehmen (beachten Sie dabei die oben genannten Genauigkeitsanforderungen) und darauf achten, dass das Gesicht des Motivs möglichst viel Platz auf dem Bild einnimmt. Weitere Informationen finden Sie unter Tipps zur Verbesserung der Echtzeitleistung.
Ein unscharfer Bildfokus kann die Genauigkeit beeinträchtigen. Wenn Sie keine zufriedenstellenden Ergebnisse erhalten, bitten Sie den Nutzer, das Bild noch einmal aufzunehmen.
Auch die Ausrichtung eines Gesichts im Verhältnis zur Kamera kann sich darauf auswirken, welche Gesichtsmerkmale ML Kit erkennt. Weitere Informationen finden Sie unter Konzepte der Gesichtserkennung.
1. Gesichtserkennung konfigurieren
Wenn Sie die Standardeinstellungen der Gesichtserkennung ändern möchten, bevor Sie die Gesichtserkennung auf ein Bild anwenden, geben Sie diese Einstellungen mit einemFirebaseVisionFaceDetectorOptions
-Objekt an.
Sie können die folgenden Einstellungen ändern:
Einstellungen | |
---|---|
Leistungsmodus |
FAST (Standard)
| ACCURATE
Legen Sie bei der Gesichtserkennung Wert auf Geschwindigkeit oder Genauigkeit. |
Sehenswürdigkeiten erkennen |
NO_LANDMARKS (Standard)
| ALL_LANDMARKS
Ob versucht werden soll, Gesichtsmerkmale wie Augen, Ohren, Nase, Wangen, Mund usw. zu erkennen. |
Konturen erkennen |
NO_CONTOURS (Standard)
| ALL_CONTOURS
Ob die Konturen der Gesichtsmerkmale 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 „Augen offen“ klassifiziert werden sollen. |
Mindestgröße des Gesichts |
float (Standard: 0.1f )
Die Mindestgröße der zu erkennenden Gesichter im Verhältnis zum Bild. |
Gesichtstracking aktivieren |
false (Standard) | true
Ob Gesichtern eine ID zugewiesen werden soll, mit der sie in Bildern verfolgt werden können. Wenn die Konturerkennung aktiviert ist, wird nur ein Gesicht erkannt. Das Gesichts-Tracking liefert dann keine nützlichen Ergebnisse. Aus diesem Grund und um die Erkennungsgeschwindigkeit zu verbessern, sollten Sie nicht gleichzeitig die Konturerkennung und die Gesichtserkennung aktivieren. |
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
// 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. Gesichtserkennung ausführen
Wenn Sie Gesichter in einem Bild erkennen möchten, erstellen Sie einFirebaseVisionImage
-Objekt aus einem Bitmap
-, media.Image
-, ByteBuffer
-, Byte-Array oder einer Datei auf dem Gerät. Übergeben Sie dann das FirebaseVisionImage
-Objekt an die detectInImage
-Methode von FirebaseVisionFaceDetector
.
Für die Gesichtserkennung sollten Sie ein Bild mit den Abmessungen 480 × 360 Pixel verwenden. Wenn Sie Gesichter in Echtzeit erkennen, kann die Aufnahme von Frames mit dieser Mindestauflösung die Latenz verringern.
Erstellen Sie ein
FirebaseVisionImage
-Objekt aus Ihrem Bild.-
Wenn Sie ein
FirebaseVisionImage
-Objekt aus einemmedia.Image
-Objekt erstellen möchten, z. B. wenn Sie ein Bild mit der Kamera eines Geräts aufnehmen, übergeben Sie dasmedia.Image
-Objekt und die Drehung des Bilds anFirebaseVisionImage.fromMediaImage()
.Wenn Sie die CameraX-Bibliothek verwenden, wird der Drehwert von den Klassen
OnImageCapturedListener
undImageAnalysis.Analyzer
für Sie berechnet. Sie müssen ihn also nur in eine derROTATION_
-Konstanten von ML Kit umwandeln, bevor SieFirebaseVisionImage.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
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 die Drehung des Bildes angibt, können Sie sie anhand 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
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 Drehwert anFirebaseVisionImage.fromMediaImage()
:Java
FirebaseVisionImage image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation);
Kotlin
val image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation)
- Wenn Sie ein
FirebaseVisionImage
-Objekt aus einem Datei-URI erstellen möchten, übergeben Sie den App-Kontext und den Datei-URI anFirebaseVisionImage.fromFilePath()
. Das ist nützlich, wenn Sie mit einerACTION_GET_CONTENT
-Intent den Nutzer auffordern, ein Bild aus seiner Galerie-App auszuwählen.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() }
- Wenn Sie ein
FirebaseVisionImage
-Objekt aus einemByteBuffer
oder einem Byte-Array erstellen möchten, berechnen Sie zuerst die Bilddrehung wie oben für diemedia.Image
-Eingabe beschrieben.Erstellen Sie dann ein
FirebaseVisionImageMetadata
-Objekt, das die Höhe, Breite, Farbcodierung und Drehung des Bildes 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
val metadata = FirebaseVisionImageMetadata.Builder() .setWidth(480) // 480x360 is typically sufficient for .setHeight(360) // image recognition .setFormat(FirebaseVisionImageMetadata.IMAGE_FORMAT_NV21) .setRotation(rotation) .build()
Verwende 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
val image = FirebaseVisionImage.fromByteBuffer(buffer, metadata) // Or: val image = FirebaseVisionImage.fromByteArray(byteArray, metadata)
- So erstellen Sie ein
FirebaseVisionImage
-Objekt aus einemBitmap
-Objekt:Java
FirebaseVisionImage image = FirebaseVisionImage.fromBitmap(bitmap);
Kotlin
val image = FirebaseVisionImage.fromBitmap(bitmap)
Bitmap
-Objekt dargestellte Bild muss aufrecht sein und darf nicht zusätzlich gedreht werden.
-
Instanz von
FirebaseVisionFaceDetector
abrufen:Java
FirebaseVisionFaceDetector detector = FirebaseVision.getInstance() .getVisionFaceDetector(options);
Kotlin
val detector = FirebaseVision.getInstance() .getVisionFaceDetector(options)
Übergeben Sie das Bild abschließend an 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
val result = detector.detectInImage(image) .addOnSuccessListener { faces -> // Task completed successfully // ... } .addOnFailureListener { e -> // Task failed with an exception // ... }
3. Informationen zu erkannten Gesichtern abrufen
Wenn der Vorgang der Gesichtserkennung erfolgreich war, wird dem Erfolgsempfänger eine Liste vonFirebaseVisionFace
-Objekten übergeben. Jedes FirebaseVisionFace
-Objekt stellt ein Gesicht dar, das im Bild erkannt wurde. Für jedes Gesicht können Sie die Begrenzungskoordinaten im Eingabebild sowie alle anderen Informationen abrufen, die Sie für die Gesichtserkennung konfiguriert haben. 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
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 die Gesichtskonturerkennung aktiviert ist, wird für jedes erkannte Gesichtsmerkmal eine Liste mit Punkten angezeigt. Diese Punkte repräsentieren die Form des Elements. Weitere Informationen zur Darstellung von Konturen finden Sie unter Konzepte der Gesichtserkennung.
Das folgende Bild veranschaulicht, wie diese Punkte einem Gesicht zugeordnet werden (zum Vergrößern auf das Bild klicken):
Echtzeit-Gesichtserkennung
Wenn Sie die Gesichtserkennung in einer Echtzeitanwendung verwenden möchten, beachten Sie die folgenden Richtlinien, um die beste Framerate zu erzielen:
Konfigurieren Sie den Gesichtserkennungsalgorithmus so, dass entweder die Gesichtskonturerkennung oder die Klassifizierung und Sehenswürdigkeitenerkennung verwendet wird, aber nicht beide:
Konturerkennung
Erkennung von Sehenswürdigkeiten
Klassifizierung
Erkennung und Klassifizierung von Sehenswürdigkeiten
Konturerkennung und Erkennung von Sehenswürdigkeiten
Konturerkennung und Klassifizierung
Konturerkennung, Erkennung von Sehenswürdigkeiten und KlassifizierungAktivieren Sie den
FAST
-Modus (standardmäßig aktiviert).Sie können auch Bilder mit niedrigerer Auflösung aufnehmen. Beachten Sie jedoch auch die Anforderungen an die Bildabmessungen dieser API.
- Aufrufe an den Detektor drosseln Wenn während der Laufzeit des Detektors ein neuer Videoframe verfügbar wird, legen Sie ihn ab.
- Wenn Sie die Ausgabe des Detektors verwenden, um Grafiken auf das Eingabebild zu legen, rufen Sie zuerst das Ergebnis aus ML Kit ab und rendern Sie dann das Bild und das Overlay in einem einzigen Schritt. So wird für jeden Eingabeframe nur einmal auf die Displayoberfläche gerendert.
-
Wenn Sie die Camera2 API verwenden, sollten Sie Bilder im
ImageFormat.YUV_420_888
-Format aufnehmen.Wenn Sie die ältere Camera API verwenden, nehmen Sie Bilder im
ImageFormat.NV21
-Format auf.