Versuchen Sie die Bildklassifizierung mit TensorFlow Lite unter Android (JAVA).

zunaechst

Dieses Mal werde ich TensorFlowLite unter Android (Java) verwenden, um Bilder zu klassifizieren! Wenn Sie einen Fehler im Code usw. machen und Verbesserungen haben, lassen Sie es uns bitte wissen!

Was ist TensorFlow Lite?

Laut dem TensorFlow Lite Guide

TensorFlow Lite ist ein Toolset zur Verwendung von TensorFlow-Modellen auf Smartphones und Iot-Geräten.

** TensorFlow Lite Interpreter Führt ein Modell aus, das speziell für viele verschiedene Hardwaretypen optimiert wurde, einschließlich Mobiltelefonen, eingebetteten Linux-Geräten und Mikrocontrollern. ** ** **

Sie können Ihr TensorFlow-Modell in ein effizientes Format für den TensorFlow Light Converter Interpreter umwandeln und Optimierungen zur Verbesserung der Binärgröße und -leistung einführen.

** ⇒ Mit anderen Worten, es ist eine leichte Version von TensorFlow, die nicht nur auf PCs, sondern auch auf Smartphones und Iot-Geräten problemlos ausgeführt werden kann! ** ** ** In Zukunft können Sie sogar mit nur einem Smartphone lernen! Beeindruckend!

Entwicklungsverfahren mit TensorFlow Lite

1. Bereiten Sie ein TensorFlow-Modell vor

Bereiten Sie ein Modell vor, das mit TensorFlow trainiert wurde. Dieses Mal werde ich das gehostete Modell verwenden, also werde ich es weglassen!

2. Konvertieren Sie das TensorFlow-Modell

TensorFlow Lite kann das TensorFlow-Modell nicht so verwenden, wie es ist. Konvertieren Sie es daher in ein dediziertes Format (tflite). ~~ Informationen zu Konvertierungsmethoden finden Sie im Artikel hier. ~~ Da der Artikel gelöscht wurde, werde ich den Artikel, den ich geschrieben habe, und den offiziellen Artikel veröffentlichen. Modellkonvertierungsmethode Offizieller Artikel

3. Einbinden!

Dieses Mal werde ich erklären, wie man Android (Java) einbettet!

Übernehmen!

Erstellen Sie ein neues Projekt

Bitte verwenden Sie einen beliebigen Namen für den Projektnamen usw.! image.png Dieses Mal verwenden wir AndroidX. Wenn Sie "Android x. * Artefakte verwenden" aktivieren, ist dies in Ordnung. Sie müssen Android X nicht verwenden, da es optional ist.

Abhängigkeit hinzufügen

In build.gradle unter dem App-Verzeichnis

build.gradle(app)


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

Hinzufügen. Bei dieser Rate enthält es ABI für alle CPUs und Befehlssätze, jedoch "armeab-v7a" und "arm64-v8a". Wenn es enthalten ist, kann es die meisten Android-Geräte abdecken. Stellen Sie daher ein, dass keine anderen ABIs enthalten sind. Es spielt keine Rolle, ob es enthalten ist, aber es wird empfohlen, da es die Größe der App reduziert.

build.gradle(app)


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

Informationen zu ABI finden Sie im Artikel hier.

Unter Android wird das, was im Asset-Ordner abgelegt wird, komprimiert. Wenn Sie das Modell also im Asset-Ordner ablegen, wird es komprimiert und kann nicht gelesen werden. Daher werde ich angeben, die tflite-Datei nicht zu komprimieren.

build.gradle(app)


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

Modellinstallation

