O introducere pentru detectarea feței pe Android

Prezentat împreună cu bibliotecile Vision din Serviciile Play 8.1, detectarea feței ușurează ca dezvoltator să analizeze un videoclip sau o imagine pentru a găsi fețe umane. După ce ați găsit o listă de fețe detectate pe o imagine, puteți aduna informații despre fiecare față, cum ar fi orientarea, probabilitatea de a zâmbi, dacă cineva are ochii deschiși sau închisi și repere specifice pe față.

Această informație poate fi utilă pentru mai multe aplicații, cum ar fi o aplicație pentru cameră care face automat o fotografie atunci când toată lumea din cadru se zâmbește cu ochii deschiși sau pentru augmentarea imaginilor cu efecte prostești, cum ar fi coarnele de unicorn. Este important să rețineți că detecția feței este nu recunoastere faciala. Deși informațiile pot fi adunate despre o față, aceste informații nu sunt folosite de biblioteca Vision pentru a determina dacă două fețe provin de la aceeași persoană.

Acest tutorial va utiliza o imagine statică pentru a rula API-ul de detectare a feței și pentru a aduna informații despre persoanele din fotografie, ilustrând, de asemenea, acele informații cu grafică suprapusă. Toate codurile pentru acest tutorial pot fi găsite pe GitHub.

Configurare 1. Proiect

Pentru a adăuga biblioteca Vision la proiectul dvs., trebuie să importați Servicii de Play 8.1 sau mai mult în proiectul dvs. Acest tutorial importa numai biblioteca Play Services Vision. Deschis proiectul tău build.gradle fișier și adăugați următoarea linie de compilare la dependențe nodul.

compile 'com.google.android.gms: play-services-vision: 8.1.0'

După ce ați inclus serviciile Play în proiectul dvs., puteți închide proiectul build.gradle fișier și deschis AndroidManifest.xml. Trebuie să adăugați o meta-date element care defineste dependenta de fata sub cerere nod al manifestației tale. Acest lucru permite bibliotecii Vision să știe că intenționați să detectați fețele din cadrul aplicației.

După ce ați terminat de configurat AndroidManifest.xml, puteți continua și închideți-o. Apoi, trebuie să creați o nouă clasă numită FaceOverlayView.java. Această clasă se extinde Vedere și conține logica pentru detectarea fețelor în proiect, afișarea bitmap-ului analizat și desenarea deasupra imaginii pentru a ilustra punctele.

Pentru moment, începeți prin adăugarea variabilelor membre în partea de sus a clasei și definirea constructorilor. Bitmap obiect va fi folosit pentru a stoca bitmap care vor fi analizate și SparseArray de Față obiectele vor stoca fiecare față găsită în bitmap.

clasa publică FaceOverlayView extinde Vizualizați privat Bitmap mBitmap; private SparseArray mFaces; public FaceOverlayView (context context) this (context, null);  public FaceOverlayView (Context context, AttributeSet attrs) acest (context, attrs, 0);  public FaceOverlayView (context context, attributeSet attrs, int defStyleAttr) super (context, attrs, defStyleAttr); 

Apoi, adăugați o nouă metodă în interiorul FaceOverlayView denumit setBitmap (bitmap bitmap). De acum, acest lucru va salva pur și simplu bitmap-ul trecut, cu toate acestea mai târziu veți folosi această metodă pentru analiza imaginii.

void public setBitmap (bitmap bitmap) mBitmap = bitmap; 

Apoi, aveți nevoie de un bitmap. Am inclus unul în proba de proiect pe GitHub, dar puteți folosi orice imagine pe care doriți să o jucați cu Face Detection și să vedeți ce funcționează și ce nu. Când ați selectat o imagine, plasați-o în res / raw director. Acest tutorial va presupune că imaginea este apelată face.jpg.

După ce ați plasat imaginea în res / raw director, deschis res / aspect / activity_main.xml. Acest aspect conține o referință la FaceOverlayView astfel încât să fie afișată în Activitate principala.

 

Cu aspectul definit, deschideți Activitate principala și configurați FaceOverlayView din onCreate (). Faceți acest lucru prin obținerea unei referințe la vizualizare, citirea textului face.jpg fișier imagine din directorul brut ca flux de intrare și conversia acestuia într-un bitmap. Odată ce aveți bitmap, puteți apela setBitmap pe FaceOverlayView pentru a transmite imaginea la vizualizarea personalizată.

clasa publica MainActivity extinde AppCompatActivity private FaceOverlayView mFaceOverlayView; @Override protejate void onCreate (Bundle savedInstanceState) super.onCreate (savedInstanceState); setContentView (R.layout.activity_main); mFaceOverlayView = (FaceOverlayView) findViewById (R.id.face_overlay); Fluxul InputStream = getResources () openRawResource (R.raw.face); Bitmap Bitmap = BitmapFactory.decodeStream (flux); mFaceOverlayView.setBitmap (bitmap); 

2. Detectarea fețelor

