Een inleiding tot gezichtsdetectie op Android

Geïntroduceerd met de Vision-bibliotheken in Play Services 8.1, maakt gezichtsdetectie het voor u als ontwikkelaar gemakkelijk om een ​​video of afbeelding te analyseren om menselijke gezichten te lokaliseren. Zodra u een lijst met gezichten hebt gevonden op een afbeelding, kunt u informatie verzamelen over elk gezicht, zoals de richting, de kans op glimlachen, of iemand zijn ogen open of gesloten heeft en specifieke herkenningspunten op hun gezicht.

Deze informatie kan handig zijn voor meerdere applicaties, zoals een camera-app die automatisch een foto maakt wanneer iedereen in het frame lacht met hun ogen open, of voor het vergroten van afbeeldingen met onzinnige effecten, zoals eenhoornhoorns. Het is belangrijk om op te merken dat Gezichtsdetectie is niet gezichtsherkenning. Hoewel informatie over een gezicht kan worden verzameld, wordt die informatie niet door de Vision-bibliotheek gebruikt om te bepalen of twee gezichten van dezelfde persoon komen.

In deze zelfstudie wordt een foto gebruikt om de gezichtsherkennings-API uit te voeren en informatie te verzamelen over de personen in de foto, terwijl deze zelf ook informatie met overlappende afbeeldingen illustreert. Alle code voor deze tutorial is te vinden op GitHub.

1. Project Setup

Als u de Vision-bibliotheek aan uw project wilt toevoegen, moet u Play Services 8.1 of hoger in uw project importeren. Deze zelfstudie importeert alleen de Play Services Vision-bibliotheek. Open jouw projecten build.gradle bestand en voeg de volgende compileerregel toe aan de afhankelijkheden knooppunt.

compileer 'com.google.android.gms: play-services-visie: 8.1.0'

Nadat u Play Services in uw project hebt opgenomen, kunt u uw project afsluiten build.gradle bestand en open AndroidManifest.xml. U moet een toevoegen meta-data item dat de gezichtsafhankelijkheid definieert onder de toepassing knooppunt van je manifest. Hierdoor weet de Vision-bibliotheek dat u gezichten in uw toepassing wilt detecteren.

Als je klaar bent met instellen AndroidManifest.xml, je kunt doorgaan en het afsluiten. Vervolgens moet u een nieuwe klasse met de naam maken FaceOverlayView.java. Deze klasse breidt zich uit Uitzicht en bevat de logica voor het detecteren van gezichten in het project, het weergeven van de geanalyseerde bitmap en het tekenen van de afbeelding om punten te illustreren.

Begin nu met het toevoegen van de lidvariabelen aan de bovenkant van de klas en het definiëren van de constructors. De Bitmap object zal worden gebruikt om de bitmap die zal worden geanalyseerd op te slaan en de SparseArray van Gezicht objecten slaan elk gezicht op dat wordt gevonden in de bitmap.

public class FaceOverlayView breidt uit View private Bitmap mBitmap; privé SparseArray mFaces; public FaceOverlayView (Context-context) this (context, null);  public FaceOverlayView (Context-context, AttributeSet attrs) this (context, attrs, 0);  public FaceOverlayView (Context-context, AttributeSet attrs, int defStyleAttr) super (context, attrs, defStyleAttr); 

Voeg vervolgens een nieuwe methode toe binnenin FaceOverlayView riep setBitmap (Bitmap bitmap). Voorlopig wordt hiermee de bitmap opgeslagen die is doorgegeven, maar later gebruikt u deze methode voor het analyseren van de afbeelding.

public void setBitmap (Bitmap bitmap) mBitmap = bitmap; 

Vervolgens hebt u een bitmap nodig. Ik heb er een opgenomen in het voorbeeldproject op GitHub, maar je kunt elke afbeelding gebruiken die je leuk zou willen zijn om met gezichtsherkenning te spelen en te zien wat werkt en wat niet. Wanneer u een afbeelding hebt geselecteerd, plaatst u deze in de res / raw directory. Deze tutorial gaat ervan uit dat de afbeelding wordt aangeroepen face.jpg.