Platzieren Sie das Modell und label_text im Asset-Ordner. Bitte laden Sie das Modell von [hier] herunter (https://www.tensorflow.org/lite/models/image_classification/overview). image.png

Erstellen Sie zunächst einen Asset-Ordner. image.png Kopieren Sie die Datei aus dem entpackten Ordner. image.png Benennen Sie es nach dem Kopieren in "model.tflite" und "labels.txt" um. image.png

Damit ist die Modellinstallation abgeschlossen.

Klasse kopieren und anpassen

Android-Beispiel für TensorFlow Lite 3 Klassen und [hier](https://github.com/tensorflow/examples/blob/master/lite/examples/image_classification/android/app/src/main/java/org/tensorflow/lite/examples/ Kopieren Sie Logger.java aus Klassifizierung (env / Logger.java). image.png Wenn Sie es nur kopieren, erhalten Sie eine Fehlermeldung. Schreiben Sie das Importziel der Logger-Klasse mit Classifier.java neu.

Classfier.java


import org.tensorflow.lite.Interpreter;
//Hier löschen import org.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 Wenn Sie es löschen, werden Sie von Android Studio dazu aufgefordert. Wenn Sie also "Alt + Eingabetaste" drücken, wird es automatisch importiert. image.png Beim Importieren image.png

Ich denke, es wird zwei Typen geben, also wählen Sie den aus, der nicht <Android API ~ Platform> (android.jar) sagt.

Ich denke, alle Fehler sind jetzt weg.

Modell laden

ClassifierFloatMobileNet.java ClassifierQuantizedMobileNet.java Der für beide gemeinsame Ladeteil des Modells wurde geändert

*** 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";
  }

*** Nach der veränderung ***

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";
  }


Platzierung anzeigen

Ordnen Sie TextView, Button, ImageView so an. Stellen Sie onClick for Button ein und drücken Sie es. ↑ Ist es für Hörer besser, onClick einzustellen? Bitte sagen Sie mir eine detaillierte Person 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="Wählen Sie ein Bild aus" />
        </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>

Code schreiben

Lassen Sie uns zunächst die zu verwendenden Variablen deklarieren!

MainActivity.java


    ImageView imageView;
    TextView textView;
    Classifier classifier;
    private static final int RESULT_IMAGEFILE = 1001;  //Anforderungscode, der beim Erfassen von Bildern verwendet wird

Verknüpfen Sie Textansicht und ImageView in onCreate.

MainActivity.java


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

Dann rufen Sie Classfier an.

MainActivity.java


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

Die Argumente geben die Aktivität, den Modelltyp, das für die Berechnung verwendete Gerät und die Anzahl der zu verwendenden Threads an. Grundsätzlich funktioniert diese Einstellung, aber wir können sie flexibel ändern.

Schreibschaltflächenverhalten

Öffnen Sie nach dem Drücken der Taste die Galerie und überspringen Sie die Absicht, damit Sie das Bild auswählen können.

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);
}

Weitere Informationen hierzu finden Sie hier (https://qiita.com/yukiyamadajp/items/137d15a4e65ed2308787).

Bearbeitung nach Rückkehr aus der Galerie

Wenn Sie von der Galerie zurückkommen, holen Sie sich das Bild und verarbeiten Sie es.

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();
                    }
                }

            }
        }
    }

Da es lang ist, werde ich es separat erklären.

Dieser Code wird aufgerufen, wenn Sie zur Aktivität zurückkehren, um festzustellen, ob er aus der Galerie zurückgekehrt ist.

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) {
        }
    }

Dieser Code ruft den URI vom Rückgabewert ab und nimmt die Dateidaten mit ParceFileDescriptor auf. Da Sie eine solche URI "content: //com.android.providers.media.documents/document/image%3A325268" erhalten können, erhalte ich das Bild von hier.

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();

Dieser Code konvertiert das zuvor erhaltene Bild in eine Bitmap, sodass die Größe des Bildes kleiner als 300 ist. Wenn das Bild größer als 300 ist, kann es nicht normal beurteilt werden und wird aufgrund eines Fehlers gelöscht. Caused by: java.lang.ArrayIndexOutOfBoundsException Daher wird unter Beibehaltung des Seitenverhältnisses das Seitenverhältnis innerhalb von 300 gehalten.

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);

