Identifizieren von Personen mit dem Snapdragon SDK von Qualcomm
German (Deutsch) translation by Władysław Łucyszyn (you can also view the original English article)
Es ist noch nicht lange her, da war das Fotografieren ziemlich teuer. Kameras erforderten Film mit begrenzter Kapazität und das Betrachten der Ergebnisse erforderte auch zusätzliche Zeit und mehr Geld. Diese inhärenten Einschränkungen sorgten dafür, dass wir bei den von uns aufgenommenen Fotos selektiv waren.
Schneller Vorlauf bis heute und diese Einschränkungen wurden dank der Technologie abgebaut, aber wir stehen jetzt vor einem neuen Problem, dem Filtern, Organisieren und Aufdecken wichtiger Fotos aus den vielen, die wir aufnehmen.
Dieses neue Problem hat dieses Tutorial inspiriert. Darin werde ich demonstrieren, wie wir mit neuen Tools das Leben der Benutzer erleichtern können, indem wir neue Möglichkeiten zum Filtern und Organisieren unserer Inhalte einführen.
1. Konzept
Für dieses Projekt werden wir uns eine andere Methode ansehen, um Ihre Fotosammlung zu filtern. Unterwegs erfahren Sie, wie Sie das Snapdragon SDK von Qualcomm für die Gesichtsverarbeitung und -erkennung integrieren und verwenden.
Wir werden es dem Benutzer ermöglichen, eine Sammlung von Fotos nach Identität/Identitäten zu filtern. Die Sammlung wird nach Identitäten aus einem Foto gefiltert, auf das der Benutzer tippt, wie unten gezeigt.



2. Übersicht
Der Schwerpunkt dieses Beitrags liegt auf der Einführung der Gesichtsverarbeitung und -erkennung mit dem Snapdragon SDK von Qualcomm, während – hoffentlich – indirekt neue Denkweisen gefördert und von Inhalten abgeleitete Metadaten verwendet werden.
Damit ich mich nicht auf die Klempnerarbeit versteifen kann, habe ich eine Vorlage erstellt, die den grundlegenden Service zum Durchsuchen der Fotosammlung des Benutzers und ein Raster zum Anzeigen der Fotos bietet. Unser Ziel ist es, dies mit dem oben vorgeschlagenen Konzept zu verbessern.
Im folgenden Abschnitt werden wir diese Komponenten kurz überprüfen, bevor wir mit der Einführung von Qualcomms Snapdragon SDK fortfahren.
3. Skelett
Wie oben erwähnt, ist es unser Ziel, uns auf das Snapdragon SDK zu konzentrieren, daher habe ich ein Skelett erstellt, in dem alle Installationen implementiert sind. Unten finden Sie ein Diagramm und eine Beschreibung des Projekts, die von GitHub heruntergeladen werden können.



Unser data-Paket enthält eine Implementierung von SQLiteOpenHelper
(IdentityGalleryDatabase
), die für die Erstellung und Verwaltung unserer Datenbank verantwortlich ist. Die Datenbank besteht aus drei Tabellen, eine als Zeiger auf den Mediendatensatz (photo
), eine andere für erkannte Identitäten (indentity
) und schließlich die Beziehungstabelle, die Identitäten mit ihren Fotos verbindet (identity_photo
).



