-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix TFLite project, expand the Android project materials
- Loading branch information
Showing
35 changed files
with
1,029 additions
and
0 deletions.
There are no files selected for viewing
1 change: 1 addition & 0 deletions
1
ILT6-deploying-models/TFLite/SimpleImageClassification/app/.gitignore
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
/build |
55 changes: 55 additions & 0 deletions
55
ILT6-deploying-models/TFLite/SimpleImageClassification/app/build.gradle
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
plugins { | ||
id 'com.android.application' | ||
id 'org.jetbrains.kotlin.android' | ||
} | ||
|
||
android { | ||
compileSdk 34 | ||
|
||
defaultConfig { | ||
applicationId "com.example.travelokaocr" | ||
minSdk 21 | ||
targetSdk 34 | ||
versionCode 1 | ||
versionName "1.0" | ||
|
||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" | ||
} | ||
|
||
buildTypes { | ||
release { | ||
minifyEnabled false | ||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' | ||
} | ||
} | ||
|
||
buildFeatures{ | ||
viewBinding true | ||
} | ||
|
||
compileOptions { | ||
sourceCompatibility JavaVersion.VERSION_1_8 | ||
targetCompatibility JavaVersion.VERSION_1_8 | ||
} | ||
kotlinOptions { | ||
jvmTarget = '1.8' | ||
} | ||
|
||
aaptOptions { | ||
noCompress "tflite" | ||
} | ||
namespace 'com.example.imageclassification' | ||
} | ||
|
||
dependencies { | ||
implementation 'androidx.core:core-ktx:1.7.0' | ||
implementation 'androidx.appcompat:appcompat:1.5.1' | ||
implementation 'com.google.android.material:material:1.7.0' | ||
implementation 'androidx.constraintlayout:constraintlayout:2.1.4' | ||
testImplementation 'junit:junit:4.13.2' | ||
androidTestImplementation 'androidx.test.ext:junit:1.1.5' | ||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' | ||
|
||
implementation('org.tensorflow:tensorflow-lite-support:0.4.4') | ||
implementation('org.tensorflow:tensorflow-lite-gpu:2.9.0') | ||
} |
21 changes: 21 additions & 0 deletions
21
ILT6-deploying-models/TFLite/SimpleImageClassification/app/proguard-rules.pro
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
# Add project specific ProGuard rules here. | ||
# You can control the set of applied configuration files using the | ||
# proguardFiles setting in build.gradle. | ||
# | ||
# For more details, see | ||
# http://developer.android.com/guide/developing/tools/proguard.html | ||
|
||
# If your project uses WebView with JS, uncomment the following | ||
# and specify the fully qualified class name to the JavaScript interface | ||
# class: | ||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview { | ||
# public *; | ||
#} | ||
|
||
# Uncomment this to preserve the line number information for | ||
# debugging stack traces. | ||
#-keepattributes SourceFile,LineNumberTable | ||
|
||
# If you keep the line number information, uncomment this to | ||
# hide the original source file name. | ||
#-renamesourcefileattribute SourceFile |
26 changes: 26 additions & 0 deletions
26
...ion/app/src/androidTest/java/com/example/imageclassification/ExampleInstrumentedTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package com.example.imageclassification; | ||
|
||
import android.content.Context; | ||
|
||
import androidx.test.platform.app.InstrumentationRegistry; | ||
import androidx.test.ext.junit.runners.AndroidJUnit4; | ||
|
||
import org.junit.Test; | ||
import org.junit.runner.RunWith; | ||
|
||
import static org.junit.Assert.*; | ||
|
||
/** | ||
* Instrumented test, which will execute on an Android device. | ||
* | ||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a> | ||
*/ | ||
@RunWith(AndroidJUnit4.class) | ||
public class ExampleInstrumentedTest { | ||
@Test | ||
public void useAppContext() { | ||
// Context of the app under test. | ||
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); | ||
assertEquals("com.example.imageclassification", appContext.getPackageName()); | ||
} | ||
} |
21 changes: 21 additions & 0 deletions
21
ILT6-deploying-models/TFLite/SimpleImageClassification/app/src/main/AndroidManifest.xml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"> | ||
|
||
<application | ||
android:allowBackup="true" | ||
android:icon="@mipmap/ic_launcher" | ||
android:label="@string/app_name" | ||
android:roundIcon="@mipmap/ic_launcher_round" | ||
android:supportsRtl="true" | ||
android:theme="@style/AppTheme"> | ||
<activity android:name="com.example.imageclassification.MainActivity" | ||
android:exported="true"> | ||
<intent-filter> | ||
<action android:name="android.intent.action.MAIN" /> | ||
|
||
<category android:name="android.intent.category.LAUNCHER" /> | ||
</intent-filter> | ||
</activity> | ||
</application> | ||
|
||
</manifest> |
Binary file renamed
BIN
+12.4 MB
...ing-models/TFLite/ImageClassification.zip → ...ification/app/src/main/assets/vegs.tflite
Binary file not shown.
5 changes: 5 additions & 0 deletions
5
ILT6-deploying-models/TFLite/SimpleImageClassification/app/src/main/assets/vegs.txt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
Broccoli | ||
Carrot | ||
Cheese | ||
Potato | ||
Tomato |
86 changes: 86 additions & 0 deletions
86
...leImageClassification/app/src/main/java/com/example/imageclassification/MainActivity.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
package com.example.imageclassification; | ||
|
||
import android.content.Intent; | ||
import android.graphics.Bitmap; | ||
import android.net.Uri; | ||
import android.os.Bundle; | ||
import android.provider.MediaStore; | ||
import android.view.View; | ||
import android.widget.Button; | ||
import android.widget.ImageView; | ||
import android.widget.TextView; | ||
|
||
import androidx.annotation.Nullable; | ||
import androidx.appcompat.app.AppCompatActivity; | ||
|
||
import java.io.IOException; | ||
|
||
public class MainActivity extends AppCompatActivity { | ||
|
||
// ---- Tambahkan contoh kodingan disini ---- | ||
ImageView imageView; | ||
Uri imageuri; | ||
Button buclassify; | ||
TextView classitext; | ||
|
||
TFLiteHelper tfLiteHelper; | ||
private Bitmap bitmap; | ||
|
||
@Override | ||
protected void onCreate(Bundle savedInstanceState) { | ||
super.onCreate(savedInstanceState); | ||
setContentView(R.layout.activity_main); | ||
imageView = (ImageView) findViewById(R.id.image); | ||
buclassify = (Button) findViewById(R.id.classify); | ||
classitext = (TextView) findViewById(R.id.classifytext); | ||
|
||
tfLiteHelper = new TFLiteHelper(this); | ||
tfLiteHelper.init(); | ||
|
||
imageView.setOnClickListener(selectImageListener); | ||
buclassify.setOnClickListener(classifyImageListtener); | ||
|
||
} | ||
|
||
@Override | ||
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { | ||
super.onActivityResult(requestCode, resultCode, data); | ||
if (requestCode == 12 && resultCode == RESULT_OK && data != null) { | ||
imageuri = data.getData(); | ||
try { | ||
bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), imageuri); | ||
imageView.setImageBitmap(bitmap); | ||
} catch (IOException e) { | ||
e.printStackTrace(); | ||
} | ||
} | ||
} | ||
|
||
View.OnClickListener selectImageListener = new View.OnClickListener() { | ||
@Override | ||
public void onClick(View view) { | ||
String SELECT_TYPE = "image/*"; | ||
String SELECT_PICTURE = "Select Picture"; | ||
|
||
Intent intent = new Intent(); | ||
intent.setType(SELECT_TYPE); | ||
intent.setAction(Intent.ACTION_GET_CONTENT); | ||
startActivityForResult(Intent.createChooser(intent, SELECT_PICTURE), 12); | ||
} | ||
}; | ||
|
||
View.OnClickListener classifyImageListtener = new View.OnClickListener() { | ||
@Override | ||
public void onClick(View v) { | ||
if (bitmap != null) { | ||
tfLiteHelper.classifyImage(bitmap); | ||
setLabel(tfLiteHelper.showresult()); | ||
} | ||
} | ||
}; | ||
|
||
void setLabel(String label) { | ||
classitext.setText(label); | ||
} | ||
// ---------------------------------------------------- | ||
} |
149 changes: 149 additions & 0 deletions
149
...leImageClassification/app/src/main/java/com/example/imageclassification/TFLiteHelper.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
package com.example.imageclassification; | ||
|
||
import android.app.Activity; | ||
import android.content.res.AssetFileDescriptor; | ||
import android.graphics.Bitmap; | ||
|
||
import org.tensorflow.lite.DataType; | ||
import org.tensorflow.lite.Interpreter; | ||
import org.tensorflow.lite.support.common.FileUtil; | ||
import org.tensorflow.lite.support.common.TensorOperator; | ||
import org.tensorflow.lite.support.common.TensorProcessor; | ||
import org.tensorflow.lite.support.common.ops.NormalizeOp; | ||
import org.tensorflow.lite.support.image.ImageProcessor; | ||
import org.tensorflow.lite.support.image.TensorImage; | ||
import org.tensorflow.lite.support.image.ops.ResizeOp; | ||
import org.tensorflow.lite.support.image.ops.ResizeWithCropOrPadOp; | ||
import org.tensorflow.lite.support.label.TensorLabel; | ||
import org.tensorflow.lite.support.tensorbuffer.TensorBuffer; | ||
|
||
import java.io.FileInputStream; | ||
import java.io.IOException; | ||
import java.nio.MappedByteBuffer; | ||
import java.nio.channels.FileChannel; | ||
import java.util.Collections; | ||
import java.util.List; | ||
import java.util.Map; | ||
|
||
public class TFLiteHelper { | ||
|
||
private int imageSizeX; | ||
private int imageSizeY; | ||
|
||
private List<String> labels; | ||
private Interpreter tflite; | ||
|
||
private MappedByteBuffer tfliteModel; | ||
private TensorImage inputImageBuffer; | ||
private TensorBuffer outputProbabilityBuffer; | ||
private TensorProcessor probabilityProcessor; | ||
|
||
private static final float IMAGE_MEAN = 0.0f; | ||
private static final float IMAGE_STD = 1.0f; | ||
|
||
private static final float PROBABILITY_MEAN = 0.0f; | ||
private static final float PROBABILITY_STD = 255.0f; | ||
|
||
private Activity context; | ||
|
||
TFLiteHelper(Activity context) { | ||
this.context = context; | ||
} | ||
|
||
// ---- Kolom inisiasi TensorFlow Lite Interpreter ---- | ||
|
||
void init() { | ||
try { | ||
Interpreter.Options opt = new Interpreter.Options(); | ||
tflite = new Interpreter(loadmodelfile(context), opt); | ||
} catch (Exception e) { | ||
e.printStackTrace(); | ||
} | ||
} | ||
// ---------------------------------------------------- | ||
|
||
// ---- Kolom preprocessing gambar ---- | ||
private TensorImage loadImage(final Bitmap bitmap) { | ||
// Loads bitmap into a TensorImage. | ||
inputImageBuffer.load(bitmap); | ||
|
||
// Creates processor for the TensorImage. | ||
int cropSize = Math.min(bitmap.getWidth(), bitmap.getHeight()); | ||
// TODO(b/143564309): Fuse ops inside ImageProcessor. | ||
ImageProcessor imageProcessor = | ||
new ImageProcessor.Builder() | ||
.add(new ResizeWithCropOrPadOp(cropSize, cropSize)) | ||
.add(new ResizeOp(imageSizeX, imageSizeY, ResizeOp.ResizeMethod.NEAREST_NEIGHBOR)) | ||
.add(getPreprocessNormalizeOp()) | ||
.build(); | ||
return imageProcessor.process(inputImageBuffer); | ||
} | ||
// ---------------------------------------------------- | ||
|
||
// ---- Kolom pemanggilan model tflite ---- | ||
private MappedByteBuffer loadmodelfile(Activity activity) throws IOException { | ||
String MODEL_NAME = "vegs.tflite"; | ||
AssetFileDescriptor fileDescriptor = activity.getAssets().openFd(MODEL_NAME); | ||
FileInputStream inputStream = new FileInputStream(fileDescriptor.getFileDescriptor()); | ||
FileChannel fileChannel = inputStream.getChannel(); | ||
long startoffset = fileDescriptor.getStartOffset(); | ||
long declaredLength = fileDescriptor.getDeclaredLength(); | ||
return fileChannel.map(FileChannel.MapMode.READ_ONLY, startoffset, declaredLength); | ||
} | ||
|
||
void classifyImage(Bitmap bitmap){ | ||
int imageTensorIndex = 0; | ||
int[] imageShape = tflite.getInputTensor(imageTensorIndex).shape(); // {1, height, width, 3} | ||
imageSizeY = imageShape[1]; | ||
imageSizeX = imageShape[2]; | ||
DataType imageDataType = tflite.getInputTensor(imageTensorIndex).dataType(); | ||
|
||
int probabilityTensorIndex = 0; | ||
int[] probabilityShape = | ||
tflite.getOutputTensor(probabilityTensorIndex).shape(); // {1, NUM_CLASSES} | ||
DataType probabilityDataType = tflite.getOutputTensor(probabilityTensorIndex).dataType(); | ||
|
||
inputImageBuffer = new TensorImage(imageDataType); | ||
outputProbabilityBuffer = TensorBuffer.createFixedSize(probabilityShape, probabilityDataType); | ||
probabilityProcessor = new TensorProcessor.Builder().add(getPostprocessNormalizeOp()).build(); | ||
|
||
inputImageBuffer = loadImage(bitmap); | ||
|
||
tflite.run(inputImageBuffer.getBuffer(),outputProbabilityBuffer.getBuffer().rewind()); | ||
|
||
} | ||
|
||
private TensorOperator getPreprocessNormalizeOp() { | ||
return new NormalizeOp(IMAGE_MEAN, IMAGE_STD); | ||
} | ||
// ---------------------------------------------------- | ||
|
||
// ---- Kolom postprocessing ---- | ||
public String showresult() { | ||
try { | ||
labels = FileUtil.loadLabels(context, "vegs.txt"); | ||
} catch (Exception e) { | ||
e.printStackTrace(); | ||
return null; | ||
} | ||
Map<String, Float> labeledProbability = | ||
new TensorLabel(labels, probabilityProcessor.process(outputProbabilityBuffer)) | ||
.getMapWithFloatValue(); | ||
float maxValueInMap = (Collections.max(labeledProbability.values())); | ||
String result = null; | ||
for (Map.Entry<String, Float> entry : labeledProbability.entrySet()) { | ||
if (entry.getValue() == maxValueInMap) { | ||
result = entry.getKey(); | ||
} | ||
} | ||
|
||
return result; | ||
} | ||
|
||
private TensorOperator getPostprocessNormalizeOp() { | ||
return new NormalizeOp(PROBABILITY_MEAN, PROBABILITY_STD); | ||
} | ||
// ---------------------------------------------------- | ||
|
||
} | ||
|
Oops, something went wrong.