Nadat u uw afbeelding in de res / raw map, openen res / lay-out / activity_main.xml. Deze lay-out bevat een verwijzing naar FaceOverlayView zodat het wordt weergegeven in Hoofdactiviteit.

 

Met de opmaak gedefinieerd, open Hoofdactiviteit en stel de FaceOverlayView van onCreate (). Dit doet u door een verwijzing naar het aanzicht te krijgen, het te lezen face.jpg afbeeldingsbestand uit de onbewerkte map als een invoerstroom en converteren naar een bitmap. Zodra u de bitmap hebt, kunt u bellen SetBitmap op de FaceOverlayView om de afbeelding door te geven aan uw aangepaste weergave.

public class MainActivity breidt AppCompatActivity uit private FaceOverlayView mFaceOverlayView; @Override protected void onCreate (Bundle savedInstanceState) super.onCreate (savedInstanceState); setContentView (R.layout.activity_main); mFaceOverlayView = (FaceOverlayView) vindt ViewById (R.id.face_overlay); InputStream stream = getResources (). OpenRawResource (R.raw.face); Bitmap bitmap = BitmapFactory.decodeStream (stream); mFaceOverlayView.setBitmap (bitmap); 

2. Gezichten detecteren

Nu uw project is ingesteld, is het tijd om gezichten te detecteren. In setBitmap (Bitmap bitmap) je moet een maken FaceDetector. Dit kan worden gedaan met behulp van een FaceDetector.Builder, waarmee u meerdere parameters kunt definiëren die van invloed zijn op hoe snel gezichten worden gedetecteerd en welke andere gegevens de FaceDetector zal genereren.

De instellingen die u kiest, zijn afhankelijk van wat u in uw toepassing probeert te doen. Als u het zoeken naar oriëntatiepunten inschakelt, worden gezichten langzamer gedetecteerd. Zoals met de meeste dingen in de programmering, heeft alles zijn wisselwerking. Voor meer informatie over de beschikbare opties FaceDetector.Builder, je kunt de officiële documentatie vinden op de ontwikkelaarswebsite van Android.

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

U moet ook een vinkje plaatsen om te zien of het FaceDetector is operationeel. Wanneer een gebruiker gezichtsdetectie voor het eerst op zijn apparaat gebruikt, moet Play Services worden uitgevoerd en een aantal kleine native bibliotheken krijgen om de aanvraag van uw toepassing te verwerken. Hoewel dit bijna altijd zal gebeuren voordat uw app klaar is met de lancering, is het belangrijk om de onvoorziene omstandigheden aan te nemen dat dit is mislukt.

Als het FaceDetector is operationeel, dan kunt u uw bitmap converteren naar een omlijsting object en geef het door aan de detector om gegevens over gezichten in de afbeelding te verzamelen. Als u klaar bent, moet u de detector vrijgeven om geheugenlekken te voorkomen. Als u klaar bent met het detecteren van gezichten, belt u ongeldig () om de weergave opnieuw te tekenen.

if (! detector.isOperational ()) // Omgaan met contingentie else Frame frame = nieuwe Frame.Builder (). setBitmap (bitmap) .build (); mFaces = detector.detect (frame); detector.release ();  invalidate ();

Nu dat je de gezichten in je afbeelding hebt gedetecteerd, is het tijd om ze te gebruiken. Voor dit voorbeeld teken je eenvoudig een groene doos rond elk gezicht. Sinds ongeldig () werd genoemd nadat de gezichten werden gedetecteerd, kunt u alle benodigde logica toevoegen onDraw (Canvas canvas). Deze methode zorgt ervoor dat de bitmap en gezichten worden ingesteld, tekent vervolgens de bitmap op het canvas en tekent vervolgens een vak rond elk vlak.

