Skip to content

Commit

Permalink
Fix TFLite project, expand the Android project materials
Browse files Browse the repository at this point in the history
  • Loading branch information
sanggusti committed Dec 3, 2024
1 parent 84cc0b9 commit efbd9c4
Show file tree
Hide file tree
Showing 35 changed files with 1,029 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
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')
}
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
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());
}
}
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 not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Broccoli
Carrot
Cheese
Potato
Tomato
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);
}
// ----------------------------------------------------
}
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);
}
// ----------------------------------------------------

}

Loading

0 comments on commit efbd9c4

Please sign in to comment.