Face Detection

19 aprile 2017

Un’altra caratteristica molto utile di Vision è la Face Detection, ossia la possibilità di individuare volti all’interno di foto. Come vedremo, ciò viene reso in una maniera molto intuitiva, efficiente e con gran dettaglio di informazioni. Per poter utilizzare tale funzionalità in un progetto Android Studio, dovremo:

  • includere i Google Play Services (o almeno la porzione che rappresenta le funzionalità di Vision) in una versione pari o superiore alla 7.8, inserendo nel file build.gradle del modulo applicativo la seguente dipendenza (adattando la versione a quanto disponibile nel proprio ambiente di lavoro):
    dependencies {
        ...
        ...
        compile 'com.google.android.gms:play-services-vision:10.0.0'
    }
    
  • inserire nel file AndroidManifest.xml un campo meta-data che servirà ad ottenere le dipendenze necessarie all’interpretazione dei volti:
  • <meta-data android:name="com.google.android.gms.vision.DEPENDENCIES" android:value="face"/>
    

Come utilizzare le API

Per poter utilizzare il FaceDetector, dobbiamo prima inizializzarlo tramite l’apposito Builder:

FaceDetector faceDetector = new
                FaceDetector.Builder(getApplicationContext())
                .setTrackingEnabled(false)
                .setClassificationType(FaceDetector.ALL_CLASSIFICATIONS)
                .build();

Imposteremo le caratteristiche che vorremo includere nel Detector ed invocheremo il metodo build: per il nostro esempio abbiamo scelto di non abilitare il Face Tracking (che assegna un ID univoco ad ogni volto) e di richiedere tutte le classificazioni possibili per poter identificare sorrisi ed apertura degli occhi.

Appena inizializzato il Face Detector, converrà verificarne l’operatività, condizione necessaria per poter proseguire:

if(!faceDetector.isOperational()){
            // segnalare il problema all'utente
        }

Qualora la verifica fallisse, si controlli di avere incluso il nodo meta-data sopra citato nel file AndroidManifest.xml.

Fatto ciò, il FaceDetector è pronto e saranno sufficienti solo poche righe di codice per arrivare al riconoscimento:

Frame frame = new Frame.Builder().setBitmap(img).build();
SparseArray<Face> faces = faceDetector.detect(frame);

Creato un Frame dalla Bitmap che rappresenta l’immagine da analizzare, lo passeremo al metodo detect del FaceDetector che restituirà uno SparseArray con tanti oggetti Face quanti sono i volti riconosciuti. Sarà poi sufficiente scansionare il contenuto dell’array per sfruttare i risultati nella nostra app.

Esempio pratico

In queste esempio, visualizzeremo una foto tramite una ImageView e, al click del FloatingActionButton, attiveremo il riconoscimento. In base ai dati ottenuti, disegneremo un ovale intorno al volto riconosciuto (verificheremo solo se ne è stato individuato uno ma, come presumibile, ve ne potrebbero essere più di uno) e ci faremo calcolare la probabilità che il volto stia sorridendo e che gli occhi siano aperti.

Figura 1. Risultati ottenuti con il FaceDetector (click per ingrandire)

Risultati ottenuti con il FaceDetector

Nel metodo onCreate, assegneremo il layout e svolgeremo alcuni findViewById (non mostrato nel seguente frammento) per ottenere i riferimenti all’ImageView e alle TextView che manipoleremo. Oltre ad inizializzare il FaceDetector come già indicato, istanzieremo un oggetto Paint che costituisce lo strumento di disegno.