Omdat verschillende apparaten verschillende weergaveformaten hebben, houdt u ook de geschaalde grootte van de bitmap bij, zodat de volledige afbeelding altijd zichtbaar is op het apparaat en alle overlays op de juiste manier worden getekend.

@Override protected void onDraw (Canvas canvas) super.onDraw (canvas); if ((mBitmap! = null) && (mFaces! = null)) double scale = drawBitmap (canvas); drawFaceBox (canvas, schaal); 

De drawBitmap (Canvas canvas) methode tekent uw bitmap op het canvas en stelt deze op de juiste manier in, terwijl ook een vermenigvuldiger wordt geretourneerd voor het correct schalen van uw andere dimensies.

private double drawBitmap (Canvas canvas) double viewWidth = canvas.getWidth (); double viewHeight = canvas.getHeight (); dubbele imageWidth = mBitmap.getWidth (); double imageHeight = mBitmap.getHeight (); dubbele schaal = Math.min (viewWidth / imageWidth, viewHeight / imageHeight); Rect destBounds = new Rect (0, 0, (int) (imageWidth * schaal), (int) (imageHeight * schaal)); canvas.drawBitmap (mBitmap, null, destBounds, null); terugkeer schaal; 

De drawFaceBox (Canvas canvas, dubbele schaal) methode wordt iets interessanter. Elk gezicht dat werd gedetecteerd en opgeslagen, heeft een positiewaarde boven en links van elk gezicht. Deze methode neemt die positie in en tekent er een groene rechthoek uit om elk vlak te omvatten op basis van de breedte en hoogte.

U moet uw definiëren Verf object en loop er vervolgens doorheen Gezicht in uw SparseArray om de positie, breedte en hoogte te vinden en teken de rechthoek op het canvas met die informatie.

private void drawFaceBox (Canvas canvas, dubbele schaal) // paint moet worden gedefinieerd als een ledvariabele in plaats van // wordt gemaakt op elke onDraw-aanvraag, maar hier achtergelaten voor // emphasis. Verf verf = nieuwe verf (); paint.setColor (Color.GREEN); paint.setStyle (Paint.Style.STROKE); paint.setStrokeWidth (5); zweven links = 0; zweeftop = 0; zweven rechts = 0; zwevende bodem = 0; voor (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 );  

Op dit punt zou u uw applicatie moeten kunnen uitvoeren en uw afbeelding met rechthoeken rond elk gedetecteerd gezicht kunnen zien. Het is belangrijk op te merken dat de Gezichtsdetectie-API op het moment van schrijven nog vrij nieuw is en dat hij mogelijk niet elk gezicht detecteert. U kunt met enkele van de instellingen in de FaceDetector.Builder object om hopelijk meer gegevens te verzamelen, maar het is niet gegarandeerd.

3. Begrijpen van monumenten

Oriëntatiepunten zijn interessante punten op een gezicht. De gezichtsherkennings-API gebruikt geen oriëntatiepunten voor het detecteren van een gezicht, maar detecteert eerder een vlak in zijn geheel voordat hij naar oriëntatiepunten zoekt. Daarom is het ontdekken van herkenningspunten een optionele instelling die kan worden ingeschakeld via de FaceDetector.Builder.

U kunt deze herkenningspunten gebruiken als extra informatiebron, zoals waar de ogen van het onderwerp zijn, zodat u op gepaste wijze in uw app kunt reageren. Er zijn twaalf oriëntatiepunten die u kunt vinden:

  • linker- en rechteroog
  • linker en rechter oor
  • linker en rechter oortip
  • basis van de neus
  • linker en rechterwang
  • linker- en rechterhoek van de mond
  • basis van de mond

De oriëntatiepunten die beschikbaar zijn, zijn afhankelijk van de hoek van het gedetecteerde gezicht. Iemand die naar de zijkant kijkt, heeft bijvoorbeeld slechts één oog zichtbaar, wat betekent dat het andere oog niet detecteerbaar is. De volgende tabel geeft aan welke herkenningspunten detecteerbaar moeten zijn op basis van de Euler Y-hoek (richting links of rechts) van het gezicht.

