Mit dem ML Kit können Sie Gesichter in Bildern und Videos erkennen.
Bevor Sie beginnen
- Falls noch nicht geschehen, fügen Sie Firebase zu Ihrem Android-Projekt hinzu .
- 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' }
- 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 Modell-Downloads 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 keinem Ergebnis.
Geben Sie Bildrichtlinien ein
Damit ML Kit Gesichter genau erkennen kann, müssen Eingabebilder 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, möchten 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 daher mit niedrigeren Auflösungen auf (unter Berücksichtigung der oben genannten Genauigkeitsanforderungen) und stellen Sie sicher, dass das Gesicht des Motivs so viel Bild wie möglich einnimmt. Siehe auch Tipps zur Verbesserung der Echtzeitleistung .
Eine schlechte Bildschärfe 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 darauf auswirken, welche Gesichtsmerkmale das ML Kit erkennt. Siehe Gesichtserkennungskonzepte .
1. Konfigurieren Sie den Gesichtsdetektor
Bevor Sie die Gesichtserkennung auf ein Bild anwenden und Standardeinstellungen des Gesichtsdetektors ändern möchten, geben Sie diese Einstellungen mit einemFirebaseVisionFaceDetectorOptions
-Objekt an. Sie können die folgenden Einstellungen ändern:Einstellungen | |
---|---|
Leistungsmodus | FAST (Standard) | ACCURATE Bevorzugen Sie Geschwindigkeit oder Genauigkeit bei der Gesichtserkennung. |
Orientierungspunkte erkennen | NO_LANDMARKS (Standard) | ALL_LANDMARKS Ob versucht werden soll, „Wahrzeichen“ im Gesicht 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. |
Mindestgesichtsgröß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, 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
Um Gesichter in einem Bild zu erkennen, erstellen Sie einFirebaseVisionImage
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 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.
Erstellen Sie aus Ihrem Bild ein
FirebaseVisionImage
Objekt.Um ein
FirebaseVisionImage
Objekt aus einemmedia.Image
Objekt zu erstellen, beispielsweise beim Aufnehmen eines Bildes von der Kamera eines Geräts, übergeben Sie dasmedia.Image
Objekt und die Drehung des Bildes anFirebaseVisionImage.fromMediaImage()
.Wenn Sie die CameraX- Bibliothek verwenden, berechnen die Klassen
OnImageCapturedListener
undImageAnalysis.Analyzer
den Rotationswert für Sie, Sie müssen also nur die Rotation in eine derROTATION_
Konstanten von ML Kit konvertieren, 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+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 diese 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 anFirebaseVisionImage.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 anFirebaseVisionImage.fromFilePath()
. Dies ist nützlich, wenn Sie eineACTION_GET_CONTENT
Absicht 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 einemByteBuffer
oder einem Byte-Array zu erstellen, berechnen Sie zunächst die Bildrotation wie oben fürmedia.Image
Eingabe beschrieben.Erstellen Sie dann ein
FirebaseVisionImageMetadata
-Objekt, das die Höhe, Breite, das Farbkodierungsformat und die 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+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 einemBitmap
Objekt:Das durch dasJava
FirebaseVisionImage image = FirebaseVisionImage.fromBitmap(bitmap);
Kotlin+KTX
val image = FirebaseVisionImage.fromBitmap(bitmap)
Bitmap
Objekt dargestellte Bild muss aufrecht stehen, ohne dass eine zusätzliche Drehung erforderlich ist.
Holen Sie sich eine Instanz von
FirebaseVisionFaceDetector
:Java
FirebaseVisionFaceDetector detector = FirebaseVision.getInstance() .getVisionFaceDetector(options);
Kotlin+KTX
val detector = FirebaseVision.getInstance() .getVisionFaceDetector(options)
Übergeben Sie abschließend das Bild 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 vonFirebaseVisionFace
Objekten an den Erfolgslistener übergeben. Jedes FirebaseVisionFace
Objekt stellt ein Gesicht dar, das im Bild erkannt wurde. Für jedes Gesicht können Sie seine Grenzkoordinaten im Eingabebild sowie alle anderen Informationen abrufen, für deren Suche 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 mit Punkten für jedes erkannte Gesichtsmerkmal. Diese Punkte stellen die Form des Features dar. 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 Bildraten zu erzielen:
Konfigurieren Sie den Gesichtsdetektor so, dass er entweder die Gesichtskonturerkennung oder die Klassifizierung und Erkennung von Orientierungspunkten verwendet, jedoch nicht beides:
Konturerkennung
Erkennung von Wahrzeichen
Einstufung
Erkennung und Klassifizierung von Wahrzeichen
Konturerkennung und Landmarkenerkennung
Konturerkennung und -klassifizierung
Konturerkennung, Landmarkenerkennung und KlassifizierungAktivieren Sie
FAST
Modus (standardmäßig aktiviert).Erwägen Sie die Aufnahme von Bildern mit einer niedrigeren Auflösung. Beachten Sie jedoch auch die Bildabmessungsanforderungen dieser API.
- Gasrufe an den Detektor. Wenn ein neues Videobild verfügbar wird, während der Detektor läuft, löschen Sie das Bild.
- Wenn Sie die Ausgabe des Detektors verwenden, um Grafiken auf dem Eingabebild zu überlagern, rufen Sie zunächst das Ergebnis vom ML Kit ab und rendern Sie dann das Bild und überlagern Sie es in einem einzigen Schritt. Auf diese Weise rendern Sie für jeden Eingaberahmen nur einmal auf der Anzeigeoberfläche.
Wenn Sie die Camera2-API verwenden, erfassen Sie Bilder im
ImageFormat.YUV_420_888
Format.Wenn Sie die ältere Kamera-API verwenden, erfassen Sie Bilder im
ImageFormat.NV21
Format.