Eine Einführung in die Gesichtserkennung auf Android
() translation by (you can also view the original English article)
Mit den Vision-Bibliotheken in Play Services 8.1 eingeführt, erleichtert Ihnen die Gesichtserkennung 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, z. B. Einhornhörnern, zu verstärken. Beachten Sie, dass die Gesichtserkennung keine Gesichtserkennung ist. 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 Sie die build.gradle-Datei Ihres Projekts und fügen Sie dem Abhängigkeitsknoten die folgende dependencies
hinzu.
1 |
compile 'com.google.android.gms:play-services-vision:8.1.0' |
Wenn Sie Play Services in Ihr Projekt aufgenommen haben, können Sie die build.gradle-Datei Ihres Projekts schließen und AndroidManifest.xml öffnen. Sie müssen ein meta-data
element hinzufügen, das die Flächenabhängigkeit unter dem application
Ihres Manifests definiert. Dadurch wird der Vision-Bibliothek mitgeteilt, dass Sie Gesichter in Ihrer Anwendung erkennen möchten.
1 |
<meta-data android:name="com.google.android.gms.vision.DEPENDENCIES" android:value="face"/> |
Wenn Sie mit der Einrichtung von AndroidManifest.xml fertig sind, können Sie sie schließen und beenden. Als Nächstes müssen Sie eine neue Klasse mit dem Namen FaceOverlayView.java erstellen. Diese Klasse erweitert die View
und enthält die Logik zum Erkennen von Gesichtern im Projekt. Sie zeigt die analysierte Bitmap und das 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
-Objekt wird zum Speichern der zu analysierenden Bitmap verwendet, und die SparseArray
of Face
-Objekte speichern alle in der Bitmap gefundenen Flächen.
1 |
public class FaceOverlayView extends View { |
2 |
|
3 |
private Bitmap mBitmap; |
4 |
private SparseArray<Face> mFaces; |
5 |
|
6 |
public FaceOverlayView(Context context) { |
7 |
this(context, null); |
8 |
}
|
9 |
|
10 |
public FaceOverlayView(Context context, AttributeSet attrs) { |
11 |
this(context, attrs, 0); |
12 |
}
|
13 |
|
14 |
public FaceOverlayView(Context context, AttributeSet attrs, int defStyleAttr) { |
15 |
super(context, attrs, defStyleAttr); |
16 |
}
|
17 |
}
|
Fügen Sie in FaceOverlayView
eine neue Methode mit dem Namen setBitmap (Bitmap-Bitmap)
hinzu. Im Moment speichert dies einfach die übergebene Bitmap. Später werden Sie diese Methode jedoch zur Analyse des Bildes verwenden.
1 |
public void setBitmap( Bitmap bitmap ) { |
2 |
mBitmap = bitmap; |
3 |
}
|
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, legen Sie es im Verzeichnis res / raw ab. In diesem Lernprogramm wird davon ausgegangen, dass das Bild face.jpg heißt.
Nachdem Sie Ihr Bild im Verzeichnis res / raw abgelegt haben, öffnen Sie res / layout / activity_main.xml. Dieses Layout enthält einen Verweis auf FaceOverlayView
, sodass es in MainActivity
angezeigt wird.
1 |
<?xml version="1.0" encoding="utf-8"?>
|
2 |
<com.tutsplus.facedetection.FaceOverlayView
|
3 |
xmlns:android="https://schemas.android.com/apk/res/android" |
4 |
android:id="@+id/face_overlay" |
5 |
android:layout_width="match_parent" |
6 |
android:layout_height="match_parent" /> |
Öffnen Sie mit dem definierten Layout MainActivity
und richten Sie die FaceOverlayView
von onCreate()
ein. Dazu erhalten Sie einen Verweis auf die Ansicht, lesen die Bilddatei face.jpg aus dem unformatierten Verzeichnis als Eingabestrom und konvertieren diese in eine Bitmap. Sobald Sie die Bitmap haben, können Sie setBitmap
in der FaceOverlayView
aufrufen, um das Bild an Ihre benutzerdefinierte Ansicht zu übergeben.
1 |
public class MainActivity extends AppCompatActivity { |
2 |
|
3 |
private FaceOverlayView mFaceOverlayView; |
4 |
|
5 |
@Override
|
6 |
protected void onCreate(Bundle savedInstanceState) { |
7 |
super.onCreate(savedInstanceState); |
8 |
setContentView(R.layout.activity_main); |
9 |
mFaceOverlayView = (FaceOverlayView) findViewById( R.id.face_overlay ); |
10 |
|
11 |
InputStream stream = getResources().openRawResource( R.raw.face ); |
12 |
Bitmap bitmap = BitmapFactory.decodeStream(stream); |
13 |
|
14 |
mFaceOverlayView.setBitmap(bitmap); |
15 |
|
16 |
}
|
17 |
}
|
2. Gesichter erkennen
Jetzt, da Ihr Projekt eingerichtet ist, können Sie jetzt Gesichter erkennen. In setBitmap (Bitmap-Bitmap)
müssen Sie einen FaceDetector
erstellen. Dies kann mit einem FaceDetector.Builder
durchgeführt werden, mit dem Sie mehrere Parameter definieren können, die bestimmen, wie schnell Gesichter erkannt werden und welche anderen Daten der FaceDetector
generiert.
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
finden Sie in der offiziellen Dokumentation auf der Android's developer website.
1 |
FaceDetector detector = new FaceDetector.Builder( getContext() ) |
2 |
.setTrackingEnabled(false) |
3 |
.setLandmarkType(FaceDetector.ALL_LANDMARKS) |
4 |
.setMode(FaceDetector.FAST_MODE) |
5 |
.build(); |
Sie müssen auch überprüfen, ob der FaceDetector
betriebsbereit ist. 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 der FaceDetector
betriebsbereit ist, können Sie Ihre Bitmap in ein Frame
-Objekt konvertieren und an den Detektor übergeben, 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 invalidate()
auf, um das erneute Zeichnen der Ansicht auszulösen.
1 |
if (!detector.isOperational()) { |
2 |
//Handle contingency
|
3 |
} else { |
4 |
Frame frame = new Frame.Builder().setBitmap(bitmap).build(); |
5 |
mFaces = detector.detect(frame); |
6 |
detector.release(); |
7 |
}
|
8 |
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. Da invalidate()
aufgerufen wurde, nachdem die Gesichter erkannt wurden, können Sie die gesamte erforderliche Logik in onDraw (Canvas Canvas)
hinzufügen. 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.
1 |
@Override
|
2 |
protected void onDraw(Canvas canvas) { |
3 |
super.onDraw(canvas); |
4 |
|
5 |
if ((mBitmap != null) && (mFaces != null)) { |
6 |
double scale = drawBitmap(canvas); |
7 |
drawFaceBox(canvas, scale); |
8 |
}
|
9 |
}
|
Die drawBitmap (Canvas Canvas)
-Methode zeichnet Ihre Bitmap auf die Leinwand und passt sie entsprechend an. Außerdem wird ein Multiplikator für die korrekte Skalierung Ihrer anderen Bemaßungen zurückgegeben.
1 |
private double drawBitmap( Canvas canvas ) { |
2 |
double viewWidth = canvas.getWidth(); |
3 |
double viewHeight = canvas.getHeight(); |
4 |
double imageWidth = mBitmap.getWidth(); |
5 |
double imageHeight = mBitmap.getHeight(); |
6 |
double scale = Math.min( viewWidth / imageWidth, viewHeight / imageHeight ); |
7 |
|
8 |
Rect destBounds = new Rect( 0, 0, (int) ( imageWidth * scale ), (int) ( imageHeight * scale ) ); |
9 |
canvas.drawBitmap( mBitmap, null, destBounds, null ); |
10 |
return scale; |
11 |
}
|
Die drawFaceBox (Canvas Canvas, Double Scale)
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 Ihr Paint
-Objekt definieren und dann durch jede Face
in Ihrem SparseArray
durchlaufen, um Position, Breite und Höhe zu ermitteln und das Rechteck auf der Leinwand mit diesen Informationen zu zeichnen.
1 |
private void drawFaceBox(Canvas canvas, double scale) { |
2 |
//paint should be defined as a member variable rather than
|
3 |
//being created on each onDraw request, but left here for
|
4 |
//emphasis.
|
5 |
Paint paint = new Paint(); |
6 |
paint.setColor(Color.GREEN); |
7 |
paint.setStyle(Paint.Style.STROKE); |
8 |
paint.setStrokeWidth(5); |
9 |
|
10 |
float left = 0; |
11 |
float top = 0; |
12 |
float right = 0; |
13 |
float bottom = 0; |
14 |
|
15 |
for( int i = 0; i < mFaces.size(); i++ ) { |
16 |
Face face = mFaces.valueAt(i); |
17 |
|
18 |
left = (float) ( face.getPosition().x * scale ); |
19 |
top = (float) ( face.getPosition().y * scale ); |
20 |
right = (float) scale * ( face.getPosition().x + face.getWidth() ); |
21 |
bottom = (float) scale * ( face.getPosition().y + face.getHeight() ); |
22 |
|
23 |
canvas.drawRect( left, top, right, bottom, paint ); |
24 |
}
|
25 |
}
|
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 der Einstellungen im FaceDetector.Builder
-Objekt spielen, um hoffentlich mehr Daten zu erhalten. Dies ist jedoch nicht garantiert.



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 vollständig, bevor es nach Landmarken sucht. Daher ist das Erkennen von Orientierungspunkten eine optionale Einstellung, die über FaceDetector.Builder
aktiviert werden kann.
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, Nasenbasis, 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, Nasenfuß, 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 getLandmarks()
für ein Face
-Objekt aufrufen, um eine List
von Landmark
-Objekten zu erhalten, mit denen Sie arbeiten können.
In diesem Lernprogramm zeichnen Sie einen kleinen Kreis auf jeden erkannten Orientierungspunkt, indem Sie eine neue Methode, drawFaceLandmarks(Canvas canvas, double scale)
, von onDraw(canvas canvas)
anstelle von drawFaceBox(Canvas canvas, double scale)
aufrufen. 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.
1 |
private void drawFaceLandmarks( Canvas canvas, double scale ) { |
2 |
Paint paint = new Paint(); |
3 |
paint.setColor( Color.GREEN ); |
4 |
paint.setStyle( Paint.Style.STROKE ); |
5 |
paint.setStrokeWidth( 5 ); |
6 |
|
7 |
for( int i = 0; i < mFaces.size(); i++ ) { |
8 |
Face face = mFaces.valueAt(i); |
9 |
|
10 |
for ( Landmark landmark : face.getLandmarks() ) { |
11 |
int cx = (int) ( landmark.getPosition().x * scale ); |
12 |
int cy = (int) ( landmark.getPosition().y * scale ); |
13 |
canvas.drawCircle( cx, cy, 10, paint ); |
14 |
}
|
15 |
|
16 |
}
|
17 |
}
|
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 Gesichtes und seine Markierungen sind zwar nützlich, Sie können jedoch mithilfe einiger integrierter Methoden über das Objekt "Face
" weitere Informationen zu jedem in Ihrer App erkannten Gesicht herausfinden. Die Methoden getIsSmilingProbability()
, getIsLeftEyeOpenProbability()
und getIsRightEyeOpenProbability()
versuchen zu ermitteln, ob die Augen geöffnet sind oder ob die erkannte Person lächelt, indem sie einen Float im Bereich von 0,0 bis 1,0 zurückgeben. 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.
1 |
private void logFaceData() { |
2 |
float smilingProbability; |
3 |
float leftEyeOpenProbability; |
4 |
float rightEyeOpenProbability; |
5 |
float eulerY; |
6 |
float eulerZ; |
7 |
for( int i = 0; i < mFaces.size(); i++ ) { |
8 |
Face face = mFaces.valueAt(i); |
9 |
|
10 |
smilingProbability = face.getIsSmilingProbability(); |
11 |
leftEyeOpenProbability = face.getIsLeftEyeOpenProbability(); |
12 |
rightEyeOpenProbability = face.getIsRightEyeOpenProbability(); |
13 |
eulerY = face.getEulerY(); |
14 |
eulerZ = face.getEulerZ(); |
15 |
|
16 |
Log.e( "Tuts+ Face Detection", "Smiling: " + smilingProbability ); |
17 |
Log.e( "Tuts+ Face Detection", "Left eye open: " + leftEyeOpenProbability ); |
18 |
Log.e( "Tuts+ Face Detection", "Right eye open: " + rightEyeOpenProbability ); |
19 |
Log.e( "Tuts+ Face Detection", "Euler Y: " + eulerY ); |
20 |
Log.e( "Tuts+ Face Detection", "Euler Z: " + eulerZ ); |
21 |
}
|
22 |
}
|
Fazit
In diesem Lernprogramm haben Sie die Gesichtserkennung von Play Services Vision kennengelernt. 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.