[JAVA] Application de reconnaissance faciale avec OpenCV + Android Studio

Chose que tu veux faire

Créer une application de reconnaissance faciale avec OpenCV ·Cible ・ Pour le moment, découvrez comment installer et utiliser Android Studio (débutant) ・ Exécutez OpenCV sur Android ・ Les images prises avec l'appareil photo et les images enregistrées dans la galerie peuvent être utilisées.

référence

J'ai essayé de créer une simple application Android de reconnaissance faciale en utilisant OpenCV https://qiita.com/Kuroakira/items/094ecb236da89949d702 Supplément sur la façon d'appeler la caméra avec intention (principalement pour le problème Xperia 2.1) https://gabu.hatenablog.com/entry/20101125/1290681748

Ce que j'ai utilisé

Android Studio 3.5.3 OpenCV 4.2.0

Écoulement brutal

Quant à la mise en œuvre, je vais l'écrire brièvement car je me réfère aux prédécesseurs ci-dessus.

Appuyez sur le bouton de l'appareil photo et de la galerie ↓ Obtenir des images de la caméra, de la galerie ↓ Convertir l'image acquise du format bitmap au format Mat ↓ Passer l'image au format Mat à OpenCV ↓ Acquiert les informations de reconnaissance faciale et les affiche à l'écran

résultat

Des informations de coordination comme celle-là sont sorties.

result1.png

Choses qui peuvent être utilisées à l'avenir

