Essayez la classification d'image à l'aide de TensorFlow Lite sur Android (JAVA)

en premier

Cette fois, je vais utiliser TensorFlowLite sur Android (Java) pour classer les images! Si vous faites une erreur dans le code, etc. et que vous avez des améliorations, veuillez nous en informer!

Qu'est-ce que TensorFlow Lite?

Selon le Guide TensorFlow Lite,

TensorFlow Lite est un ensemble d'outils permettant d'utiliser les modèles TensorFlow sur les smartphones et les appareils Iot.

** Interpréteur TensorFlow Lite Exécute un modèle spécifiquement optimisé pour de nombreux types de matériel différents, y compris les téléphones mobiles, les périphériques Linux embarqués et les microcontrôleurs. ** **

Vous pouvez transformer votre modèle TensorFlow en un format efficace à utiliser par l'interpréteur de convertisseur de lumière TensorFlow et introduire des optimisations pour améliorer la taille et les performances binaires.

** ⇒ En d'autres termes, c'est une version légère de TensorFlow qui peut être facilement exécutée non seulement sur les PC mais aussi sur les smartphones et les appareils Iot! ** ** À l'avenir, vous pourrez même apprendre avec un simple smartphone! Hou la la!

Procédure de développement à l'aide de TensorFlow Lite

1. Préparez un modèle TensorFlow

Préparez un modèle qui a été formé avec TensorFlow. Cette fois, je vais utiliser le modèle hébergé, donc je vais l'omettre!

2. Convertissez le modèle TensorFlow

TensorFlow Lite ne peut pas utiliser le modèle TensorFlow tel quel, alors convertissez-le dans un format dédié (tflite). ~~ Veuillez vous référer à l'article ici pour les méthodes de conversion. ~~ Puisque l'article a été supprimé, je publierai l'article que j'ai écrit et l'article officiel. Méthode de conversion de modèle Article officiel

3. Incorporer!

Cette fois, je vais vous expliquer comment intégrer Android (Java)!

Intégrer!

Créer un nouveau projet

Veuillez utiliser n'importe quel nom pour le nom du projet, etc.! image.png Cette fois, nous utiliserons AndroidX. Si vous cochez "Utiliser les artefacts android x. *", C'est OK. Vous n'êtes pas obligé d'utiliser Android X car il est facultatif.

Ajouter une dépendance

Dans build.gradle sous le répertoire de l'application

build.gradle(app)


dependencies {
    implementation 'org.tensorflow:tensorflow-lite:0.0.0-nightly'
    implementation 'org.tensorflow:tensorflow-lite-gpu:0.0.0-nightly'
}

Ajouter. À ce rythme, il contient ABI pour tous les processeurs et jeux d'instructions, mais "armeab-v7a" et "arm64-v8a" S'il est inclus, il peut couvrir la plupart des appareils Android, alors configurez-le pour ne pas inclure d'autres ABI. Peu importe s'il est inclus, mais c'est recommandé car cela réduit la taille de l'application.

build.gradle(app)


android {
    defaultConfig {
        ndk {
            abiFilters 'armeabi-v7a', 'arm64-v8a'
        }
    }
}

Pour ABI, veuillez consulter l'article ici pour une compréhension facile.

Android compresse ce qui se trouve dans le dossier d'actifs, donc si vous placez le modèle dans le dossier d'actifs, il sera compressé et ne pourra pas être lu. Par conséquent, je spécifierai de ne pas compresser le fichier tflite.

build.gradle(app)


android {
    defaultConfig {
        aaptOptions {
            noCompress "tflite"
        }
    }
}

Installation du modèle

Placez le modèle et le label_text dans le dossier des ressources. Veuillez télécharger le modèle depuis ici. image.png

Commencez par créer un dossier d'actifs. image.png Copiez le fichier du dossier décompressé. image.png Après la copie, renommez-le en "model.tflite" et "labels.txt". image.png

Ceci termine l'installation du modèle.

Copier et personnaliser la classe

