赞
踩
官方其实已经提供了详细的端侧部署,如果按照官方步骤无法正常编译的,可在评论区留言,我将详细编译步骤也发布出来,在这里我主要讲一下如何将官方的提供的代码转成可方便移植的module包,便于方便引入各个项目中。
官方2.5编译教程:PaddleOCR/readme.md at release/2.5 · PaddlePaddle/PaddleOCR (github.com)
官方包结构对比module包结构,可以发现后面结构清晰明了
1、首先将官方包下所有文件拷贝到新建的Module包下
2、删除以下文件
3、新建单例模式启动OCRPredictor类和接口OnImagePredictorListener类,代码如下:
- package com.yangy.ocr;
-
- import android.annotation.SuppressLint;
- import android.content.Context;
- import android.graphics.Bitmap;
- import android.graphics.BitmapFactory;
- import android.media.ExifInterface;
- import android.os.Binder;
- import android.os.Build;
- import android.os.Bundle;
- import android.os.Handler;
- import android.os.HandlerThread;
- import android.os.Message;
- import android.text.TextUtils;
- import android.util.Base64;
- import android.util.Log;
-
- import java.io.IOException;
-
- public class OCRPredictor {
- public final int REQUEST_LOAD_MODEL = 0;
- public final int REQUEST_RUN_MODEL = 1;
- public final int RESPONSE_LOAD_MODEL_SUCCESSED = 0;
- public final int RESPONSE_LOAD_MODEL_FAILED = 1;
- public final int RESPONSE_RUN_MODEL_SUCCESSED = 2;
- public final int RESPONSE_RUN_MODEL_FAILED = 3;
- public final int RESPONSE_RUN_MODEL_NO_FILE = 4;
-
- // private final String assetModelDirPath = "models/bank";
- // private final String assetlabelFilePath = "labels/ppocr_keys_bank.txt";
- private final String assetModelDirPath = "models/ocr";
- private final String assetlabelFilePath = "labels/ppocr_keys_v1.txt";
-
- protected Handler sender = null; // Send command to worker thread
- protected HandlerThread worker = null; // Worker thread to load&run model
- protected volatile Predictor predictor = null;
-
- private OnImagePredictorListener listener;
- @SuppressLint("StaticFieldLeak")
- private static OCRPredictor ocrPredictor;
- private Context context;
-
- public static OCRPredictor getInstance(Context context) {
- if (ocrPredictor == null) {
- ocrPredictor = new OCRPredictor(context);
- }
- return ocrPredictor;
- }
-
-
- public OCRPredictor(Context context) {
- this.context = context;
- init();
- }
-
- /**
- *
- */
- private void init() {
- worker = new HandlerThread("Predictor Worker");
- worker.start();
- sender = new Handler(worker.getLooper()) {
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case REQUEST_LOAD_MODEL:
- // Load model and reload test image
- if (!onLoadModel(context)) {
- predictor = null;
- Log.d("OCR", "加载模型失败!");
- } else {
- Log.d("OCR", "加载模型成功!");
- }
- break;
- case REQUEST_RUN_MODEL:
- Bundle bundle = msg.getData();
- if (predictor == null) {
- receiver.sendEmptyMessage(RESPONSE_LOAD_MODEL_FAILED);
- } else {
- // Run model if model is loaded
- if (!TextUtils.isEmpty(bundle.getString("imagePath"))) {
- if (!onRunModel(bundle.getString("imagePath"))) {
- receiver.sendEmptyMessage(RESPONSE_RUN_MODEL_FAILED);
- } else {
- receiver.sendEmptyMessage(RESPONSE_RUN_MODEL_SUCCESSED);
- }
- } else {
- ImageBinder imageBinder = (ImageBinder) bundle.getBinder("bitmap");
- if (imageBinder != null) {
- Bitmap bitmap = imageBinder.getBitmap();
- if (!onRunModel(bitmap)) {
- receiver.sendEmptyMessage(RESPONSE_RUN_MODEL_FAILED);
- } else {
- receiver.sendEmptyMessage(RESPONSE_RUN_MODEL_SUCCESSED);
- }
- } else {
- StringBinder stringBinder = (StringBinder) bundle.getBinder("base64");
- if (stringBinder != null) {
- String str = stringBinder.getStr();
- if (!onRunModelBase64(str)) {
- receiver.sendEmptyMessage(RESPONSE_RUN_MODEL_FAILED);
- } else {
- receiver.sendEmptyMessage(RESPONSE_RUN_MODEL_SUCCESSED);
- }
- } else {
- receiver.sendEmptyMessage(RESPONSE_RUN_MODEL_NO_FILE);
- }
- }
-
- }
- }
- break;
- }
- }
- };
- sender.sendEmptyMessage(REQUEST_LOAD_MODEL);
- }
-
- private Handler receiver = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- // case RESPONSE_LOAD_MODEL_SUCCESSED:
- // sender.sendEmptyMessage(REQUEST_RUN_MODEL);
- // break;
- case RESPONSE_LOAD_MODEL_FAILED:
- listener.failure(0, "加载模型失败!");
- break;
- case RESPONSE_RUN_MODEL_SUCCESSED:
- listener.success(predictor.outputResult, predictor.outputResultList, predictor.outputImage);
- break;
- case RESPONSE_RUN_MODEL_FAILED:
- listener.failure(1, "运行模型失败!");
- break;
- case RESPONSE_RUN_MODEL_NO_FILE:
- listener.failure(2, "运行模型失败,请传入待识别图片!");
- break;
- default:
- break;
- }
- }
- };
-
- public void predictor(final String imagePath, final OnImagePredictorListener listener) {
- this.listener = listener;
-
- Message message = new Message();
- message.what = REQUEST_RUN_MODEL;
- Bundle bundle = new Bundle();
- bundle.putString("imagePath", imagePath);
- message.setData(bundle);
-
- sender.sendMessage(message);
- }
-
- public void predictorBitMap(final Bitmap bitmap, final OnImagePredictorListener listener) {
- this.listener = listener;
-
- Message message = new Message();
- message.what = REQUEST_RUN_MODEL;
- Bundle bundle = new Bundle();
- bundle.putBinder("bitmap", new ImageBinder(bitmap));
- message.setData(bundle);
-
- sender.sendMessage(message);
- }
-
- public void predictorBase64(final String base64, final OnImagePredictorListener listener) {
- this.listener = listener;
-
- Message message = new Message();
- message.what = REQUEST_RUN_MODEL;
- Bundle bundle = new Bundle();
- bundle.putBinder("base64", new StringBinder(base64));
- message.setData(bundle);
-
- sender.sendMessage(message);
- }
-
-
- private static class ImageBinder extends Binder {
- private Bitmap bitmap;
-
- public ImageBinder(Bitmap bitmap) {
- this.bitmap = bitmap;
- }
-
- Bitmap getBitmap() {
- return bitmap;
- }
- }
-
-
- private static class StringBinder extends Binder {
- private String str;
-
- public StringBinder(String str) {
- this.str = str;
- }
-
- String getStr() {
- return str;
- }
- }
-
-
- /**
- * call in onCreate, model init
- *
- * @return
- */
- private boolean onLoadModel(Context context) {
- if (predictor == null) {
- predictor = new Predictor();
- }
- return predictor.init(context, assetModelDirPath, assetlabelFilePath);
- }
-
- private boolean onRunModel(String imagePath) {
- try {
- ExifInterface exif = null;
- exif = new ExifInterface(imagePath);
- int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION,
- ExifInterface.ORIENTATION_UNDEFINED);
- Log.i("OCR", "rotation " + orientation);
- Bitmap image = BitmapFactory.decodeFile(imagePath);
- image = Utils.rotateBitmap(image, orientation);
-
- predictor.setInputImage(image);
- return predictor.isLoaded() && predictor.runModel();
- } catch (IOException e) {
- e.printStackTrace();
- return false;
- }
- }
-
- private boolean onRunModel(Bitmap image) {
- try {
- predictor.setInputImage(image);
- return predictor.isLoaded() && predictor.runModel();
- } catch (Exception e) {
- e.printStackTrace();
- return false;
- }
- }
-
- private boolean onRunModelBase64(String base64) {
- try {
- byte[] bitmapByte = Base64.decode(base64, Base64.DEFAULT);
- Bitmap bitmap = BitmapFactory.decodeByteArray(bitmapByte, 0, bitmapByte.length);
- predictor.setInputImage(bitmap);
- return predictor.isLoaded() && predictor.runModel();
- } catch (Exception e) {
- e.printStackTrace();
- return false;
- }
- }
-
- /**
- * 卸载模型
- */
- private void onUnloadModel() {
- if (predictor != null) {
- predictor.releaseModel();
- predictor = null;
- }
- }
-
- /**
- * 退出线程
- */
- private void quit() {
- if (worker != null) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
- worker.quitSafely();
- } else {
- worker.quit();
- }
- }
- }
-
- /**
- * 销毁
- */
- public void onDestroy() {
- onUnloadModel();
- quit();
- ocrPredictor = null;
- }
-
- }

- package com.yangy.ocr;
-
- import android.graphics.Bitmap;
-
- import java.util.ArrayList;
-
- public abstract class OnImagePredictorListener {
- public abstract void success(String result, ArrayList<OCRResultModel> list, Bitmap bitmap);
-
- public void failure(int code, String message) {
- }
- }
4、修改Predictor类,加入以下两行
5、修改native.cpp文件,将官方的_com_baidu_paddle_lite_demo_ocr_替换成我们自己的包名,如_com_yangy_ocr_,如下截图:
6、最后一步,删除Module包下build.gradle中下载PaddleLite、OpenCV包的代码,红框部分全部删除,我们不需要 ,PaddleLite和模型包需要自行编译
7、使用方式,在主App下引入该Module包,短短几行代码就可实现
这里发布一个自己打的包,引入aar包后,使用如上面最后一图:
1、minSdkVersion 21
2、支持arm64-v8a和armabi-v7a
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。