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目录,查看类中模型参数。

相关推荐
心中有国也有家3 小时前
AtomGit Flutter 鸿蒙客户端:Canvas 绘制进阶-路径、渐变与混合模式
android·javascript·flutter·华为·harmonyos
hunterandroid4 小时前
WorkManager 可靠性实战:唯一任务、重试与幂等设计
android·前端
程序员老刘5 小时前
Android 17的10个AI功能,国内用户真正能用的有几个?
android·flutter·ai编程
花开彼岸天~6 小时前
鸿蒙应用开发实战【94】— 实战多卡号场景管理最佳实践
android·华为·harmonyos·鸿蒙系统
用户41659673693556 小时前
视频源文件音频轨异常分析记录
android
我命由我123457 小时前
集成 mupdf-android 的示例做为模块使用报错,程序包android.support.v4.view不存在
android·java·java-ee·android studio·android jetpack·android-studio·android runtime
皓悦编程记7 小时前
【YOLO26 系列】基于YOLO26的垃圾分类检测系统【python源码+Pyqt5界面/WEB+数据集+训练代码】
python·qt·分类
雨白9 小时前
嵌套 ScrollView 滑动冲突实战:实现内部优先滚动
android
阿pin9 小时前
Android随笔-IntentService详解(了解)
android·intentservice
海天鹰9 小时前
content://com.android.externalstorage.documents/document/primary%3A
android