Échantillon Android de TensorFlow Lite 3 classes et [ici](https://github.com/tensorflow/examples/blob/master/lite/examples/image_classification/android/app/src/main/java/org/tensorflow/lite/examples/ Copiez Logger.java depuis classification / env / Logger.java). image.png Si vous le copiez simplement, vous obtiendrez une erreur. Réécrivez la destination d'importation de la classe Logger avec Classifier.java.

Classfier.java


import org.tensorflow.lite.Interpreter;
//Supprimer ici importer l'organisation.tensorflow.lite.examples.classification.env.Logger;
import org.tensorflow.lite.gpu.GpuDelegate;

/** A classifier specialized to label images using TensorFlow Lite. */
public abstract class Classifier {
    private static final Logger LOGGER = new Logger();

image.png Si vous le supprimez, Android Studio vous demandera quelque chose comme ça, donc si vous appuyez sur "Alt + Entrée", il sera importé automatiquement. image.png Lors de l'importation image.png

Je pense qu'il y aura deux types, alors sélectionnez celui qui ne dit pas <Android API ~ Platform> (android.jar).

Je pense que toutes les erreurs ont maintenant disparu.

Modèle de charge

ClassifierFloatMobileNet.java ClassifierQuantizedMobileNet.java Modification de la partie de chargement du modèle qui est commune aux deux

*** Original ***

java:ClassifierFloatMobileNet.java,ClassifierQuantizedMobileNet.java



  @Override
  protected String getModelPath() {
    // you can download this file from
    // see build.gradle for where to obtain this file. It should be auto
    // downloaded into assets.
    return "mobilenet_v1_1.0_224.tflite";
  }

*** Après le changement ***

ClassifierFloatMobileNet.java,ClassifierQuantizedMobileNet



  @Override
  protected String getModelPath() {
    // you can download this file from
    // see build.gradle for where to obtain this file. It should be auto
    // downloaded into assets.
    return "model.tflite";
  }


Afficher le placement

Organisez TextView, Button, ImageView comme ceci. Réglez surCliquez sur Bouton et appuyez dessus ↑ Est-il préférable pour les auditeurs de définir onClick? S'il vous plaît dites-moi une personne détaillée image.png

activity_main.xml


<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">

            <TextView
                android:id="@+id/textView"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="TextView" />
        </LinearLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">

            <Button
                android:id="@+id/button"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:onClick="select"
                android:text="Sélectionnez une image" />
        </LinearLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">

            <ImageView
                android:id="@+id/imageView"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                tools:srcCompat="@tools:sample/avatars" />
        </LinearLayout>
    </LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

Ecrire le code

Commençons par déclarer les variables à utiliser!

MainActivity.java


    ImageView imageView;
    TextView textView;
    Classifier classifier;
    private static final int RESULT_IMAGEFILE = 1001;  //Code de demande utilisé lors de l'acquisition d'images

Associez textview et ImageView dans onCreate.

MainActivity.java


        imageView = findViewById(R.id.imageView);
        textView = findViewById(R.id.textView);

Appelez ensuite Classfier.

MainActivity.java


        try {
            classifier = Classifier.create(this,QUANTIZED,CPU,2);
        } catch (IOException e) {
            e.printStackTrace();
        }

Les arguments spécifient l'Acritivy, le type de modèle, le périphérique utilisé pour le calcul et le nombre de threads à utiliser. En gros, ce paramètre fonctionnera, mais modifions-le de manière flexible.

Comportement du bouton d'écriture

Après avoir appuyé sur le bouton, ouvrez la galerie et ignorez l'intention afin de pouvoir sélectionner l'image.

MainAcritivy.java


public void image(View V){
        Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
        intent.addCategory(Intent.CATEGORY_OPENABLE);
        intent.setType("image/*");
        startActivityForResult(intent, RESULT_IMAGEFILE);
}

Pour plus d'informations à ce sujet, cliquez ici (https://qiita.com/yukiyamadajp/items/137d15a4e65ed2308787)

Traitement après le retour de la galerie

Lorsque vous revenez de la galerie, récupérez l'image et traitez-la.

MainAcritivty.java


    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent resultData) {
        super.onActivityResult(requestCode, resultCode, resultData);
        if (requestCode == RESULT_IMAGEFILE && resultCode == Activity.RESULT_OK) {
            if (resultData.getData() != null) {
                ParcelFileDescriptor pfDescriptor = null;
                try {
                    Uri uri = resultData.getData();
                    pfDescriptor = getContentResolver().openFileDescriptor(uri, "r");
                    if (pfDescriptor != null) {
                        FileDescriptor fileDescriptor = pfDescriptor.getFileDescriptor();
                        Bitmap bmp = BitmapFactory.decodeFileDescriptor(fileDescriptor);
                        pfDescriptor.close();
                        int height = bmp.getHeight();
                        int width = bmp.getWidth();
                        while (true) {
                            int i = 2;
                            if (width < 500 && height < 500) {
                                break;
                            } else {
                                if (width > 500 || height > 500) {
                                    width = width / i;
                                    height = height / i;
                                } else {
                                    break;
                                }
                                i++;
                            }
                        }

                        Bitmap croppedBitmap = Bitmap.createScaledBitmap(bmp, width, height, false);
                        imageView.setImageBitmap(croppedBitmap);
                        List<Classifier.Recognition> results = classifier.recognizeImage(croppedBitmap,classfier);
                        String text;
                        for (Classifier.Recognition result : results) {
                            RectF location = result.getLocation();
                            Float conf = result.getConfidence();
                            String title = result.getTitle();
                            text += title + "\n";
                        }
                         textView.setText(text);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    try {
                        if (pfDescriptor != null) {
                            pfDescriptor.close();
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }

            }
        }
    }

Puisqu'il est long, je vais l'expliquer séparément.

Ce code est appelé lorsque vous revenez à l'activité pour déterminer si elle est revenue de la galerie.

MainAcrivity.java


   @Override
    public void onActivityResult(int requestCode, int resultCode, Intent resultData) {
        super.onActivityResult(requestCode, resultCode, resultData);
        if (requestCode == RESULT_IMAGEFILE && resultCode == Activity.RESULT_OK) {
        }
    }

Ce code obtient l'URI de la valeur de retour et prend les données du fichier avec ParceFileDescriptor. Puisque vous pouvez obtenir un tel URI "content: //com.android.providers.media.documents/document/image%3A325268", j'obtiens l'image d'ici.

MainAcrivity.java


            if (resultData.getData() != null) {
                ParcelFileDescriptor pfDescriptor = null;
                try {
                    Uri uri = resultData.getData();
                    pfDescriptor = getContentResolver().openFileDescriptor(uri, "r");
                    if (pfDescriptor != null) {
                        FileDescriptor fileDescriptor = pfDescriptor.getFileDescriptor();

Ce code convertit l'image obtenue précédemment en bitmap afin que la taille de l'image soit inférieure à 300. Si l'image est plus grande que 300, elle ne peut pas être jugée normalement et elle sera supprimée en raison d'une erreur. Caused by: java.lang.ArrayIndexOutOfBoundsException Par conséquent, tout en conservant le rapport hauteur / largeur, le rapport hauteur / largeur est maintenu à 300.

MainAcrivity.java


                        Bitmap bmp = BitmapFactory.decodeFileDescriptor(fileDescriptor);
                        pfDescriptor.close();

                        if (!bmp.isMutable()) {
                            bmp = bmp.copy(Bitmap.Config.ARGB_8888, true);
                        }
                        int height = bmp.getHeight();
                        int width = bmp.getWidth();
                        while (true) {
                            int i = 2;
                            if (width < 300 && height < 300) {
                                break;
                            } else {
                                if (width > 300 || height > 300) {
                                    width = width / i;
                                    height = height / i;
                                } else {
                                    break;
                                }
                                i++;
                            }
                        }
                        Bitmap croppedBitmap = Bitmap.createScaledBitmap(bmp, width, height, false);

C'est finalement un jugement. Ce code discrimine l'image traitée et la reçoit dans sa propre liste. Ensuite, la liste est tournée avec pour pour obtenir le résultat et l'afficher dans le textView. Cette fois, seul le nom de l'élément déterminé est affiché, mais vous pouvez également avoir la possibilité qu'il s'agisse d'un élément.

MainAcrivity.java


                        List<Classifier.Recognition> results = classifier.recognizeImage(croppedBitmap);
                        String text="";
                        for (Classifier.Recognition result : results) {
                            /*
                            RectF location = result.getLocation();
                            Float conf = result.getConfidence();
                            */
                            String title = result.getTitle();
                            text += title + "\n";
                        } 
                        textView.setText(text);

C'est tout! !!

Je vais vraiment le déplacer

Ensuite, j'aimerais vraiment le déplacer! Tout d'abord, l'image du chien image.png Banc de parc ... clou,,, Caméléon américain ... Hmm La précision est subtile Vient ensuite une image d'un beau paysage. Le paysage urbain de Delft

image.png

Écran de fenêtre ... Paillasson ... aveugle,,, Hmm Non!

Résumé

La précision était subtile, mais bon? J'ai pu classer les images! La prochaine fois, j'aimerais classer en temps réel! À bientôt!

Recommended Posts

Essayez la classification d'image à l'aide de TensorFlow Lite sur Android (JAVA)
Essayez la communication en utilisant gRPC sur un serveur Android + Java
Filtre Sobel utilisant OpenCV sur Android (Java)
Essayez la recherche similaire de Recherche d'images à l'aide du SDK Java [Inscription]
Essayez d'utiliser RocksDB avec Java
Essayez de gratter en utilisant Java [Note]
Essayez Hello World en utilisant Java brut sur le conteneur Docker
OSX 10.15 (Catalina) Utilisation de Java avec β
Essayez d'implémenter Android Hilt en Java
Essayez d'utiliser Redis avec Java (jar)
Enregistrer ArrayList à l'aide de GSON sur Android
[Java] Essayez de mettre en œuvre à l'aide de génériques
Essayez d'utiliser le traçage de méthode IBM Java
Remarques sur le traitement des threads Android (java)
Essayez d'utiliser le SDK Java d'Hyperledger Iroha
[Java] Où avez-vous essayé d'utiliser java
Essayez d'utiliser le framework Java Nablarch [Application Web]
Essayez d'utiliser l'API Stream en Java
Utilisation de JupyterLab + Java avec WSL sous Windows 10
Appeler java depuis C ++ sur Android NDK
Étude de Java Essayez d'utiliser un scanner ou une carte
Essayez d'utiliser l'API au format JSON en Java
[Ruby on Rails] Diaporama d'images utilisant Skippr
Essayez d'utiliser l'API REST de JobScheduler - implémentation Java RestClient--
Essayez d'utiliser l'API Emotion d'Android
Essayez d'utiliser la télécommande Wii en Java
Essayez d'ajouter du texte à une image avec Scala en utilisant la bibliothèque standard de Java
[Android] [Java] Télécharger des images sur GCS (Google Cloud Storage) avec Stream à l'aide de Glide
Essayez d'utiliser la classe de test RestClient de JobScheduler REST-API-Java-
Essayez de créer un environnement Java 8 sur Amazon Linux2
Installez java et android-sdk sur Mac en utilisant homebrew
Les débutants essaient d'utiliser Android Studio Partie 2 (traitement des événements)
Essayez d'utiliser Sourcetrail (version win) avec du code Java
Essayez d'utiliser l'API Cloud Vision de GCP en Java
Essayez d'utiliser Sourcetrail (version macOS) avec du code Java
Les débutants essaient d'utiliser Android Studio Partie 1 (Hello World)
Essayez d'accéder à l'ensemble de données depuis Java en utilisant JZOS
Traduire à l'aide de l'API Microsoft Translator Text sur Android ~ Implémentation ~
Essayez d'utiliser l'analyse syntaxique de l'API COTOHA en Java
Histoire de l'automatisation des tests avec Appium [Android / java]