Acum, când proiectul dvs. este setat, este timpul să începeți să detectați chipurile. În setBitmap (bitmap bitmap) trebuie să creați o FaceDetector. Acest lucru se poate face folosind a FaceDetector.Builder, permițându-vă să definiți mai mulți parametri care afectează cât de repede vor fi detectate fețele și ce alte date FaceDetector va genera.

Setările pe care le alegeți depind de ceea ce încercați să faceți în aplicația dvs. Dacă activați căutarea reperelor, atunci fețele vor fi detectate mai lent. Ca și în majoritatea programelor, totul are compromisuri. Pentru a afla mai multe despre opțiunile disponibile pentru FaceDetector.Builder, puteți găsi documentația oficială pe site-ul dezvoltatorului Android.

Detectorul FaceDetector = nou FaceDetector.Builder (getContext ()) .setTrackingEnabled (false) .setLandmarkType (FaceDetector.ALL_LANDMARKS) .setMode (FaceDetector.FAST_MODE) .build ();

De asemenea, trebuie să aveți un control pentru a vedea dacă FaceDetector este operațional. Când un utilizator utilizează detectarea feței pentru prima dată pe dispozitivul său, serviciile Play trebuie să iasă și să obțină un set de biblioteci native mici pentru a procesa solicitarea aplicației. În timp ce acest lucru va fi aproape întotdeauna făcut înainte ca aplicația dvs. să înceapă lansarea, este important să se rezolve situația în care aceasta nu a reușit.

În cazul în care FaceDetector este operațional, atunci puteți converti bitmap-ul în a Cadru obiecte și transmiteți-le detectorului pentru a aduna date despre fețele din imagine. Când ați terminat, va trebui să eliberați detectorul pentru a preveni scurgeri de memorie. Când ați terminat de detectat fețele, apelați invalida() pentru a declanșa redenumirea vederii.

dacă (! detector.isOperational ()) / Handle contingency altceva Cadru cadru = nou Frame.Builder () setBitmap (bitmap) .build (); mFaces = detector.detect (cadru); detector.release ();  invalidate ();

Acum că ați detectat chipurile din imaginea dvs., este timpul să le folosiți. Pentru acest exemplu, pur și simplu trageți o cutie verde în jurul fiecărei fețe. De cand invalida() a fost chemat după detectarea fețelor, puteți adăuga toate logica necesară onDraw (canvas panza). Această metodă asigură faptul că bitmap-ul și fețele sunt setate, apoi se desenează bitmap-ul pe panza și apoi se desenează o cutie în jurul fiecărei fețe.

Deoarece diferite dispozitive au diferite dimensiuni de afișare, veți ține evidența dimensiunii scalate a bitmap-ului, astfel încât întreaga imagine să fie întotdeauna vizibilă pe dispozitiv și toate suprapunerile sunt desenate în mod corespunzător.

@Override protejate void onDraw (canvas panza) super.onDraw (panza); dacă ((mBitmap! = null) && (mFaces! = null)) scala dublă = drawBitmap (canvas); drawFaceBox (canvas, scale); 

drawBitmap (canvas panza) metoda atrage bitmap-ul dvs. pe panza și mărimează-l corespunzător, în timp ce returnează de asemenea un multiplicator pentru a scala corect celelalte dimensiuni.

