android + tflite 分类APP开发-2

APP开发

build.gradle导入库

//implementation 'org.tensorflow:tensorflow-android:+'

implementation 'org.tensorflow:tensorflow-lite:2.4.0'

implementation 'org.tensorflow:tensorflow-lite-support:0.3.1

implementation 'org.tensorflow:tensorflow-lite-metadata:0.3.1'

加载模型

try {

tfLiteClassificationUtil = new TFLiteClassificationUtil(CONST.downPath + "/zjym.tflite");

Toast.makeText(MainActTflite.this, "模型加载成功!", Toast.LENGTH_SHORT).show();

} catch (Exception e) {

Toast.makeText(MainActTflite.this, "模型加载失败!", Toast.LENGTH_SHORT).show();

e.printStackTrace();

finish();

}

模型一般在assets目录下,在编译时会集成到APP中,不利于模型的迭代,这里模型保存在内部存储目录下。

分类预测

try { // 预测图像

FileInputStream fis = new FileInputStream(image_path);

imageView.setImageBitmap(BitmapFactory.decodeStream(fis));

long start = System.currentTimeMillis();

int\[\]\[\] res2Arr = tfLiteClassificationUtil.predictImage(image_path);

long end = System.currentTimeMillis();

String show_text = "预测结果标签:" + (int) res2Arrres2Arr.length-10 +

"\n名称:" + classNames.get((int) res2Arrres2Arr.length-10) +"概率:" + (float) res2Arrres2Arr.length - 11 / 256 +

"\n名称:" + classNames.get((int) res2Arrres2Arr.length-20) +"概率:" + (float) res2Arrres2Arr.length - 21 / 256 +

"\n名称:" + classNames.get((int) res2Arrres2Arr.length-30) +"概率:" + (float) res2Arrres2Arr.length - 31 / 256 +

"\n时间:" + (end - start) + "ms";

textView.setText(show_text);

} catch (Exception e) {

e.printStackTrace();

}

res2Arrres2Arr.length - 11 / 256,两个整数相除显示为0,添加(float)显示字符串

TFLiteClassificationUtil类功能模块

public TFLiteClassificationUtil(String modelPath) throws Exception {

File file = new File(modelPath);

if (!file.exists()) {

throw new Exception("model file is not exists!");

}

try {

Interpreter.Options options = new Interpreter.Options();

options.setNumThreads(NUM_THREADS);// 使用多线程预测

NnApiDelegate delegate = new NnApiDelegate();// 使用Android自带的API或者GPU加速

// GpuDelegate delegate = new GpuDelegate();

options.addDelegate(delegate);

tflite = new Interpreter(file, options);

// 获取输入,shape为{1, height, width, 3}

int\[\] imageShape = tflite.getInputTensor(tflite.getInputIndex("input_1")).shape();

DataType imageDataType = tflite.getInputTensor(tflite.getInputIndex("input_1")).dataType();

inputImageBuffer = new TensorImage(imageDataType);

// 获取输入,shape为{1, NUM_CLASSES}

int\[\] probabilityShape = tflite.getOutputTensor(tflite.getOutputIndex("Identity")).shape();

DataType probabilityDataType = tflite.getOutputTensor(tflite.getOutputIndex("Identity")).dataType();

//outputProbabilityBuffer = TensorBuffer.createFixedSize(probabilityShape, probabilityDataType);

outputProbabilityBuffer = TensorBuffer.createFixedSize(tflite.getOutputTensor(0).shape(), DataType.UINT8);

// 添加图像预处理方式

imageProcessor = new ImageProcessor.Builder()

.add(new ResizeOp(224, 224, ResizeOp.ResizeMethod.NEAREST_NEIGHBOR))

.add(new NormalizeOp(new float\[\] {0.0f}, new float\[\] {255.0f}))

.add(new QuantizeOp(0f, 0.003921569f))

.add(new CastOp(DataType.UINT8))

.build();

TensorProcessor probabilityPostProcessor = new TensorProcessor.Builder()

.add(new DequantizeOp((float) 0, (float) 0.00390625))

.add(new NormalizeOp(new float\[\]{0.0f}, new float\[\]{1.0f}))

.build();

} catch (Exception e) {

e.printStackTrace();

throw new Exception("load model fail!");

}

}

public int\[\]\[\] predictImage(String image_path) throws Exception {

if (!new File(image_path).exists()) {

throw new Exception("image file is not exists!");

}

FileInputStream fis = new FileInputStream(image_path);

Bitmap bitmap = BitmapFactory.decodeStream(fis);

int\[\]\[\] result = predictImage(bitmap);

if (bitmap.isRecycled()) {

bitmap.recycle();

}

return result;

}

// 重载方法,直接使用Bitmap预测

public int\[\]\[\] predictImage(Bitmap bitmap) throws Exception {

return predict(bitmap);

}

private int\[\]\[\] predict(Bitmap bmp) throws Exception {

inputImageBuffer = loadImage(bmp);

try {

tflite.run(inputImageBuffer.getBuffer(), outputProbabilityBuffer.getBuffer().rewind());

} catch (Exception e) {

throw new Exception("predict image fail! log:" + e);

}

int\[\] results = outputProbabilityBuffer.getIntArray();

Log.d("results", Arrays.toString(results));

int\[\]\[\] arr = new intresults.length2;

for (int i=0;i<results.length;i++) {

arri0 = i;

arri1 = resultsi;

}

Arrays.sort(arr, Comparator.comparingInt(e -> e1));

//int l = getMaxResult(results);

return arr;//new float\[\]{l, resultsl};

}

tflite默认保存格式为UINT8,如果不加add(new CastOp(DataType.UINT8))可能显示

Cannot copy to a TensorFlowLite tensor (input_1) with 150528 bytes from a Java Buffer with 602112 bytes

默认的预训练模型是 EfficientNet-Lite0,如果为其他模型,其输入参数等也要修改。可通过下述方法查看。

Android Studio ->File ->open ->other ->tflite,打开tflite模型,build ->Make Project 会自动生成模型接口类,并移动模型到ml目录,查看类中模型参数。

相关推荐
limuyang23 小时前
PDF Viewer KMP(基于 chrome 的 PDFium 内核)
android·kotlin
心平气和量大福大7 小时前
android-控件-搜索框SearchView
android·gitee
2601_962177137 小时前
【MySQL篇】聚合查询,联合查询
android·java·mysql
壮哥_icon7 小时前
【Android】批量 VectorDrawable 动态分别修改 fillColor 和 strokeColor 的踩坑与终极解决方案
android
齐天qaq8 小时前
Android 系统 APK 分区与权限
android
心平气和量大福大8 小时前
android-控件-多选框CheckBox
android·gitee
pengyu10 小时前
【Kotlin 协程修仙录 · 大乘境 · 初阶】 | 跳出三界:协程在 KMP 与后端开发中的跨平台之道
android·kotlin
XiaoLeisj10 小时前
Android Memory Profiler:堆内存指标、内存抖动与泄漏定位
android·性能优化·内存抖动·内存泄露·memory profiler
未来猫咪花10 小时前
Everything is ViewModel:让状态管理回到对象世界
android·flutter·ios