·caméra Si vous souhaitez acquérir l'image prise par la caméra en haute résolution, écrivez-la une fois dans l'URL et acquérez l'image à partir de l'URL. getImg = (Bitmap) data.getExtras (). get ("data"); ne peut obtenir que des images basse résolution pour les vignettes. (L'image pour la reconnaissance d'image est obtenue par getImg = (Bitmap) data.getExtras (). Get ("data");, mais cela semble gênant si le nombre de personnes augmente ou s'il s'agit d'une image de dessin)

MainActivity.java


   getImg = (Bitmap) data.getExtras().get("data");

MainActivity.java


    /**Abréviation**/
    imageView.setImageURI(mImageUri);
    /**Abréviation**/

    /**
     *Pour la photographie
     *Exportez une fois la photo prise vers l'URL et stockez l'URL de destination dans mImageUri
     */
    protected void takePhoto(){
        String filename = System.currentTimeMillis() + ".jpg ";

        ContentValues values = new ContentValues();
        values.put(MediaStore.Images.Media.TITLE,filename);
        values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
        mImageUri = getContentResolver().insert(
                MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values
        );

        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        intent.putExtra(MediaStore.EXTRA_OUTPUT, mImageUri);
        startActivityForResult(intent, RESULT_CAMERA);
    }

Ce que je veux réaliser à l'avenir

・ Division de classe uniquement pour la reconnaissance faciale Au départ, j'ai essayé de l'implémenter en le classant, mais j'ai abandonné car je ne savais pas comment classer les parties suivantes. (Vous ne pouvez pas accéder à res / raw avec la même description que MainActivity.java depuis une autre classe?)

MainActivity.java


        File cascadeDir = getDir("cscade", Context.MODE_PRIVATE);
        File cascadeFile = new File(cascadeDir, "lbpcascade_frontalface.xml");

・ Acquisition d'images depuis ImageView En acquérant des images d'ImageVIew, dans le cas des caméras et des galeries, la mise en œuvre dans chaque cas devient inutile, il peut donc être possible de réduire le code.

・ Implémentation à Kotlin Je l'ai implémenté dans un Java bien écrit parce que c'était pour m'y habituer pour le moment, mais j'aimerais utiliser Kotlin lors du développement pour Android à l'avenir

Code source

MainActivity.java


package com.example.myapplication;

import androidx.appcompat.app.AppCompatActivity;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import  java.io.InputStream;

import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.Paint;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import org.opencv.android.Utils;
import org.opencv.core.Mat;
import org.opencv.core.MatOfRect;
import org.opencv.core.Rect;
import org.opencv.objdetect.CascadeClassifier;

public class MainActivity extends AppCompatActivity {
    private final static int RESULT_CAMERA = 1001; //Pour les caméras
    private final static int REQUEST_GALLERY = 1000; //Pour la galerie
    private Uri mImageUri; //Variable d'instance pour stocker l'URL de l'image
    private Bitmap getImg = null; //Images prises depuis l'appareil photo ou la galerie
    private ImageView imageView;//Déclaration de vue d'image

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        imageView = findViewById(R.id.image_view);//Associez d'abord ImageView à l'ID de la vue de mise en page

        Button cameraButton = findViewById(R.id.camera_button);
        cameraButton.setOnClickListener(new View.OnClickListener() {//Implémentation utilisant une classe interne normale
            @Override
            public void onClick(View v) {
                takePhoto();
            }
        });

        Button galleyButton = findViewById(R.id.gallery_button);
        galleyButton.setOnClickListener(new View.OnClickListener() {//Implémentation utilisant une classe interne normale
            @Override
            public void onClick(View v) {
                Intent intent = new Intent();
                intent.setType("image/*");
                intent.setAction(Intent.ACTION_GET_CONTENT);
                startActivityForResult(intent, REQUEST_GALLERY);
            }
        });
    }

    //Je vais désormais coller la photo prise dans la vue Image.
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if(requestCode == RESULT_CAMERA || requestCode == REQUEST_GALLERY) {
            TextView textView = findViewById(R.id.text1); //Affichage(Afficher pour stocker le texte à afficher)
            String outputText = ""; //Texte à afficher
            MatOfRect faceRects; //Stocker les données de reconnaissance faciale

            //Lors de la sélection d'une image de l'appareil photo
            if (requestCode == RESULT_CAMERA) {
                //Y compris les cas annulés
                if (data.getExtras() == null) {
                    Log.d("debug", "cancel ?");
                    return;
                } else {
                    imageView.setImageURI(mImageUri);
                    getImg = (Bitmap) data.getExtras().get("data");
                }
            }
            //Lors de la sélection d'une image dans la galerie
            if (requestCode == REQUEST_GALLERY && resultCode == RESULT_OK) {
                try {
                    InputStream in = getContentResolver().openInputStream(data.getData());
                    getImg = BitmapFactory.decodeStream(in);
                    in.close();
                    //Afficher l'image sélectionnée
                    imageView.setImageBitmap(getImg);
                } catch (Exception e) {
                    //Quand il n'y a pas de fichier
                    textView.setText("Fichier non trouvé");
                }
            }
            //Image collée sur imageView(Obtenu de la caméra, de la galerie)Reconnaissance faciale de
            try {
                faceRects = checkFaceExistence(getImg);
                outputText = makeOutputText(faceRects);\
                //Afficher l'image sélectionnée
                imageView.setImageBitmap(getImg);
            } catch (IOException e) {
                outputText = "Erreur de reconnaissance faciale";
                e.printStackTrace();
            }

            Toast.makeText(this,outputText,Toast.LENGTH_LONG).show();
            textView.setText(outputText);
        }
    }

    /**
     *Pour la photographie
     *Exportez une fois la photo prise vers l'URL et stockez l'URL de destination dans mImageUri
     */
    protected void takePhoto(){
        String filename = System.currentTimeMillis() + ".jpg ";

        ContentValues values = new ContentValues();
        values.put(MediaStore.Images.Media.TITLE,filename);
        values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
        mImageUri = getContentResolver().insert(
                MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values
        );

        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        intent.putExtra(MediaStore.EXTRA_OUTPUT, mImageUri);
        startActivityForResult(intent, RESULT_CAMERA);
    }

    /**
     *Effectuer la reconnaissance faciale en fonction de l'image transmise
     * @image bitmap param pour la reconnaissance faciale
     * @texte de retour informations de reconnaissance faciale
     * @throws IOException
     */
    protected MatOfRect checkFaceExistence(Bitmap bitmap) throws IOException{
        System.loadLibrary("opencv_java4");

        //Données d'image envoyées(bitmap)Au format de tapis
        Mat matImg = new Mat();
        Utils.bitmapToMat(bitmap, matImg);
        String text =  "";   //Texte pour stocker les informations de reconnaissance faciale

        //Génération d'une instance de classificateur en cascade pour la reconnaissance faciale(Exportez le fichier une fois et obtenez le chemin du fichier)
        //Obtenez le fichier xml une fois stocké sous raw
        InputStream inStream = getResources().openRawResource(R.raw.haarcascade_frontalface_alt);
        MatOfRect faceRects = new MatOfRect(); //Stocker les données de reconnaissance faciale

        try {
            //Définissez le chemin du fichier xml de sortie sur l'argument de Cascade Classfle
            CascadeClassifier faceDetetcor = outputCascadeFile(inStream);
            //Reconnaissance faciale en donnant des données d'image au classificateur en cascade
            faceDetetcor.detectMultiScale(matImg, faceRects);
        }
        catch (IOException e){
            Toast.makeText(this,"Échec de l'ouverture du fichier d'informations d'analyse.",Toast.LENGTH_SHORT).show();
        }

        return faceRects;
    }

    /**
     *Importez une fois le classificateur openCV pré-préparé et rendez-le disponible pour l'exportation.
     * @param inStream Données d'origine du classificateur
     * @retour des données du classificateur faceDetector
     * @throws IOException
     */
    protected CascadeClassifier outputCascadeFile(InputStream inStream) throws IOException {
        File cascadeDir = getDir("cscade", Context.MODE_PRIVATE);
        File cascadeFile = new File(cascadeDir, "lbpcascade_frontalface.xml");

        //Sortir le fichier xml acquis dans un répertoire spécifique
        FileOutputStream outputStream = new FileOutputStream(cascadeFile);

        byte[] buf = new byte[2048];
        int rdBytes;

        while ((rdBytes = inStream.read(buf)) != -1) {
            try {
                outputStream.write(buf, 0, rdBytes);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        //Définissez le chemin du fichier xml de sortie sur l'argument de Cascade Classfle
        CascadeClassifier faceDetetcor = new CascadeClassifier((cascadeFile.getAbsolutePath()));

        outputStream.close();

        return faceDetetcor;
    }

    /**
     *Création de texte pour la sortie
     *Définissez les informations de coordonnées sur du texte en fonction des informations de reconnaissance faciale
     * @param faceRects
     * @return
     */
    protected String makeOutputText(MatOfRect faceRects){
        String text = "";

        //Renvoie le résultat de la reconnaissance faciale sous forme de chaîne
        if(faceRects.toArray().length > 0){
            for(Rect face: faceRects.toArray()) {
                text = "Largeur verticale du visage:" + face.height + "\n" +
                        "Largeur du visage" + face.width + "\n" +
                        "Position du visage(Coordonnée Y)" + face.y + "\n" +
                        "Position du visage(Coordonnée X)" + face.x;
            }
        }
        else{
            text = "Aucun visage n'a été détecté.";
        }

        return text;
    }

Recommended Posts

Application de reconnaissance faciale avec OpenCV + Android Studio
Application de reconnaissance faciale conçue avec Amazon Rekognition et Java
Comment créer une application à l'aide de Tensorflow avec Android Studio
Importer des images d'appareils avec l'application Android
Une série de problèmes dans le développement de studios Android
J'ai créé une application Janken avec Android
Développement (paramètres) Riot (application de chat) dans Android Studio
Application météo Android
[Android] Histoire désespérée avec UserId et SharedUserId de l'application
Faire vibrer le bracelet avec Bluetooth à partir de l'application Android
Compatible avec Android 10 (API 29)
Analyseur de spectre d'application Android
Remarques sur le studio Android
Vaincre Android Studio Partie 3-6
Vaincre Android Studio Partie 1 et Partie 2
À propos des composants de l'application Android
Comment faire une capture d'écran avec l'émulateur Android Studio
Utilisez Java inclus avec Android Studio pour créer React Native