priză dublă drawBitmap (Canvas Canvas) vizualizare dublăWidth = canvas.getWidth (); vizualizare dublăHeight = canvas.getHeight (); dublu imageWidth = mBitmap.getWidth (); dublu imageHeight = mBitmap.getHeight (); scară dublă = Math.min (vizualizare Lățimea / dimensiunea imaginii, vizualizareHeight / imagineHeight); Rect destBounds = nou Rect (0, 0, (int) (scala imageWidth *), (int) (scara imageHeight *); canvas.drawBitmap (mBitmap, null, destBounds, null); scara de revenire; 

drawFaceBox (canvas Canvas, scala dubla) metoda devine un pic mai interesant. Fiecare față care a fost detectată și salvată are o valoare de poziție deasupra și în partea stângă a fiecărei fețe. Această metodă va lua această poziție și va trage un dreptunghi verde din ea pentru a acoperi fiecare față pe baza lățimii și înălțimii acesteia.

Trebuie să vă definiți A picta obiect și apoi buclă prin fiecare Față în tine SparseArray pentru a-și găsi poziția, lățimea și înălțimea, și trage dreptunghiul pe pânză folosind acele informații.

private void drawFaceBox (canvas canvas, scala dubla) // vopseaua ar trebui sa fie definita ca o variabila member, mai degraba decat // fiind creata la fiecare cerere onDraw, dar a lasat aici pentru // emphasis. Paint vopsea = nou Paint (); paint.setColor (Color.GREEN); paint.setStyle (Paint.Style.STROKE); paint.setStrokeWidth (5); flotați stânga = 0; float top = 0; flotați dreapta = 0; fundul plutitorului = 0; pentru (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 );  

În acest moment, ar trebui să puteți rula aplicația și să vedeți imaginea cu dreptunghiuri în jurul fiecărei fețe care a fost detectată. Este important să rețineți că API-ul de detectare a feței este încă destul de nou la momentul acestei scrieri și este posibil să nu detecteze fiecare față. Puteți juca cu unele dintre setările din FaceDetector.Builder obiect pentru a obține, cu siguranță, mai multe date, deși nu este garantată.

3. Înțelegerea reperelor

Punctele de reper sunt puncte de interes pe o față. API-ul de detectare a feței nu utilizează repere pentru detectarea unei fețe, ci detectează mai degrabă o față în întregime înainte de a căuta repere. De aceea, descoperirea reperelor este o setare opțională care poate fi activată prin FaceDetector.Builder.

Puteți utiliza aceste repere ca o sursă suplimentară de informații, cum ar fi în cazul în care ochii subiectului sunt, astfel încât să puteți reacționa în mod corespunzător în cadrul aplicației dvs. Există douăsprezece repere care pot fi găsite:

  • stânga și dreapta
  • stânga și dreapta ureche
  • stânga și dreapta
  • baza nasului
  • stânga și dreapta obrajii
  • colțul stâng și drept al gurii
  • baza gurii

Reperele care sunt disponibile depind de unghiul feței detectate. De exemplu, cineva cu care se confruntă în lateral va avea doar un ochi vizibil, ceea ce înseamnă că celălalt ochi nu va fi detectabil. Tabelul următor descrie ce repere ar trebui să fie detectabile pe baza unghiului Euler Y (direcția stânga sau dreapta) a feței.

Euler Y Repere vizibile
< -36° ochiul stâng, gura stângă, urechea stângă, baza nasului, obrazul stâng
-36 ° până la -12 °     gura stângă, baza nasului, gura inferioară, ochiul drept, ochiul stâng, obrazul stâng, vârful urechii din stânga
-12 ° până la 12 ° ochiul drept, ochiul stâng, baza nasului, obrazul stâng, obrazul drept, gura stângă, gura dreaptă, gura inferioară
12 ° la 36 ° gura dreaptă, baza nasului, gura inferioară, ochiul stâng, ochiul drept, obrazul drept, vârful urechii drepte
> 36 ° ochiul drept, gura dreaptă, urechea dreaptă, baza nasului, obrazul drept

Repere sunt, de asemenea, incredibil de ușor de utilizat în aplicația dvs., așa cum le-ați inclus deja în timpul detectării feței. Trebuie doar să sunați getLandmarks () pe o Față obiecte pentru a obține o Listă de Reper obiecte cu care puteți lucra.

În acest tutorial, veți picta un cerc mic pe fiecare punct de reper detectat apelând o nouă metodă, drawFaceLandmarks (panza canvas, scală dublă), din onDraw (panza panza) in loc de drawFaceBox (canvas Canvas, scala dubla). Această metodă preia poziția fiecărui punct de reper, ajustează-o pentru scala bitmap-ului și apoi afișează cercul indicatorului de punctaj.

private void drawFaceLandmarks (Canvas canvas, scară dublă) Paint paint = new Paint (); vopsea.setColor (Color.GREEN); varianta.setStyle (Paint.Style.STROKE); paint.setStrokeWidth (5); pentru (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 );   

După ce apelați această metodă, ar trebui să vedeți cercuri mici verzi care acoperă fețele detectate așa cum se arată în exemplul de mai jos.

4. Date personale suplimentare

În timp ce poziția unei fețe și reperele sale sunt utile, puteți afla mai multe informații despre fiecare față detectată în aplicație prin intermediul unor metode integrate din Față obiect. getIsSmilingProbability ()getIsLeftEyeOpenProbability () și getIsRightEyeOpenProbability () metodele încearcă să determine dacă ochii sunt deschise sau dacă persoana detectată zâmbește returnând un flotor care variază de la 0.0 la 1.0. Cu cât este mai aproape de 1.0, cu atât este mai probabil ca acea persoană să zâmbească sau să aibă ochiul stâng sau drept deschis.

De asemenea, puteți găsi unghiul feței pe axele Y și Z ale unei imagini, verificând valorile lui Euler. Valoarea Z Euler va fi întotdeauna raportată, totuși, trebuie să utilizați modul precis atunci când detectează chipurile pentru a primi valoarea X. Puteți vedea un exemplu de obținere a acestor valori în următorul fragment de cod.

void privat logFaceData () float smilingProbability; flotați leftEyeOpenProbability; float rightEyeOpenProbability; float eulerY; float eulerZ; pentru (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 );  

Concluzie

În acest tutorial, ați învățat despre una dintre componentele principale ale bibliotecii Play Services Vision, Detectare facială. Acum știți cum să detectați fețele într-o imagine statică, cum să adunați informații și să găsiți repere importante pentru fiecare față.

Folosind ceea ce ați învățat, ar trebui să puteți adăuga câteva funcții deosebite propriilor aplicații pentru augmentarea imaginilor statice, urmărirea fețelor într-un flux video sau orice altceva ce vă puteți imagina.

Cod