PP-OCR的安卓端部署

EMO了几天

我浪费了几天的生命,去研究PP-OCR的模型微调、从训练模型导出预测模型,结果一个坑接着一个坑,没有善终。

找了好多资料,得到一些负面信息,比如说飞浆的团队修复问题不及时啦,代码仓库有好多年不更新啦,为了KPI而搞开源啦等等。

今天想着还是先把安卓端部署过程记录下来吧,忘掉那些不开心吧。

安卓端部署简介

如果直接用官方提供的模型去跑,其实还是挺香的,OCR是飞浆框架下最厉害的库了。

安卓部署官方也有demo的(当然是几年前的),PaddleOCR--deploy下去找,我也放到csdn下载了。

例子中使用的PP-OCRv2的模型,想想现在都PP-OCRv4了,是不是心中着急?

PaddleLite

想要在安卓端部署,需要飞浆下的另一个重要的库,PaddleLite。

Paddle Lite 是百度飞桨(PaddlePaddle)生态中的端侧推理引擎,专注于在移动设备、嵌入式设备和边缘计算场景中实现高效的深度学习模型部署。其核心目标是通过轻量化、高性能的优化技术,降低模型运行时的资源消耗,同时支持多种硬件平台和操作系统。

Demo中使用的是2.10版本,目录结构如下:

OpenCV

OpenCV的作用自然在负责图像处理部分。在安卓平台,它的用途还真是广泛的不得了。

Demo中使用的是4.2.0,目录结构如下:

PaddleOCR的模型和字典

模型文件和字典是程序运行后下载的,如下图:

App源码简介

代码结构依然是Java层+Native层。

Java代码

上层的业务逻辑,以及通过JNI调用Native层代码。结构如下:

Java层与Native层沟通仅仅用了三个方法,它们在OCRPredictorNative类中:

java 复制代码
    protected native long init(String detModelPath, String recModelPath, String clsModelPath, int useOpencl, int threadNum, String cpuMode);

    protected native float[] forward(long pointer, Bitmap originalImage,int max_size_len, int run_det, int run_cls, int run_rec);

    protected native void release(long pointer);

Native层代码

源码结构如下图:

JNI的实现在native.cpp中,重点看forward方法的实现,OCR的处理逻辑及返回结果都在这里了。

cpp 复制代码
extern "C" JNIEXPORT jfloatArray JNICALL
Java_com_baidu_paddle_lite_demo_ocr_OCRPredictorNative_forward(
    JNIEnv *env, jobject thiz, jlong java_pointer, jobject original_image,
    jint j_max_size_len, jint j_run_det, jint j_run_cls, jint j_run_rec) {
  LOGI("begin to run native forward");
  if (java_pointer == 0) {
    LOGE("JAVA pointer is NULL");
    return cpp_array_to_jfloatarray(env, nullptr, 0);
  }

  cv::Mat origin = bitmap_to_cv_mat(env, original_image);
  if (origin.size == 0) {
    LOGE("origin bitmap cannot convert to CV Mat");
    return cpp_array_to_jfloatarray(env, nullptr, 0);
  }

  int max_size_len = j_max_size_len;
  int run_det = j_run_det;
  int run_cls = j_run_cls;
  int run_rec = j_run_rec;

  ppredictor::OCR_PPredictor *ppredictor =
      (ppredictor::OCR_PPredictor *)java_pointer;
  std::vector<int64_t> dims_arr;
  std::vector<ppredictor::OCRPredictResult> results =
      ppredictor->infer_ocr(origin, max_size_len, run_det, run_cls, run_rec);
  LOGI("infer_ocr finished with boxes %ld", results.size());

  // 这里将std::vector<ppredictor::OCRPredictResult> 序列化成
  // float数组,传输到java层再反序列化
  std::vector<float> float_arr;
  for (const ppredictor::OCRPredictResult &r : results) {
    float_arr.push_back(r.points.size());
    float_arr.push_back(r.word_index.size());
    float_arr.push_back(r.score);
    // add det point
    for (const std::vector<int> &point : r.points) {
      float_arr.push_back(point.at(0));
      float_arr.push_back(point.at(1));
    }
    // add rec word idx
    for (int index : r.word_index) {
      float_arr.push_back(index);
    }
    // add cls result
    float_arr.push_back(r.cls_label);
    float_arr.push_back(r.cls_score);
  }
  return cpp_array_to_jfloatarray(env, float_arr.data(), float_arr.size());
}

运行结果

相关推荐
-指短琴长-9 分钟前
MySQL快速入门——基本查询(上)
android·数据库·mysql
下位子1 小时前
『OpenGL学习滤镜相机』- Day6: EGL 与 GLSurfaceView 深入理解
android·opengl
java干货1 小时前
MySQL “灵异事件”:我 INSERT id=11,为什么被 UPDATE id=10 锁住了?
android·数据库·mysql
正经教主2 小时前
【App开发】ADB 详细使用教程- Android 开发新人指南
android·adb
gx23482 小时前
MySQL-5-触发器和储存过程
android·mysql·adb
六件套是我10 小时前
redission实现延时队列
android·java·servlet
翔云 OCR API14 小时前
VIN码识别接口技术解析:智能OCR解决方案
ocr
00后程序员张15 小时前
iOS 上架费用全解析 开发者账号、App 审核、工具使用与开心上架(Appuploader)免 Mac 成本优化指南
android·macos·ios·小程序·uni-app·cocoa·iphone
来来走走15 小时前
Android开发(Kotlin) 扩展函数和运算符重载
android·开发语言·kotlin
wuwu_q15 小时前
用通俗易懂 + Android 开发实战的方式,详细讲解 Kotlin Flow 中的 retryWhen 操作符
android·开发语言·kotlin