Identifiera människor med Qualcomms Snapdragon SDK

Det var inte så länge sedan att ta bilder var ganska dyrt. Kameror krävde film med begränsad kapacitet och att se resultaten krävde också ytterligare tid och mer pengar. Dessa inneboende begränsningar gjorde att vi var selektiva med de bilder vi tog.

Snabbare fram till idag och dessa begränsningar har minskat tack vare tekniken, men vi står nu inför ett nytt problem, filtrerar, organiserar och avslöjar viktiga foton från de många vi tar.

Det här nya problemet är det som inspirerade denna handledning. I det kommer jag att visa hur vi kan använda nya verktyg för att underlätta användarens liv genom att införa nya sätt att filtrera och organisera innehållet.

1. Koncept

För det här projektet ska vi titta på ett annat sätt att filtrera genom din samling bilder. Under tiden lär du dig att integrera och använda Qualcomms Snapdragon SDK för ansiktsbehandling och -känsla.

Vi kommer att göra det möjligt för användaren att filtrera en samling bilder med identitet / identiteter. Samlingen filtreras av identiteter från ett foto som användaren tappar på, vilket visas nedan.

2. Översikt

Huvudfokusen för detta inlägg är introduktionen av ansiktsbehandling och erkännande med Qualcomms Snapdragon SDK, samtidigt som man förhoppningsvis indirekt uppmuntrar till nya sätt att tänka och använda härledda metadata från innehåll.

För att undvika att bli fixerad i VVS, har jag skapat en mall som tillhandahåller den grundläggande tjänsten för skanning genom användarens samling bilder och ett galler för att visa bilderna. Vårt mål är att förbättra detta med ovanstående koncept.

I det följande avsnittet kommer vi att granska dessa komponenter kort innan de flyttas till introduktion av Qualcomms Snapdragon SDK.

3. Skelett

Som nämnts ovan är vårt mål att fokusera på Snapdragon SDK så jag har skapat ett skelett som har all rörinstallation implementerad. Nedan följer ett diagram och en beskrivning av projektet, som kan laddas ner från GitHub.

Vår data paketet innehåller en implementering av SQLiteOpenHelper (IdentityGalleryDatabase) ansvarig för att skapa och hantera vår databas. Databasen kommer att bestå av tre tabeller, en för att fungera som en pekare till medieposten (Foto), en annan för detekterade identiteter (identitet), och slutligen förhållandet bordet förbinder identiteter med sina foton (identity_photo).

Vi använder identitetstabellen för att lagra attributen som ges av Snapdragon SDK, detaljerad i ett senare avsnitt av denna handledning.

Också i datapaketet ingår a provider (IdentityGalleryProvider) och Kontrakt (IdentityGalleryContract) klass, vilket är inget mer än en standard provider agerar som ett omslag av SQLiteOpenHelper klass.

Att ge dig en känsla av hur man interagerar med provider klass, följande kod tas från testprovider klass. Som namnet antyder används den för att testa provider klass. 

// ... Fråga för alla bilder Markörmarkör = mContext.getContentResolver () .fråga (IdentityGalleryContract.PhotoEntity.CONTENT_URI, null, null, null, null); // ... Fråga för alla bilder som innehåller någon av identiteterna inom det refererade fotot Cursor cursor = mContext.getContentResolver () .fråga (IdentityGalleryContract.PhotoEntity.buildUriWithReferencePhoto (photoId), null, null, null, null); // ... Query call identities Markörmarkör = mContext.getContentResolver () .fråga (IdentityGalleryContract.IdentityEntity.CONTENT_URI, null, null, null, null); // ... Fråga för alla markörmarkör = mContext.getContentResolver () .fråga (IdentityGalleryContract.PhotoEntity.CONTENT_URI, null, null, null, null);

De service Paketet ansvarar för iterering genom, katalogisering och så småningom bearbetning av bilderna tillgängliga via MediaStore. Tjänsten i sig sträcker sig IntentService som ett enkelt sätt att utföra behandlingen på egen tråd. Det faktiska arbetet delegeras till GalleryScanner, vilken klass kommer vi att sträcka till ansiktsbehandling och erkännande.

Detta GalleryScannerIntentService är instansierad varje gång Huvudaktivitet skapas med följande samtal:

@Override protected void onCreate (Bundle savedInstanceState) ... GalleryScannerIntentService.startActionScan (this.getApplicationContext ()); ...