private FaceDetector faceDetector;
    private Paint paint;
    ...

    @Override
    protected void onCreate(Bundle savedInstanceState) {
       /*
        * OMISSIS: inizializzazione UI
        */

        paint = new Paint();
        paint.setStrokeWidth(10);
        paint.setColor(Color.YELLOW);
        paint.setStyle(Paint.Style.STROKE);

        faceDetector = new
                FaceDetector.Builder(getApplicationContext())
                .setTrackingEnabled(false)
                .setClassificationType(FaceDetector.ALL_CLASSIFICATIONS)
                .build();
        if(!faceDetector.isOperational()){
            new AlertDialog.Builder(this).setMessage("Impossibile usare il FaceDetector!").show();
            return;
        }

        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                Bitmap img=((BitmapDrawable)imageView.getDrawable()).getBitmap();

                Frame frame = new Frame.Builder().setBitmap(img).build();
                SparseArray<Face> faces = faceDetector.detect(frame);

                if (faces.size()>0)
                {
                    Face detectedFace = faces.valueAt(0);
                    drawOval(img, detectedFace);
                    smile.setText(roud(detectedFace.getIsSmilingProbability()*100));
                    lefteye.setText(roud(detectedFace.getIsLeftEyeOpenProbability()*100));
                    righteye.setText(roud(detectedFace.getIsRightEyeOpenProbability()*100));
                }

            }
        });
    }

    private String roud(float num)
    {
        return String.format("%.2f", num)+"%";
    }

    private void drawOval(Bitmap img, Face face)
    {
        Bitmap bmp = Bitmap.createBitmap(img.getWidth(), img.getHeight(), Bitmap.Config.RGB_565);
        Canvas canvas = new Canvas(bmp);
        canvas.drawBitmap(img, 0, 0, null);
        float x1 = face.getPosition().x;
        float y1 = face.getPosition().y;
        float x2 = x1 + face.getWidth();
        float y2 = y1 + face.getHeight();
        canvas.drawOval(new RectF(x1, y1, x2, y2), paint);

        imageView.setImageDrawable(new BitmapDrawable(getResources(),bmp));
    }

Al click sul FloatingActionButton, estrarremo la Bitmap dall’ImageView e la useremo per creare il Frame su cui il FaceDetector agirà. Le azioni che svolgeremo sul volto riconosciuto saranno due:

  • disegneremo l’ovale con le operazioni descritte nel metodo drawOval. Utilizzeremo un Canvas per costruire una versione della Bitmap arrichita della forma geometrica da collocare nuovamente nella ImageView;
  • utilizzeremo i metodi getIsSmilingProbability, getIsLeftEyeOpenProbability e getIsRightEyeOpenProbability della classe Face per calcolare, rispettivamente, la probabilità che il volto raffigurato stia sorridendo, che l’occhio sinistro sia aperto e che lo sia quello destro. Riporteremo i valori ottenuti nella tabella sottostante l’ImageView. Qualora questi metodi restituissero il valore -1 (corrispondente alla costante float UNCOMPUTED_PROBABILITY), si verifichi di aver invocato il metodo setClassificationTypes nell’inizializzazione del FaceDetector.

Figura 2. Orientamento del viso (click per ingrandire)

Orientamento del viso

Conclusioni

Quelle viste sono solo alcune delle funzionalità messe a disposizione da Vision relativamente all’individuazione dei volti.

Tramite gli oggetti Face, ad esempio, è possibile ottenere i Landmarks che rappresentano i punti principali del viso come occhi e base del naso, ed inoltre vengono individuati una serie di angoli che forniscono informazioni sull’orientamento del viso. Per utilizzare queste funzionalità sarà sufficiente attivarle nell’inizializzazione del FaceDetector ed invocare gli opportuni metodi sull’oggetto Face: qualcosa di analogo a quanto visto in questa lezione.

Tutte le lezioni

1 ... 53 54 55 ... 82

Se vuoi aggiornamenti su Face Detection inserisci la tua e-mail nel box qui sotto:
Tags:
 
X
Se vuoi aggiornamenti su Face Detection

inserisci la tua e-mail nel box qui sotto:

Ho letto e acconsento l'informativa sulla privacy

Acconsento al trattamento di cui al punto 3 dell'informativa sulla privacy