Eine Einführung in die Gesichtserkennung auf Android

Mit den Vision-Bibliotheken in Play Services 8.1 eingeführt, erleichtert Ihnen Face Detection als Entwickler die Analyse eines Videos oder Bildes, um menschliche Gesichter zu finden. Sobald Sie eine Liste von Gesichtern auf einem Bild erkannt haben, können Sie Informationen zu jedem Gesicht sammeln, wie z. B. Orientierung, Wahrscheinlichkeit des Lächelns, ob jemand die Augen offen oder geschlossen hat, und bestimmte Landmarken auf dem Gesicht.

Diese Informationen können für mehrere Anwendungen nützlich sein, z. B. für eine Kamera-App, die automatisch ein Bild aufnimmt, wenn alle Personen im Bild mit offenen Augen lächeln, oder um Bilder mit dummen Effekten wie Einhornhörnern zu verstärken. Es ist wichtig zu beachten, dass Gesichtserkennung ist nicht Gesichtserkennung. Während Informationen zu einem Gesicht erfasst werden können, wird diese Information nicht von der Vision-Bibliothek verwendet, um zu bestimmen, ob zwei Gesichter von derselben Person stammen.

In diesem Lernprogramm wird ein Standbild verwendet, um die Gesichtserkennungs-API auszuführen und Informationen über die Personen auf dem Foto zu sammeln. Außerdem werden diese Informationen mit überlagerten Grafiken veranschaulicht. Den gesamten Code für dieses Tutorial finden Sie auf GitHub.

1. Projekteinrichtung

Um die Vision-Bibliothek zu Ihrem Projekt hinzuzufügen, müssen Sie Play Services 8.1 oder höher in Ihr Projekt importieren. In diesem Lernprogramm wird nur die Play Services Vision-Bibliothek importiert. Öffnen dein Projekt build.gradle Datei und fügen Sie die folgende Compile-Zeile hinzu Abhängigkeiten Knoten.

"com.google.android.gms: play-services-vision: 8.1.0" kompilieren

Sobald Sie Play Services in Ihr Projekt aufgenommen haben, können Sie die Projekte schließen build.gradle Datei und öffnen AndroidManifest.xml. Sie müssen eine hinzufügen Metadaten Element, das die Gesichtsabhängigkeit unter dem Symbol definiert Anwendung Knoten Ihres Manifests. Dadurch wird der Vision-Bibliothek mitgeteilt, dass Sie Gesichter in Ihrer Anwendung erkennen möchten.

Sobald Sie mit der Einrichtung fertig sind AndroidManifest.xml, Sie können fortfahren und es schließen. Als Nächstes müssen Sie eine neue Klasse mit dem Namen erstellen FaceOverlayView.java. Diese Klasse erweitert sich Aussicht und enthält die Logik zum Erkennen von Gesichtern im Projekt, Anzeigen der analysierten Bitmap und Zeichnen auf das Bild, um Punkte zu veranschaulichen.

Fügen Sie zunächst die Mitgliedsvariablen oben in der Klasse hinzu und definieren Sie die Konstruktoren. Das Bitmap Das Objekt wird zum Speichern der zu analysierenden Bitmap und der SparseArray von Gesicht Objekte speichern jedes in der Bitmap gefundene Gesicht.

öffentliche Klasse FaceOverlayView erweitert View private Bitmap mBitmap; privates SparseArray mFaces; public FaceOverlayView (Kontextkontext) this (Kontext, null);  public FaceOverlayView (Kontextkontext, AttributeSet-Attribute) this (Kontext, Attribute, 0);  public FaceOverlayView (Kontextkontext, AttributeSet-Attribute, int defStyleAttr) super (Kontext, Attribute, defStyleAttr); 

Fügen Sie als Nächstes eine neue Methode in hinzu FaceOverlayView namens setBitmap (Bitmap-Bitmap). Im Moment speichert dies einfach die übergebene Bitmap. Später werden Sie diese Methode jedoch zur Analyse des Bildes verwenden.

public void setBitmap (Bitmap-Bitmap) mBitmap = Bitmap; 

Als nächstes benötigen Sie eine Bitmap. Ich habe eines in das Beispielprojekt auf GitHub aufgenommen, aber Sie können jedes beliebige Bild verwenden, um mit Face Detection zu spielen und zu sehen, was funktioniert und was nicht. Wenn Sie ein Bild ausgewählt haben, platzieren Sie es in der res / raw Verzeichnis. In diesem Lernprogramm wird davon ausgegangen, dass das Bild aufgerufen wird face.jpg.

Nachdem Sie Ihr Bild in den Ordner eingefügt haben res / raw Verzeichnis öffnen res / layout / activity_main.xml. Dieses Layout enthält einen Verweis auf FaceOverlayView so dass es in angezeigt wird Hauptaktivität.

 