När startade, GalleryScannerIntentService hämtar det sista skanningsdatumet och skickar detta till konstruktören av GalleryScanner. Det kallar då skanna metod för att starta iterering genom innehållet i MediaItem innehållsleverantör-för objekt efter det senaste skanningsdatumet.

Om du inspekterar skanna metod för GalleryScanner klass, märker du att det är ganska ordentligt-inget komplicerat händer här. Metoden behöver söka efter mediefiler som sparas internt (MediaStore.Images.Media.INTERNAL_CONTENT_URI) och externt (MediaStore.Images.Media.EXTERNAL_CONTENT_URI). Varje objekt skickas sedan till en krokmetod, vilket är var vi ska placera vår kod för ansiktsbehandling och erkännande.

Private void processImage (ContentValues ​​contentValues, Uri contentUri) släng nya UnsupportedOperationException ("Hook-metoden är för närvarande inte implementerad"); 

Ytterligare två krokmetoder i GalleryScanner klassen är tillgänglig för oss (som metodnamnen antyder) för att initiera och de-initialisera FacialProcessing exempel.

privat tomt initFacialProcessing () kasta UnsupportedOperationException kasta nytt UnsupportedOperationException ("Hook-metoden implementeras inte för närvarande");  privat void deinitFacialProcessing () släng ny UnsupportedOperationException ("Hook-metoden implementeras inte för närvarande"); 

Det sista paketet är presentationspaketet. Som namnet antyder, är det värd för Aktivitet klass som ansvarar för att göra vårt galleri. Galleriet är a Gridview fäst vid a CursorAdapter. Såsom förklarats ovan kommer att peka på en artikel för att fråga databasen för några foton som innehåller en av identiteterna för det valda fotot. Om du till exempel trycker på ett foto på din vän Lisa och hennes pojkvän Justin, kommer sökningen att filtrera alla foton som innehåller antingen eller både Lisa och Justin.

4. Qualcomms Snapdragon SDK

För att hjälpa utvecklare att göra hårdvaran ser bra ut och göra det rättvisa, har Qualcomm släppt en fantastisk uppsättning SDK: en är Snapdragon SDK. Snapdragon SDK exponerar en optimerad uppsättning funktioner för ansiktsbehandling.

SDK är uppdelad i två delar, ansiktsbehandling och ansiktsigenkänning. Med tanke på att inte alla enheter stöder båda eller någon av dessa funktioner, vilket förmodligen är orsaken till att dessa funktioner är separerade, ger SDK ett enkelt sätt att kontrollera vilka funktioner enheten stöder. Vi kommer att täcka detta mer i detalj senare.

Ansiktsbehandling ger ett sätt att extrahera funktioner från ett foto (i ansiktet) inklusive:  

  • Blink Detection: Mät hur öppet varje öga är.
  • Gaze Tracking: Utvärdera var ämnet ser ut.
  • Leende värde: Uppskatta graden av leendet.
  • Ansiktsorientering: Spåra yaw, pitch och roll av huvudet.

Ansiktsigenkänning, som namnet antyder, ger möjlighet att identifiera personer i ett foto. Det är värt att notera att all bearbetning görs lokalt, i motsats till molnet.

Dessa funktioner kan användas realtid (video / kamera) eller offline (galleri). I vår övning använder vi dessa funktioner offline, men det finns minimala skillnader mellan de båda metoderna.

Läs online-dokumentationen för enheter som stöds för att lära dig mer om ansiktsbehandling och ansiktsigenkänning.

5. Lägga till ansiktsbehandling och erkännande

I det här avsnittet kommer vi att fylla i dessa krokmetoder - med överraskande få rader av kod - för att ge vår applikation möjlighet att extrahera ansiktsegenskaper och identifiera personer. För att arbeta tillsammans, ladda ner källan från GitHub och öppna projektet i Android Studio. Alternativt kan du ladda ner det färdiga projektet.

Steg 1: Installera Snapdragon SDK

Det första vi behöver göra är att ta tag i SDK från Qualcomms hemsida. Observera att du måste registrera / logga in och godkänna Qualcomms användarvillkor.

När du har laddat ner, arkiverar du innehållet och navigerar till /Snapdragon_sdk_2.3.1/java/libs/libs_facial_processing/. Kopiera sd-sdk-ansikts-processing.jar filen till ditt projekt / app / libs / mapp enligt nedanstående.

Efter att ha kopierat Snapdragon SDK högerklickar du på sd-sdk-ansikts-processing.jar och välj Lägg till som bibliotek ... från listan över alternativ.

Detta lägger till biblioteket som ett beroende i din build.gradle filen som visas nedan.