Euler Y Zichtbare monumenten
< -36° linkeroog, linker mond, linker oor, neusbasis, linkerwang
-36 ° tot -12 °     linker mond, neusbasis, onderste mond, rechteroog, linkeroog, linkerwang, linker oorpunt
-12 ° tot 12 ° rechteroog, linkeroog, neusbasis, linkerwang, rechterwang, linker mond, rechter mond, mond onderaan
12 ° tot 36 ° rechter mond, neusbasis, ondermonding, linkeroog, rechteroog, rechterwang, rechter oorpunt
> 36 ° rechteroog, rechter mond, rechteroor, neusbasis, rechterwang

Oriëntatiepunten zijn ook ongelooflijk eenvoudig te gebruiken in uw toepassing, omdat u ze al hebt opgenomen tijdens gezichtsherkenning. U hoeft alleen maar te bellen getLandmarks () op een Gezicht object om een ​​te krijgen Lijst van mijlpaal objecten waarmee je kunt werken.

In deze zelfstudie schilder je een kleine cirkel op elk gedetecteerd oriëntatiepunt door een nieuwe methode aan te roepen, drawFaceLandmarks (Canvas canvas, dubbele schaal), van onDraw (canvasdoek) in plaats van drawFaceBox (Canvas canvas, dubbele schaal). Deze methode neemt de positie van elk oriëntatiepunt in, past deze aan voor de schaal van de bitmap en geeft vervolgens de richtinggevende indicatorcirkel weer.

private void drawFaceLandmarks (Canvas canvas, dubbele schaal) Verf verf = nieuwe verf (); paint.setColor (Color.GREEN); paint.setStyle (Paint.Style.STROKE); paint.setStrokeWidth (5); voor (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 );   

Nadat u deze methode hebt aangeroepen, ziet u kleine groene cirkels die de gedetecteerde gezichten bedekken, zoals in het onderstaande voorbeeld.

4. Aanvullende gezichtsgegevens

Hoewel de positie van een gezicht en de bijbehorende oriëntatiepunten nuttig zijn, kunt u ook meer informatie vinden over elk gezicht dat in uw app is gedetecteerd via enkele ingebouwde methoden van de Gezicht voorwerp. De getIsSmilingProbability ()getIsLeftEyeOpenProbability () en getIsRightEyeOpenProbability () methoden proberen vast te stellen of ogen open zijn of dat de persoon die wordt gedetecteerd glimlacht door een vlotter te retourneren variërend van 0.0 naar 1.0. Hoe dichter bij 1,0, hoe groter de kans dat die persoon lacht of zijn linker- of rechteroog open heeft.

U kunt ook de hoek van het vlak op de Y- en Z-assen van een afbeelding vinden door de Euler-waarden te controleren. De Z Euler-waarde wordt altijd gerapporteerd, maar u moet de nauwkeurige modus gebruiken bij het detecteren van gezichten om de X-waarde te ontvangen. U kunt een voorbeeld bekijken van hoe u deze waarden kunt ophalen in het volgende codefragment.

private void logFaceData () float smilingProbability; zweven naar links. EyeOpenProbability; float rightEyeOpenProbability; vlotterij; float eulerZ; voor (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 );  

Conclusie

In deze zelfstudie hebt u kennisgemaakt met een van de belangrijkste onderdelen van de Play Services Vision-bibliotheek, Gezichtsherkenning. U weet nu hoe gezichten in een stilstaand beeld moeten worden gedetecteerd, hoe u informatie kunt verzamelen en belangrijke oriëntatiepunten voor elk gezicht kunt vinden.

Met behulp van wat je hebt geleerd, moet je enkele geweldige functies aan je eigen apps kunnen toevoegen voor het vergroten van stilstaande beelden, het volgen van gezichten in een videofeed of iets anders dat je kunt bedenken.