Öffnen Sie das definierte Layout Hauptaktivität und das einrichten FaceOverlayView von onCreate (). Sie erhalten dies, indem Sie einen Verweis auf die Ansicht erhalten und das lesen face.jpg Bilddatei aus dem Raw-Verzeichnis als Eingabestrom und Konvertierung in eine Bitmap. Sobald Sie die Bitmap haben, können Sie anrufen setBitmap auf der FaceOverlayView um das Bild an Ihre benutzerdefinierte Ansicht zu übergeben.

public class MainActivity erweitert AppCompatActivity private FaceOverlayView mFaceOverlayView; @Override protected void onCreate (Bundle savedInstanceState) super.onCreate (savedInstanceState); setContentView (R.layout.activity_main); mFaceOverlayView = (FaceOverlayView) findViewById (R.id.face_overlay); InputStream-Stream = getResources (). OpenRawResource (R.raw.face); Bitmap Bitmap = BitmapFactory.decodeStream (Stream); mFaceOverlayView.setBitmap (Bitmap); 

2. Gesichter erkennen

Jetzt, da Ihr Projekt eingerichtet ist, können Sie jetzt Gesichter erkennen. Im setBitmap (Bitmap-Bitmap) Sie müssen ein erstellen FaceDetector. Dies kann mit einem FaceDetector.Builder, So können Sie mehrere Parameter definieren, die beeinflussen, wie schnell Gesichter erkannt werden und welche anderen Daten das sind FaceDetector wird erzeugen.

Die Einstellungen, die Sie auswählen, hängen davon ab, was Sie in Ihrer Anwendung versuchen. Wenn Sie die Suche nach Landmarken aktivieren, werden Gesichter langsamer erkannt. Wie bei den meisten Dingen in der Programmierung hat alles seine Kompromisse. Weitere Informationen zu den verfügbaren Optionen für FaceDetector.Builder, Die offizielle Dokumentation finden Sie auf der Entwickler-Website von Android.

FaceDetector detector = new FaceDetector.Builder (getContext ()) .setTrackingEnabled (false) .setLandmarkType (FaceDetector.ALL_LANDMARKS) .setMode (FaceDetector.FAST_MODE) .build ();

Sie müssen auch überprüfen, ob das angezeigt wird FaceDetector ist betriebsbereit. Wenn ein Benutzer zum ersten Mal die Gesichtserkennung auf seinem Gerät verwendet, müssen die Play Services eine Reihe von kleinen systemeigenen Bibliotheken erhalten, um die Anforderungen Ihrer Anwendung zu verarbeiten. Dies wird zwar fast immer vor dem Start der App erledigt, es ist jedoch wichtig, dass die eventuelle Fehlfunktion berücksichtigt wird.

Wenn die FaceDetector ist betriebsbereit, dann können Sie Ihre Bitmap in eine konvertieren Rahmen Objekt und übergeben Sie es an den Detektor, um Daten zu Gesichtern im Bild zu erfassen. Wenn Sie fertig sind, müssen Sie den Detektor freigeben, um einen Speicherverlust zu verhindern. Wenn Sie alle Gesichter erkannt haben, rufen Sie an ungültig machen () um das Neuzeichnen der Ansicht auszulösen.

if (! detector.isOperational ()) // Eventualität behandeln else Frame frame = new Frame.Builder (). setBitmap (bitmap) .build (); mFaces = detector.detect (frame); Detektor.Release ();  invalidate ();

Nachdem Sie nun die Gesichter in Ihrem Bild erkannt haben, können Sie sie verwenden. In diesem Beispiel zeichnen Sie einfach ein grünes Kästchen um jedes Gesicht. Schon seit ungültig machen () aufgerufen wurde, nachdem die Gesichter erkannt wurden, können Sie die gesamte erforderliche Logik hinzufügen onDraw (Leinwand Leinwand). Diese Methode stellt sicher, dass die Bitmap und die Flächen festgelegt sind. Zeichnen Sie dann die Bitmap auf die Leinwand und zeichnen Sie dann ein Kästchen um jede Fläche.

Da verschiedene Geräte unterschiedliche Anzeigegrößen haben, behalten Sie auch die skalierte Größe der Bitmap im Auge, sodass das gesamte Bild auf dem Gerät immer sichtbar ist und alle Überlagerungen entsprechend gezeichnet werden.

@Override protected void onDraw (Leinwandbereich) super.onDraw (Leinwandbereich); if ((mBitmap! = null) && (mFaces! = null)) double scale = drawBitmap (Zeichenfläche); drawFaceBox (Leinwand, Maßstab); 

