当前位置: 首页 > news >正文

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类中:

    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的处理逻辑及返回结果都在这里了。

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 pointfor (const std::vector<int> &point : r.points) {float_arr.push_back(point.at(0));float_arr.push_back(point.at(1));}// add rec word idxfor (int index : r.word_index) {float_arr.push_back(index);}// add cls resultfloat_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());
}

运行结果

相关文章:

  • Google Colab测试部署Qwen大模型,实现PDF转MD场景OCR 识别(支持单机环境)
  • CSS3笔记
  • 设计模式 --- 外观模式
  • 基于FPGA的AES加解密系统verilog实现,包含testbench和开发板硬件测试
  • 【ESP32-IDF笔记】06-触摸传感IO配置
  • 基于尚硅谷FreeRTOS视频笔记——6—滴答时钟—上下文切换
  • OpenAI重返巅峰:o3与o4-mini引领AI推理新时代
  • Qt QThread 两种线程管理方法
  • 【 解决Cline插件无法激活及DeepSeek模型请求卡顿或者无法加载问题】
  • C++ `unique_ptr` 多线程使用
  • SpringAI+DeepSeek大模型应用开发——5 ChatPDF
  • 深入解析C++驱动开发实战:优化高效稳定的驱动应用
  • Spring_MVC 快速入门指南
  • 汽车免拆诊断案例 | 2011款雪铁龙世嘉车刮水器偶尔自动工作
  • wordpress 垂直越权(CVE=2021-21389)漏洞复现详细教程
  • 初识Redis · C++客户端string
  • 先导木工机床与养老领域的探索之旅
  • 仿腾讯会议项目实现——设置配置文件
  • 【特殊场景应对1】视觉设计:信息密度与美学的博弈——让简历在HR视网膜上蹦迪的科学指南
  • 6.7.图的深度优先遍历(英文缩写DFS)
  • 纪念沈渭滨︱在恩师沈渭滨老师指导下走上学术研究之路
  • 美国多地举行抗议活动,特朗普经济政策支持率创新低
  • 跑马,一场对机器人的长测试
  • 专家建议提高空气质量“良”的标准,治理水平已具备提标基础
  • 集体断电+差点翻船!这夜的大巴黎,很熟悉
  • 用心用情做好对口支援各项工作!陈吉宁龚正与新疆克拉玛依市党政代表团座谈