beroenden compile fileTree (dir: 'libs', inkludera: ['* .jar']) kompilera filer ('libs / sd-sdk-facial-processing.jar') kompilera 'com.android.support:support-v13: 20,0,0 '

Det sista steget är att lägga till det ursprungliga biblioteket. För att göra detta, skapa en mapp som heter jniLibs i din / App / src / main / mapp och kopiera armeabi mapp (från SDK-hämtningen) och dess innehåll i den.

Vi är nu redo att genomföra logiken för att identifiera personer som använder API: s funktionalitet. Följande kodfragment hör till i GalleryScanner klass.

Steg 2: Initialisering

Låt oss först ta itu med initialiseringskrokmetoden. 

privat tomt initFacialProcessing () kastar UnsupportedOperationException if (! Facial Processing. FetourSupported (Facial Processing.FeatURE_LIST.FEATURE_FACIAL_PROCESSING) ||! FacialProcessing.isFeatureSupported (Facial Processing.FEATURE_LIST.FEATURE_FACIAL_RECOGNITION)) släng ny UnsupportedOperationException ("Ansiktsbehandling eller erkännande stöds inte på detta anordning");  mFacialProcessing = FacialProcessing.getInstance (); om (mFacialProcessing! = null) mFacialProcessing.setRecognitionConfidence (mConfidenceThreshold); mFacialProcessing.setProcessingMode (FacialProcessing.FP_MODES.FP_MODE_STILL); loadAlbum ();  annars släng nytt UnsupportedOperationException ("En instans är redan i bruk");

Vi måste först kontrollera att enheten stöder både ansiktsbehandling och ansiktsigenkänning. Om det inte gör vi kastar en UnsupportedOperationException undantag.

Därefter tilldelar vi vår lokala referens till FacialProcessing klass, mFacialProcessing, till en ny instans med fabriksmetoden getInstance. Detta kommer att återvända null om en instans redan används, i vilket fall konsumenten är skyldig att ringa släpp på den hänvisningen.

Om vi ​​framgångsrikt fått en instans av a FacialProcessing objekt, vi konfigurerar det genom att först ställa in förtroendet. Vi gör detta med en lokal variabel, vilket är 57 i detta fall från ett intervall från 0 till 100. Förtroendet är ett tröskelvärde när man försöker lösa identiteter. Alla matchningar under denna tröskel anses vara separata identiteter.

När det gäller att bestämma värdet, så långt det jag kan säga är det här en provprocess. Självklart är ju högre tröskeln, desto mer exakt är erkännandet, med avvägningen att öka antalet falska positiva.

Vi ställer sedan in FacialProcessing läge till FP_MODE_STILL. Dina alternativ här är antingen FP_MODE_STILL eller FP_MODE_VIDEO. Som namnen antyder är en optimerad för stillbilder medan den andra för kontinuerliga ramar, båda med uppenbara användningsfall.

P_MODE_STILL, som du kan misstänka, ger mer exakta resultat. Men som du kommer se senare, FP_MODE_STILL underförstås av den metod som vi använder för att bearbeta bilden så att den här linjen kan utelämnas. Jag lade bara till det för fullständighet.

Vi ringer sedan loadAlbum (metod av GalleryScanner klass), vilket är vad vi ska titta på nästa.

privat tomt belastningAlbum () SharedPreferences sharedPreferences = mContext.getSharedPreferences (TAG, 0); String arrayOfString = sharedPreferences.getString (KEY_IDENTITY_ALBUM, null); byte [] albumArray = null; om (arrayOfString! = null) String [] splitStringArray = arrayOfString.substring (1, arrayOfString.length () - 1) .split (","); albumArray = ny byte [splitStringArray.length]; för (int i = 0; i < splitStringArray.length; i++)  albumArray[i] = Byte.parseByte(splitStringArray[i]);  mFacialProcessing.deserializeRecognitionAlbum(albumArray);  

Den enda intressanta linjen här är:

mFacialProcessing.deserializeRecognitionAlbum (albumArray);

Dess räknemetod är:

byte [] albumBuffer = mFacialProcessing.serializeRecogntionAlbum ();

En enda FacialProcessing Exempel kan ses som en session. Tillagda personer (förklaras nedan) lagras lokalt (hänvisat till som "recognition album") inom det exemplet. För att låta ditt album fortsätta över flera sessioner, det vill säga varje gång du får en ny instans behöver du ett sätt att fortsätta och ladda dem.