Das drawBitmap (Canvas-Leinwand) Diese Methode zeichnet Ihre Bitmap auf die Leinwand und passt sie entsprechend an. Außerdem wird ein Multiplikator für die korrekte Skalierung der anderen Bemaßungen zurückgegeben.

private double drawBitmap (Canvas-Leinwand) double viewWidth = canvas.getWidth (); double viewHeight = canvas.getHeight (); double imageWidth = mBitmap.getWidth (); double imageHeight = mBitmap.getHeight (); double scale = Math.min (viewWidth / imageWidth, viewHeight / imageHeight); Rect destBounds = new Rect (0, 0, (int) (imageWidth * scale), (int) (imageHeight * scale)); canvas.drawBitmap (mBitmap, null, destBounds, null); Skala zurückgeben; 

Das drawFaceBox (Leinwand, doppelte Skala) Methode wird etwas interessanter. Jedes erkannte und gespeicherte Gesicht hat einen Positionswert oberhalb und links von jedem Gesicht. Diese Methode nimmt diese Position und zeichnet daraus ein grünes Rechteck, um jede Fläche basierend auf ihrer Breite und Höhe zu umfassen.

Sie müssen Ihre definieren Farbe Objekt und dann durchlaufen Gesicht in deiner SparseArray um seine Position, Breite und Höhe zu ermitteln und das Rechteck mit diesen Informationen auf der Leinwand zu zeichnen.

private void drawFaceBox (Canvas-Leinwand, doppelte Skalierung) // paint sollte als Member-Variable definiert werden, anstatt // für jede onDraw-Anforderung erstellt zu werden, aber hier // wegen der Betonung übrig bleiben. Paint paint = neuer Paint (); paint.setColor (Color.GREEN); paint.setStyle (Paint.Style.STROKE); paint.setStrokeWidth (5); Float links = 0; Schwimmeroberseite = 0; Schwimmer rechts = 0; Floatboden = 0; für (int i = 0; i < mFaces.size(); i++ )  Face face = mFaces.valueAt(i); left = (float) ( face.getPosition().x * scale ); top = (float) ( face.getPosition().y * scale ); right = (float) scale * ( face.getPosition().x + face.getWidth() ); bottom = (float) scale * ( face.getPosition().y + face.getHeight() ); canvas.drawRect( left, top, right, bottom, paint );  

An diesem Punkt sollten Sie in der Lage sein, Ihre Anwendung auszuführen und Ihr Bild mit Rechtecken um jedes erkannte Gesicht zu sehen. Es ist wichtig anzumerken, dass die Gesichtserkennungs-API zum Zeitpunkt der Erstellung dieses Dokuments noch relativ neu ist und möglicherweise nicht jedes Gesicht erkennt. Sie können mit einigen Einstellungen im spielen FaceDetector.Builder Objekt, um hoffentlich mehr Daten zu sammeln, obwohl dies nicht garantiert werden kann.

3. Orientierungspunkte verstehen

Sehenswürdigkeiten sind Sehenswürdigkeiten auf einem Gesicht. Die Gesichtserkennungs-API verwendet keine Landmarken zum Erkennen eines Gesichts, sondern erkennt ein Gesicht in seiner Gesamtheit, bevor es nach Landmarken sucht. Daher ist das Erkennen von Orientierungspunkten eine optionale Einstellung, die über das Symbol aktiviert werden kann FaceDetector.Builder.

Sie können diese Landmarken als zusätzliche Informationsquelle verwenden, z. B. wo sich die Augen der Person befinden, sodass Sie in Ihrer App entsprechend reagieren können. Es gibt zwölf Wahrzeichen, die gefunden werden können:

  • linkes und rechtes Auge
  • linkes und rechtes Ohr
  • linkes und rechtes Ohr
  • Basis der Nase
  • linke und rechte Wange
  • linker und rechter Mundwinkel
  • Basis des Mundes

Die verfügbaren Markierungen hängen vom erkannten Winkel ab. Bei einer Person, die zur Seite zeigt, wird beispielsweise nur ein Auge sichtbar, sodass das andere Auge nicht erkannt werden kann. In der folgenden Tabelle wird beschrieben, welche Markierungen basierend auf dem Euler-Y-Winkel (Richtung nach links oder rechts) des Gesichts erkannt werden sollen.

Euler Y Sichtbare Sehenswürdigkeiten
< -36° linkes Auge, linker Mund, linkes Ohr, Nasenbasis, linke Wange
-36 ° bis -12 °     linker Mund, Nasenbasis, unterer Mund, rechtes Auge, linkes Auge, linke Wange, linke Ohrspitze
-12 ° bis 12 ° rechtes Auge, linkes Auge, Nasenwurzel, linke Wange, rechte Wange, linker Mund, rechter Mund, unterer Mund
12 ° bis 36 ° rechter Mund, Nasenbasis, unterer Mund, linkes Auge, rechtes Auge, rechte Wange, rechte Ohrspitze
> 36 ° rechtes Auge, rechter Mund, rechtes Ohr, Nasenbasis, rechte Wange