Wir werden die Identitätstabelle verwenden, um die vom Snapdragon SDK bereitgestellten Attribute zu speichern, die in einem späteren Abschnitt dieses Tutorials beschrieben werden.
Das Datenpaket enthält auch eine Provider
-(IdentityGalleryProvider
) und eine Contract
-Klasse (IdentityGalleryContract
), die nichts anderes als ein Standard-Provider
ist, der als Wrapper der SQLiteOpenHelper
-Klasse fungiert.
Um Ihnen ein Gefühl für die Interaktion mit der Provider
-Klasse zu geben, stammt der folgende Code aus der TestProvider
-Klasse. Wie der Name schon sagt, wird es zum Testen der Provider
-Klasse verwendet.
1 |
//… Query for all Photos
|
2 |
Cursor cursor = mContext.getContentResolver().query( |
3 |
IdentityGalleryContract.PhotoEntity.CONTENT_URI, |
4 |
null, |
5 |
null, |
6 |
null, |
7 |
null
|
8 |
);
|
9 |
|
10 |
//… Query for all Photos that include any of the identities within the referenced photo
|
11 |
Cursor cursor = mContext.getContentResolver().query( |
12 |
IdentityGalleryContract.PhotoEntity.buildUriWithReferencePhoto(photoId), |
13 |
null, |
14 |
null, |
15 |
null, |
16 |
null
|
17 |
);
|
18 |
|
19 |
//… Query call identities
|
20 |
Cursor cursor = mContext.getContentResolver().query( |
21 |
IdentityGalleryContract.IdentityEntity.CONTENT_URI, |
22 |
null, |
23 |
null, |
24 |
null, |
25 |
null
|
26 |
);
|
27 |
|
28 |
//… Query for all
|
29 |
Cursor cursor = mContext.getContentResolver().query( |
30 |
IdentityGalleryContract.PhotoEntity.CONTENT_URI, |
31 |
null, |
32 |
null, |
33 |
null, |
34 |
null
|
35 |
);
|
Das service-Paket ist für das Durchlaufen, Katalogisieren und eventuelle Verarbeiten der über den MediaStore
verfügbaren Bilder verantwortlich. Der Dienst selbst erweitert den IntentService
, um die Verarbeitung in einem eigenen Thread einfach durchzuführen. Die eigentliche Arbeit wird an den GalleryScanner
delegiert, die Klasse, die wir für die Gesichtsverarbeitung und -erkennung erweitern werden.
Dieser GalleryScannerIntentService
wird jedes Mal instanziiert, wenn die MainActivity
mit dem folgenden Aufruf erstellt wird:
1 |
@Override
|
2 |
protected void onCreate(Bundle savedInstanceState) { |
3 |
...
|
4 |
GalleryScannerIntentService.startActionScan(this.getApplicationContext()); |
5 |
...
|
6 |
}
|
Beim Start holt sich GalleryScannerIntentService
das letzte Scandatum und übergibt dieses an den Konstruktor des GalleryScanner
. Anschließend wird die scan
-Methode aufgerufen, um die Iteration durch den Inhalt des MediaItem
-Inhaltsanbieters zu starten – für Elemente nach dem letzten Scandatum.
Wenn Sie die scan
-Methode der GalleryScanner
-Klasse überprüfen, werden Sie feststellen, dass sie ziemlich ausführlich ist - hier passiert nichts Kompliziertes. Die Methode muss intern (MediaStore.Images.Media.INTERNAL_CONTENT_URI
) und extern (MediaStore.Images.Media.EXTERNAL_CONTENT_URI
) gespeicherte Mediendateien abfragen. Jedes Element wird dann an eine Hook-Methode übergeben, in der wir unseren Code für die Gesichtsverarbeitung und -erkennung platzieren.
1 |
private void processImage(ContentValues contentValues, Uri contentUri) { |
2 |
throw new UnsupportedOperationException("Hook method is not currently implemented"); |
3 |
}
|
Weitere zwei Hook-Methoden in der GalleryScanner
-Klasse stehen uns (wie die Methodennamen vermuten) zur Verfügung, um die FacialProcessing
-Instanz zu initialisieren und zu Deinitialisieren.
1 |
private void initFacialProcessing() throws UnsupportedOperationException { |
2 |
throw new UnsupportedOperationException("Hook method is not currently implemented"); |
3 |
}
|
4 |
|
5 |
private void deinitFacialProcessing() { |
6 |
throw new UnsupportedOperationException("Hook method is not currently implemented"); |
7 |
}
|
Das letzte Paket ist das Präsentationspaket. Wie der Name schon sagt, beherbergt es die Activity
-Klasse, die für das Rendern unserer Galerie verantwortlich ist. Die Galerie ist eine GridView
, die an einen CursorAdapter
angehängt ist. Wie oben erläutert, wird beim Tippen auf ein Element die Datenbank nach Fotos abgefragt, die eine der Identitäten des ausgewählten Fotos enthalten. Wenn Sie beispielsweise auf ein Foto Ihrer Freundin Lisa und ihres Freundes Justin tippen, filtert die Abfrage alle Fotos, die entweder Lisa oder Justin oder beide enthalten.
4. Qualcomms Snapdragon SDK
Um Entwicklern dabei zu helfen, ihre Hardware großartig aussehen zu lassen und ihr gerecht zu werden, hat Qualcomm eine erstaunliche Reihe von SDKs veröffentlicht, darunter das Snapdragon SDK. Das Snapdragon SDK stellt einen optimierten Satz von Funktionen für die Gesichtsverarbeitung bereit.
Das SDK gliedert sich grob in zwei Teile, Gesichtsverarbeitung und Gesichtserkennung. Da nicht alle Geräte beide – oder nur eine – dieser Funktionen unterstützen, was wahrscheinlich der Grund für die Trennung dieser Funktionen ist, bietet das SDK eine einfache Möglichkeit zu überprüfen, welche Funktionen das Gerät unterstützt. Wir werden dies später genauer behandeln.
Die Gesichtsverarbeitung bietet eine Möglichkeit, Merkmale aus einem Foto (eines Gesichts) zu extrahieren, einschließlich:
- Blinzelerkennung: Messen Sie, wie offen jedes Auge ist.
- Blickverfolgung: Bewerten Sie, wohin das Motiv schaut.
- Smile Value: Schätzen Sie den Grad des Lächelns.
- Gesichtsausrichtung: Verfolgen Sie das Gieren, Neigen und Rollen des Kopfes.
Die Gesichtserkennung bietet, wie der Name schon sagt, die Möglichkeit, Personen auf einem Foto zu identifizieren. Es ist erwähnenswert, dass die gesamte Verarbeitung lokal erfolgt – im Gegensatz zur Cloud.
Diese Funktionen können in Echtzeit (Video/Kamera) oder offline (Galerie) verwendet werden. In unserer Übung verwenden wir diese Funktionen offline, es gibt jedoch nur minimale Unterschiede zwischen den beiden Ansätzen.
Weitere Informationen zur Gesichtsverarbeitung und Gesichtserkennung finden Sie in der Online-Dokumentation für unterstützte Geräte.
5. Gesichtsverarbeitung und -erkennung hinzufügen
In diesem Abschnitt werden wir diese Hook-Methoden mit überraschend wenigen Codezeilen ausfüllen, um unserer Anwendung die Möglichkeit zu geben, Gesichtseigenschaften zu extrahieren und Personen zu identifizieren. Um mitzuarbeiten, laden Sie die Quelle von GitHub herunter und öffnen Sie das Projekt in Android Studio. Alternativ können Sie das fertige Projekt herunterladen.
Schritt 1: Installieren des Snapdragon SDK
Als erstes müssen wir das SDK von der Qualcomm-Website herunterladen. Beachten Sie, dass Sie sich registrieren/einloggen und den Nutzungsbedingungen von Qualcomm zustimmen müssen.
Entarchivieren Sie nach dem Herunterladen den Inhalt und navigieren Sie zu /Snapdragon_sdk_2.3.1/java/libs/libs_facial_processing/. Kopieren Sie die Datei sd-sdk-facial-processing.jar in den Ordner /app/libs/ Ihres Projekts, wie unten gezeigt.