De serializeRecogntionAlbum Metoden omvandlar albumet till en byte array och omvänt deserializeRecognitionAlbum kommer att ladda och analysera ett tidigare lagrat album som en byte array.

Steg 3: De-initialisering

Vi vet nu hur man initialiserar FacialProcessing klass för ansiktsbehandling och erkännande. Låt oss nu vända vårt fokus för att de-initialisera det genom att implementera deinitFacialProcessing metod.

privat void deinitFacialProcessing () if (mFacialProcessing! = null) saveAlbum (); mFacialProcessing.release (); mFacialProcessing = null; 

Som nämnts ovan kan det bara vara en förekomst av FacialProcessing klass i taget så vi måste se till att vi släpper det innan vi avslutar vår uppgift. Vi gör det via a släpp metod. Men först gör vi det erkännande albumet kvarstår så att vi kan använda resultaten över flera sessioner. I det här fallet vill vi, när användaren tar eller tar emot nya foton, se till att vi använder de tidigare kända identiteterna för samma personer.

privat void saveAlbum () byte [] albumBuffer = mFacialProcessing.serializeRecogntionAlbum (); SharedPreferences sharedPreferences = mContext.getSharedPreferences (TAG, 0); SharedPreferences.Editor editor = sharedPreferences.edit (); editor.putString (KEY_IDENTITY_ALBUM, Arrays.toString (albumBuffer)); editor.commit (); 

Steg 4: Bearbetar bilden

Vi är äntligen redo att krossa den slutliga krokmetoden och använda FacialProcessing klass. Följande kodblock tillhör processImage metod. Jag har delat upp dem för tydlighet.

Private void processImage (ContentValues ​​contentValues, Uri contentUri) långt fotoRowId = ContentUris.parseId (contentUri); String uriAsString = contentValues.getAsString (GalleryContract.PhotoEntity.COLUMN_URI); Uri uri = Uri.parse (uriAsString); Bitmapp bitmapp = null; prova bitmapp = ImageUtils.getImage (mContext, uri);  fånga (IOException e) return;  om (bitmapp! = null) // fortsatte nedan (1)

Metoden hänvisar till en instans av ContentValues klass, som innehåller metadata för den här bilden tillsammans med URI som pekar på bilden. Vi använder detta för att ladda bilden i minnet.

Följande kodbit ska ersätta ovanstående kommentar // fortsatte nedan (1).