Sehenswürdigkeiten sind in Ihrer Anwendung auch unglaublich einfach zu verwenden, da Sie sie bereits während der Gesichtserkennung integriert haben. Sie müssen einfach anrufen getLandmarks () auf einen Gesicht Gegenstand, um eine Liste von Wahrzeichen Objekte, mit denen Sie arbeiten können.

In diesem Lernprogramm zeichnen Sie einen kleinen Kreis auf jeden erkannten Orientierungspunkt, indem Sie eine neue Methode aufrufen, drawFaceLandmarks (Leinwand, doppelte Skalierung), von onDraw (Leinwand Leinwand) anstatt drawFaceBox (Leinwand, doppelte Skala). Diese Methode nimmt die Position jedes Orientierungspunkts, passt sie an den Maßstab der Bitmap an und zeigt dann den Markierungskreis für den Orientierungspunkt an.

private void drawFaceLandmarks (Leinwand, doppelte Skalierung) Paint paint = new Paint (); paint.setColor (Color.GREEN); paint.setStyle (Paint.Style.STROKE); paint.setStrokeWidth (5); für (int i = 0; i < mFaces.size(); i++ )  Face face = mFaces.valueAt(i); for ( Landmark landmark : face.getLandmarks() )  int cx = (int) ( landmark.getPosition().x * scale ); int cy = (int) ( landmark.getPosition().y * scale ); canvas.drawCircle( cx, cy, 10, paint );   

Nach dem Aufruf dieser Methode sollten Sie kleine grüne Kreise sehen, die die erkannten Gesichter abdecken, wie im folgenden Beispiel gezeigt.

4. Zusätzliche Gesichtsdaten

Die Position eines Gesichts und seine Markierungen sind zwar nützlich, Sie können jedoch auch mithilfe einiger integrierter Methoden in der App weitere Informationen zu jedem in Ihrer App erkannten Gesicht herausfinden Gesicht Objekt. Das getIsSmilingProbability ()getIsLeftEyeOpenProbability () und getIsRightEyeOpenProbability () Methoden versuchen zu ermitteln, ob die Augen geöffnet sind oder ob die erkannte Person lächelt, indem sie einen Float aus dem Bereich zurückgeben 0,0 zu 1,0. Je näher der Wert bei 1,0 liegt, desto wahrscheinlicher ist es, dass die Person lächelt oder das linke oder rechte Auge geöffnet hat.

Sie können den Winkel des Gesichts auch auf den Y- und Z-Achsen eines Bildes ermitteln, indem Sie die Euler-Werte überprüfen. Der Z-Euler-Wert wird immer ausgegeben. Sie müssen jedoch den genauen Modus verwenden, wenn Sie Gesichter erkennen, um den X-Wert zu erhalten. Ein Beispiel für das Abrufen dieser Werte finden Sie im folgenden Codeausschnitt.

private void logFaceData () float smilingProbability; float leftEyeOpenProbability; float rightEyeOpenProbability; schweben eulerY; Float EulerZ; für (int i = 0; i < mFaces.size(); i++ )  Face face = mFaces.valueAt(i); smilingProbability = face.getIsSmilingProbability(); leftEyeOpenProbability = face.getIsLeftEyeOpenProbability(); rightEyeOpenProbability = face.getIsRightEyeOpenProbability(); eulerY = face.getEulerY(); eulerZ = face.getEulerZ(); Log.e( "Tuts+ Face Detection", "Smiling: " + smilingProbability ); Log.e( "Tuts+ Face Detection", "Left eye open: " + leftEyeOpenProbability ); Log.e( "Tuts+ Face Detection", "Right eye open: " + rightEyeOpenProbability ); Log.e( "Tuts+ Face Detection", "Euler Y: " + eulerY ); Log.e( "Tuts+ Face Detection", "Euler Z: " + eulerZ );  

Fazit

In diesem Lernprogramm haben Sie etwas über eine der Hauptkomponenten der Play Services Vision-Bibliothek erfahren, Gesichtserkennung. Sie wissen jetzt, wie Sie Gesichter in einem Standbild erkennen, Informationen sammeln und wichtige Orientierungspunkte für jedes Gesicht finden.

Mit dem Gelernten sollten Sie in der Lage sein, Ihren eigenen Apps einige großartige Funktionen hinzuzufügen, um Standbilder zu vergrößern, Gesichter in einem Video-Feed zu verfolgen oder alles, was Sie sich vorstellen können.