Nachdem Sie das Snapdragon SDK kopiert haben, klicken Sie mit der rechten Maustaste auf sd-sdk-facial-processing.jar und wählen Sie Als Bibliothek hinzufügen... aus der Liste der Optionen.



Dadurch wird die Bibliothek als Abhängigkeit in Ihre build.gradle-Datei eingefügt, wie unten gezeigt.
1 |
dependencies { |
2 |
compile fileTree(dir: 'libs', include: ['*.jar']) |
3 |
compile files('libs/sd-sdk-facial-processing.jar') |
4 |
compile 'com.android.support:support-v13:20.0.0' |
5 |
}
|
Der letzte Schritt besteht darin, die native Bibliothek hinzuzufügen. Erstellen Sie dazu einen Ordner namens jniLibs in Ihrem /app/src/main/-Ordner und kopieren Sie den armeabi-Ordner (aus dem SDK-Download) und seinen Inhalt hinein.



Wir sind nun bereit, die Logik zu implementieren, um Personen zu identifizieren, die die Funktionen der API verwenden. Die folgenden Codeausschnitte gehören zur GalleryScanner
-Klasse.
Schritt 2: Initialisierung
Lassen Sie uns zunächst die Initialisierungs-Hook-Methode behandeln.
1 |
private void initFacialProcessing() throws UnsupportedOperationException{ |
2 |
if( |
3 |
!FacialProcessing.isFeatureSupported(FacialProcessing.FEATURE_LIST.FEATURE_FACIAL_PROCESSING) || !FacialProcessing.isFeatureSupported(FacialProcessing.FEATURE_LIST.FEATURE_FACIAL_RECOGNITION)){ |
4 |
throw new UnsupportedOperationException("Facial Processing or Recognition is not supported on this device"); |
5 |
}
|
6 |
|
7 |
mFacialProcessing = FacialProcessing.getInstance(); |
8 |
if(mFacialProcessing != null){ |
9 |
mFacialProcessing.setRecognitionConfidence(mConfidenceThreshold); |
10 |
mFacialProcessing.setProcessingMode(FacialProcessing.FP_MODES.FP_MODE_STILL); |
11 |
loadAlbum(); |
12 |
} else{ |
13 |
throw new UnsupportedOperationException(“An instance is already in use"); |
14 |
}
|
15 |
}
|
Wir müssen zunächst überprüfen, ob das Gerät sowohl die Gesichtsverarbeitung als auch die Gesichtserkennung unterstützt. Wenn dies nicht der Fall ist, lösen wir eine UnsupportedOperationException
-Ausnahme aus.
Danach weisen wir unsere lokale Referenz der FacialProcessing
-Klasse mFacialProcessing
mit der Factory-Methode getInstance
einer neuen Instanz zu. Dies gibt null
zurück, wenn eine Instanz bereits verwendet wird. In diesem Fall muss der Verbraucher die release
für diese Referenz aufrufen.
Wenn wir erfolgreich eine Instanz eines FacialProcessing
-Objekts erhalten haben, konfigurieren wir es, indem wir zuerst die Konfidenz festlegen. Dazu verwenden wir eine lokale Variable, die in diesem Fall 57
aus einem Bereich von 0 bis 100 ist. Die Konfidenz ist ein Schwellenwert, wenn versucht wird, Identitäten aufzulösen. Alle Übereinstimmungen unter diesem Schwellenwert werden als separate Identitäten betrachtet.
Was die Ermittlung des Wertes angeht, ist dies, soweit ich das beurteilen kann, ein Versuch und Irrtum. Offensichtlich ist die Erkennung umso genauer, je höher der Schwellenwert ist, mit dem Nachteil, dass die Anzahl der falsch-positiven Ergebnisse erhöht wird.
Dann setzen wir den FacialProcessing
-Modus auf FP_MODE_STILL
. Ihre Optionen sind hier entweder FP_MODE_STILL
oder FP_MODE_VIDEO
. Wie die Namen vermuten lassen, ist eines für Standbilder optimiert, während das andere für kontinuierliche Frames optimiert ist, beide mit offensichtlichen Anwendungsfällen.
P_MODE_STILL
liefert, wie Sie vielleicht vermuten, genauere Ergebnisse. Aber wie Sie später sehen werden, wird FP_MODE_STILL
von der Methode, mit der wir das Bild verarbeiten, impliziert, sodass diese Zeile weggelassen werden kann. Ich habe es nur der Vollständigkeit halber hinzugefügt.
Wir rufen dann loadAlbum
(Methode der GalleryScanner
-Klasse) auf, worauf wir als nächstes eingehen werden.
1 |
private void loadAlbum(){ |
2 |
SharedPreferences sharedPreferences = mContext.getSharedPreferences(TAG, 0); |
3 |
String arrayOfString = sharedPreferences.getString(KEY_IDENTITY_ALBUM, null); |
4 |
|
5 |
byte[] albumArray = null; |
6 |
if (arrayOfString != null) { |
7 |
String[] splitStringArray = arrayOfString.substring(1, |
8 |
arrayOfString.length() - 1).split(", "); |
9 |
|
10 |
albumArray = new byte[splitStringArray.length]; |
11 |
for (int i = 0; i < splitStringArray.length; i++) { |
12 |
albumArray[i] = Byte.parseByte(splitStringArray[i]); |
13 |
}
|
14 |
mFacialProcessing.deserializeRecognitionAlbum(albumArray); |
15 |
}
|
16 |
}
|
Die einzige interessante Zeile hier ist:
1 |
mFacialProcessing.deserializeRecognitionAlbum(albumArray); |
Seine Zählermethode ist:
1 |
byte[] albumBuffer = mFacialProcessing.serializeRecogntionAlbum(); |
Eine einzelne FacialProcessing
-Instanz kann als Sitzung betrachtet werden. Hinzugefügte Personen (unten erläutert) werden in dieser Instanz lokal gespeichert (als "Erkennungsalbum" bezeichnet). Damit Ihr Album über mehrere Sitzungen hinweg bestehen bleibt, d.h. jedes Mal, wenn Sie eine neue Instanz erhalten, müssen Sie diese beibehalten und laden können.
Die Methode serializeRecognitionAlbum
konvertiert das Album in ein Byte-Array und umgekehrt lädt deserializeRecognitionAlbum
ein zuvor gespeichertes Album als Byte-Array und analysiert es.
Schritt 3: Deinitialisierung
Wir wissen jetzt, wie die FacialProcessing
-Klasse für die Gesichtsverarbeitung und -erkennung initialisiert wird. Wenden wir uns nun der Deinitialisierung zu, indem wir die Methode deinitFacialProcessing
implementieren.
1 |
private void deinitFacialProcessing(){ |
2 |
if(mFacialProcessing != null){ |
3 |
saveAlbum(); |
4 |
mFacialProcessing.release(); |
5 |
mFacialProcessing = null; |
6 |
}
|
7 |
}
|
Wie oben erwähnt, kann es immer nur eine Instanz der FacialProcessing
-Klasse gleichzeitig geben, daher müssen wir sicherstellen, dass wir sie freigeben, bevor wir unsere Aufgabe beenden. Wir tun dies über eine release
-Methode. Aber zuerst lassen wir das Anerkennungsalbum bestehen, damit wir die Ergebnisse über mehrere Sitzungen hinweg verwenden können. In diesem Fall möchten wir beim Aufnehmen oder Empfangen neuer Fotos sicherstellen, dass wir die zuvor erkannten Identitäten für dieselben Personen verwenden.
1 |
private void saveAlbum(){ |
2 |
byte[] albumBuffer = mFacialProcessing.serializeRecogntionAlbum(); |
3 |
SharedPreferences sharedPreferences = mContext.getSharedPreferences(TAG, 0); |
4 |
SharedPreferences.Editor editor = sharedPreferences.edit(); |
5 |
editor.putString(KEY_IDENTITY_ALBUM, Arrays.toString(albumBuffer)); |
6 |
editor.commit(); |
7 |
}
|
Schritt 4: Verarbeiten des Bildes
Wir sind endlich bereit, die letzte Hook-Methode auszuarbeiten und die FacialProcessing
-Klasse zu verwenden. Die folgenden Codeblöcke gehören zur Methode processImage
. Ich habe sie der Übersichtlichkeit halber aufgeteilt.
1 |
private void processImage(ContentValues contentValues, Uri contentUri){ |
2 |
long photoRowId = ContentUris.parseId(contentUri); |
3 |
|
4 |
String uriAsString = contentValues.getAsString(GalleryContract.PhotoEntity.COLUMN_URI); |
5 |
Uri uri = Uri.parse(uriAsString); |
6 |
Bitmap bitmap = null; |
7 |
try{ |
8 |
bitmap = ImageUtils.getImage(mContext, uri); |
9 |
} catch(IOException e){ |
10 |
return; |
11 |
}
|
12 |
|
13 |
if(bitmap != null) { |
14 |
// continued below (1)
|
15 |
}
|
16 |
}
|
Die Methode verwendet einen Verweis auf eine Instanz der ContentValues
-Klasse, die die Metadaten für dieses Bild enthält, zusammen mit dem URI, der auf das Bild verweist. Wir verwenden dies, um das Bild in den Speicher zu laden.
Das folgende Code-Snippet soll den obigen Kommentar ersetzen // continued below (1)
.
1 |
if( !mFacialProcessing.setBitmap(bitmap)){ |
2 |
return; |
3 |
}
|
4 |
int numFaces = mFacialProcessing.getNumFaces(); |
5 |
|
6 |
if(numFaces > 0){ |
7 |
FaceData[] faceDataArray = mFacialProcessing.getFaceData(); |
8 |
|
9 |
if( faceDataArray == null){ |
10 |
Log.w(TAG, contentUri.toString() + " has been returned a NULL FaceDataArray"); |
11 |
return; |
12 |
}
|
13 |
|
14 |
for(int i=0; i<faceDataArray.length; i++) { |
15 |
FaceData faceData = faceDataArray[i]; |
16 |
if(faceData == null){ |
17 |
continue; |
18 |
}
|
19 |
// continued below (2)
|
20 |
}
|
21 |
}
|
Wie oben erwähnt, übergeben wir zunächst das statische Bild über die setBitmap
-Methode an die FacialProcessing
-Instanz. Bei Verwendung dieser Methode wird implizit der FP_MODE_STILL
-Modus verwendet. Diese Methode gibt True
zurück, wenn das Bild erfolgreich verarbeitet wurde, und False
, wenn die Verarbeitung fehlgeschlagen ist.
Die alternative Methode zum Verarbeiten von Streaming-Bildern (normalerweise für Kamera-Vorschaubilder) ist:
1 |
public boolean setFrame(byte[] yuvData, int frameWidth, int frameHeight, boolean isMirrored, FacialProcessing.PREVIEW_ROTATION_ANGLE rotationAngle) |
Die meisten Parameter sind offensichtlich. Sie müssen angeben, ob der Rahmen gespiegelt ist (dies ist normalerweise für die Frontkamera erforderlich) und ob eine Drehung angewendet wurde (normalerweise über die setDisplayOrientation
-Methode einer Camera
-Instanz eingestellt).
Wir fragen dann nach der Anzahl der erkannten Gesichter und fahren erst fort, wenn mindestens eines gefunden wird. Die getFaceData
-Methode gibt die Details für jedes erkannte Gesicht als Array von FaceData
-Objekten zurück, wobei jedes FaceData
-Objekt Gesichtsmerkmale enthält, darunter:
- Flächenbegrenzung (
FACE_RECT
) - Gesichts-, Mund- und Augenpositionen (
FACE_COORDINATES
) - Gesichtskontur (
FACE_CONTOUR
) - Grad des Lächelns (
FACE_SMILE
) - Blickrichtung (
FACE_GAZE
) - Flag, das anzeigt, ob eines der Augen (oder beide Augen) blinkt (
FACE_BLINK
) - Gieren, Nicken und Rollen des Gesichts (
FACE_ORIENTATION
) - generierte oder abgeleitete Identifikation (
FACE_IDENTIFICATION
)
Es gibt eine Überladung dieser Methode, die eine Reihe von Aufzählungen (wie oben beschrieben) für einzuschließende Merkmalspunkte benötigt, wodurch redundante Berechnungen entfernt/minimiert werden.
1 |
public FaceData[] getFaceData(java.util.EnumSet<FacialProcessing.FP_DATA> dataSet) throws java.lang.IllegalArgumentException |
Wir untersuchen nun das FaceData
-Objekt, um die Identität und die Funktionen zu extrahieren. Sehen wir uns zunächst an, wie die Gesichtserkennung funktioniert.
Der folgende Codeausschnitt soll den obigen Kommentar // continued below (2)
.
1 |
int personId = faceData.getPersonId(); |
2 |
if(personId == FacialProcessingConstants.FP_PERSON_NOT_REGISTERED){ |
3 |
personId = mFacialProcessing.addPerson(i); |
4 |
} else{ |
5 |
if(mFacialProcessing.updatePerson(personId, i) != FacialProcessingConstants.FP_SUCCESS){ |
6 |
// TODO handle error
|
7 |
}
|
8 |
}
|
9 |
|
10 |
long identityRowId = getOrInsertPerson(personId); |
11 |
|
12 |
// continued below (3)
|
Wir fordern zunächst die zugewiesene Personen-ID über die Methode getPersonId
an. Dies gibt -111
(FP_PERSON_NOT_REGISTERED
) zurück, wenn im aktuell geladenen Album keine Identität vorhanden ist, andernfalls wird die ID einer übereinstimmenden Person aus dem geladenen Album zurückgegeben.
Wenn keine Identität vorhanden ist, fügen wir sie über die addPerson
-Methode des FacialProcessing
-Objekts hinzu und übergeben ihr den Index des FaceData
-Elements, das wir gerade untersuchen. Die Methode gibt die zugewiesene Personen-ID zurück, wenn sie erfolgreich ist, andernfalls gibt sie einen Fehler zurück. Dies tritt auf, wenn versucht wird, eine bereits vorhandene Identität hinzuzufügen.
Wenn die Person alternativ mit einer in unserem geladenen Album gespeicherten Identität abgeglichen wurde, rufen wir die updatePerson
-Methode des FacialProcessing
-Objekts auf und übergeben ihr die vorhandene ID und den Index des FaceData
-Elements. Das mehrfache Hinzufügen einer Person erhöht die Erkennungsleistung. Sie können bis zu zehn Gesichter für eine einzelne Person hinzufügen.
Die letzte Zeile gibt einfach die zugehörige Identitäts-ID aus unserer Datenbank zurück und fügt sie ein, wenn die Personen-ID noch nicht existiert.
Es wird oben nicht gezeigt, aber die FaceData
-Instanz macht die Methode getRecognitionConfidence
verfügbar, um die Erkennungszuverlässigkeit (0 bis 100) zurückzugeben. Je nach Bedarf können Sie damit den Flow beeinflussen.
Das letzte Snippet zeigt, wie jedes der anderen Features von der FaceData
-Instanz abgefragt wird. In dieser Demo verwenden wir sie nicht, aber mit ein wenig Fantasie können Sie sich sicher vorstellen, wie Sie sie sinnvoll einsetzen können.
Das folgende Code-Snippet soll den obigen Kommentar // continued below (3)
.
1 |
int smileValue = faceData.getSmileValue(); |
2 |
int leftEyeBlink = faceData.getLeftEyeBlink(); |
3 |
int rightEyeBlink = faceData.getRightEyeBlink(); |
4 |
int roll = faceData.getRoll(); |
5 |
PointF gazePointValue = faceData.getEyeGazePoint(); |
6 |
int pitch = faceData.getPitch(); |
7 |
int yaw = faceData.getYaw(); |
8 |
int horizontalGaze = faceData.getEyeHorizontalGazeAngle(); |
9 |
int verticalGaze = faceData.getEyeVerticalGazeAngle(); |
10 |
Rect faceRect = faceData.rect; |
11 |
|
12 |
insertNewPhotoIdentityRecord(photoRowId, identityRowId, |
13 |
gazePointValue, horizontalGaze, verticalGaze, |
14 |
leftEyeBlink, rightEyeBlink, |
15 |
pitch, yaw, roll, |
16 |
smileValue, faceRect); |
Damit ist der Verarbeitungscode abgeschlossen. Wenn Sie zur Galerie zurückkehren und auf ein Bild tippen, sollten Sie sehen, dass alle Fotos herausgefiltert werden, die keine auf dem ausgewählten Foto identifizierten Personen enthalten.
Abschluss
Wir haben dieses Tutorial gestartet und darüber gesprochen, wie mithilfe von Technologie die Inhalte des Benutzers organisiert werden können. Beim Context Aware Computing, dessen Ziel es ist, Kontext als implizites Signal zu verwenden, um die verarmte Interaktion von Mensch zu Computer zu bereichern und die Interaktion mit Computern zu erleichtern, wird dies als Auto-Tagging bezeichnet. Durch das Markieren von Inhalten mit aussagekräftigeren und nützlicheren Daten - sowohl für den Computer als auch für uns - ermöglichen wir eine intelligentere Filterung und Verarbeitung.
Wir haben gesehen, dass dies häufig bei Textinhalten verwendet wird. Das offensichtlichste Beispiel sind Spamfilter und neuerdings auch Newsreader, aber weniger bei Rich Media-Inhalten wie Fotos, Musik und Videos. Tools wie das Snapdragon SDK bieten uns die Möglichkeit, sinnvolle Funktionen aus Rich Media zu extrahieren und ihre Eigenschaften dem Benutzer und dem Computer offenzulegen.
Es ist nicht schwer vorstellbar, wie Sie unsere Anwendung erweitern könnten, um eine Filterung basierend auf der Stimmung zu ermöglichen, indem Sie ein Lächeln als Hauptmerkmal oder soziale Aktivität verwenden, indem Sie die Anzahl der Gesichter zählen. Eine solche Implementierung ist in dieser Smart Gallery-Funktion zu sehen.