Es ist endlich ein Urteil. Dieser Code unterscheidet das verarbeitete Bild und empfängt es in einer eigenen Liste. Anschließend wird die Liste mit for gedreht, um das Ergebnis abzurufen und in der Textansicht anzuzeigen. Dieses Mal wird nur der ermittelte Artikelname ausgegeben, Sie können jedoch auch die Möglichkeit erhalten, dass es sich um einen Artikel handelt.

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);

Das ist es! !!

Ich werde es tatsächlich bewegen

Dann möchte ich es tatsächlich verschieben! Zuallererst das Bild des Hundes image.png Parkbank ... Nagel,,, Amerikanisches Chamäleon ... Hmm Die Genauigkeit ist subtil Als nächstes ist ein Bild einer schönen Landschaft. Das Stadtbild von Delft

image.png

Fensterscheibe ... Fußmatte ... blind,,, Hmm Nein!

Zusammenfassung

Die Genauigkeit war subtil, aber gut? Ich konnte die Bilder klassifizieren! Nächstes Mal möchte ich in Echtzeit klassifizieren! Bis bald!

Recommended Posts

Versuchen Sie die Bildklassifizierung mit TensorFlow Lite unter Android (JAVA).
Versuchen Sie die Kommunikation mit gRPC auf einem Android + Java-Server
Sobel-Filter mit OpenCV unter Android (Java)
Probieren Sie die ähnliche Suche von Image Search mit Java SDK [Registrierung] aus.
Versuchen Sie es mit RocksDB mit Java
Versuchen Sie, mit Java zu kratzen [Hinweis]
Versuchen Sie Hello World mit einfachem Java im Docker-Container
OSX 10.15 (Catalina) Verwenden von Java mit β
Versuchen Sie, Android Hilt in Java zu implementieren
Versuchen Sie es mit Redis mit Java (jar)
Speichern Sie ArrayList mit GSON unter Android
[Java] Versuchen Sie, mithilfe von Generika zu implementieren
Versuchen Sie es mit der IBM Java-Methodenverfolgung
Versuchen Sie es mit dem Java SDK von Hyperledger Iroha
[Java] Wo haben Sie versucht, Java zu verwenden?
Versuchen Sie es mit dem Java Framework Nablarch [Web Application]
Versuchen Sie es mit der Stream-API in Java
Verwenden von JupyterLab + Java mit WSL unter Windows 10
Rufen Sie Java von C ++ auf Android NDK auf
Java lernen Versuchen Sie es mit einem Scanner oder einer Karte
Versuchen Sie es mit der JSON-Format-API in Java
[Ruby on Rails] Bild-Diashow mit Skippr
Versuchen Sie es mit der REST-API von JobScheduler - Java RestClient-Implementierung -
Versuchen Sie es mit der Emotion API von Android
Versuchen Sie es mit der Wii-Fernbedienung in Java
Versuchen Sie, mit Scala mithilfe der Standardbibliothek von Java Text zu einem Bild hinzuzufügen
[Android] [Java] Laden Sie Bilder auf GCS (Google Cloud Storage) mit Stream mit Glide herunter
Versuchen Sie es mit der RestClient Test-Klasse der REST-API-Java von JobScheduler.
Versuchen Sie, eine Java 8-Umgebung unter Amazon Linux2 zu erstellen
Installieren Sie Java und Android-SDK auf dem Mac mit Homebrew
Anfänger versuchen Android Studio Teil 2 (Ereignisverarbeitung)
Versuchen Sie es mit Sourcetrail (Win-Version) mit Java-Code
Versuchen Sie, die Cloud Vision-API von GCP in Java zu verwenden
Versuchen Sie es mit Sourcetrail (MacOS-Version) mit Java-Code
Anfänger versuchen Android Studio Teil 1 (Hello World)
Versuchen Sie, mit JZOS von Java aus auf das Dataset zuzugreifen
Übersetzen Sie mit der Microsoft Translator Text API unter Android ~ Implementierung ~
Versuchen Sie es mit der Syntaxanalyse der COTOHA-API in Java
Geschichte der Testautomatisierung mit Appium [Android / Java]