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!
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!
Bereiten Sie ein Modell vor, das mit TensorFlow trainiert wurde. Dieses Mal werde ich das gehostete Modell verwenden, also werde ich es weglassen!
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
Dieses Mal werde ich erklären, wie man Android (Java) einbettet!
Bitte verwenden Sie einen beliebigen Namen für den Projektnamen usw.! 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.
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"
}
}
}
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).
Erstellen Sie zunächst einen Asset-Ordner. Kopieren Sie die Datei aus dem entpackten Ordner. Benennen Sie es nach dem Kopieren in "model.tflite" und "labels.txt" um.
Damit ist die Modellinstallation abgeschlossen.
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). 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();
Wenn Sie es löschen, werden Sie von Android Studio dazu aufgefordert. Wenn Sie also "Alt + Eingabetaste" drücken, wird es automatisch importiert. Beim Importieren
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.
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";
}
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
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>
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.
Ö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).
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! !!
Dann möchte ich es tatsächlich verschieben! Zuallererst das Bild des Hundes Parkbank ... Nagel,,, Amerikanisches Chamäleon ... Hmm Die Genauigkeit ist subtil Als nächstes ist ein Bild einer schönen Landschaft. Das Stadtbild von Delft
Fensterscheibe ... Fußmatte ... blind,,, Hmm Nein!
Die Genauigkeit war subtil, aber gut? Ich konnte die Bilder klassifizieren! Nächstes Mal möchte ich in Echtzeit klassifizieren! Bis bald!
Recommended Posts