om (! mFacialProcessing.setBitmap (bitmapp)) return;  int numFaces = mFacialProcessing.getNumFaces (); om (numFaces> 0) FaceData [] faceDataArray = mFacialProcessing.getFaceData (); om (faceDataArray == null) Log.w (TAG, contentUri.toString () + "har returnerats en NULL FaceDataArray"); lämna tillbaka;  för (int i = 0; i

Som nämnts ovan skickar vi först den statiska bilden till FacialProcessing exempel via SetBitmap metod. Användning av denna metod använder implicit användningen av FP_MODE_STILL läge. Denna metod returnerar Sann om bilden lyckades bearbetas och Falsk om behandlingen misslyckades.

Alternativmetoden för bearbetning av strömmande bilder (vanligtvis för kamerabildramar) är:

public boolean setFrame (byte [] yuvData, int frameWidth, int frameHeight, boolean isMirrored, FacialProcessing.PREVIEW_ROTATION_ANGLE rotationAngle) 

De flesta parametrarna är uppenbara. Du måste passera om ramen är vänd (det är vanligtvis nödvändigt för den främre kameran) och om någon rotation har tillämpats (vanligtvis inställd via setDisplayOrientation Metod av a Kamera exempel).

Vi frågar sedan för antalet ansikten som detekterats och fortsätter endast om minst en finns. De getFaceData Metoden returnerar detaljerna för varje detekterat ansikte som en uppsättning av FaceData objekt, var vardera FaceData Objektet inkapslar ansiktsfunktioner, inklusive:

  • ansiktsgräns (FACE_RECT)
  • ansikte, mun och ögonplatser (FACE_COORDINATES)
  • kontur av ansiktet (FACE_CONTOUR)
  • grad av leende (FACE_SMILE)
  • ögonriktning (FACE_GAZE)
  • flagga som indikerar om ett öga (eller båda ögonen) blinkar (FACE_BLINK)
  • yaw, pitch och ansiktsrull (FACE_ORIENTATION)
  • genererad eller härledd identifiering (FACE_IDENTIFICATION)

Det finns en överbelastning för denna metod som tar en uppsättning enummar (som beskrivits ovan) för att funktionspunkter ska inkluderas, avlägsnande / minimering av redundanta beräkningar.

offentlig FaceData [] getFaceData (java.util.EnumSet dataSet) kastar java.lang.IllegalArgumentException 

Vi fortsätter nu med att inspektera FaceData motsätta sig identiteten och funktionerna. Låt oss först se hur ansiktsigenkänning är klar.

Följande kodbit ska ersätta ovanstående kommentar // fortsatte nedan (2).

int personId = faceData.getPersonId (); om (personId == FacialProcessingConstants.FP_PERSON_NOT_REGISTERED) personId = mFacialProcessing.addPerson (i);  annat om (mFacialProcessing.updatePerson (personId, i)! = FacialProcessingConstants.FP_SUCCESS) // TODO hantera fel lång identityRowId = getOrInsertPerson (personId); // fortsatte nedan (3)

Vi begär först den tilldelade personens ID via getPersonId metod. Detta kommer att återvända -111 (FP_PERSON_NOT_REGISTERED) om det inte finns någon identitet i det aktuella inlägget, annars returnerar du en matchande persons ID från det laddade albumet.

Om det inte finns någon identitet, lägger vi till det via addPerson metod för FacialProcessing objekt, passerar det indexet för FaceData objekt vi inspekterar för närvarande. Metoden returnerar det tilldelade person-idet om det lyckades, annars returnerar ett fel. Detta inträffar när du försöker lägga till en identitet som redan finns.

Alternativt, när personen matchades med en identitet lagrad i vårt laddade album, kallar vi FacialProcessing objekt updatePerson metod, passerar den befintliga id och index för FaceData Artikel. Att lägga till en person flera gånger ökar erkännandeprestandan. Du kan lägga till upp till tio ansikten för en enda person.

Den slutliga raden returnerar helt enkelt det associerade ID-numret från vår databas och infogar det om personidentifikationen inte existerar.

Det visas inte ovan, men FaceData Exempel exponerar metoden getRecognitionConfidence för att återvända igenkänningsförtroendet (0 till 100). Beroende på dina behov kan du använda detta för att påverka flödet.

Det sista stycket visar hur man frågar var och en av de andra funktionerna från FaceData exempel. I denna demo använder vi inte dem, men med lite fantasi är jag säker på att du kan tänka på sätt att använda dem bra.

Följande kodbit ska ersätta ovanstående kommentar // fortsatte nedan (3).

int smileValue = faceData.getSmileValue (); int vänsterEyeBlink = faceData.getLeftEyeBlink (); int rightEyeBlink = faceData.getRightEyeBlink (); int roll = faceData.getRoll (); PointF gazePointValue = faceData.getEyeGazePoint (); int pitch = faceData.getPitch (); int yaw = faceData.getYaw (); int horizontalGaze = faceData.getEyeHorizontalGazeAngle (); int verticalGaze = faceData.getEyeVerticalGazeAngle (); Rect faceRect = faceData.rect; insertNewPhotoIdentityRecord (photoRowId, identityRowId, gazePointValue, horizontalGaze, verticalGaze, leftEyeBlink, rightEyeBlink, pitch, yaw, roll, smileValue, faceRect); 

Det kompletterar bearbetningskoden. Om du återvänder till galleriet och trycker på en bild ska du se att det filtrerar bort några foton som inte innehåller några personer som identifierats i det valda fotot.

Slutsats

Vi startade den här handledningen om hur tekniken kan användas för att organisera användarens innehåll. I kontextmedveten databehandling, vars mål är att använda kontext som en implicit cue för att berika den fattiga interaktionen från människor till datorer, vilket gör det lättare att interagera med datorer, kallas detta auto-tagging. Genom att markera innehåll med mer meningsfull och användbar data - både för datorn och oss - tillåter vi mer intelligent filtrering och bearbetning.

Vi har sett det här bruket ofta med textinnehåll, det mest uppenbara exemplet är spamfilter och, mer nyligen, nyhetsläsare, men mindre med rich media-innehåll, till exempel foton, musik och video. Verktyg som Snapdragon SDK ger oss möjlighet att extrahera meningsfulla funktioner från rich media, exponera sina egenskaper för användaren och datorn.

Det är inte svårt att föreställa sig hur du kan förlänga vår ansökan för att tillåta filtrering baserat på känslor genom att använda ett leende som huvudfunktion eller social aktivitet genom att räkna antalet ansikten. Ett sådant genomförande kan ses i den här Smart Gallery-funktionen.