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

RK3588芯片NPU的使用:PPOCRv4例子在安卓系统部署

本文的目标

将PPOCRv4 C语言例子适配安卓端,提供选择图片后进行OCR识别功能。PPOCRv4 C语言例子请参考之前的博文《RK3588芯片NPU的使用:Windows11 Docker中运行PPOCRv4例子》。

开发环境说明

  • 主机系统:Windows 11
  • 目标设备:搭载RK3588芯片的安卓开发板
  • 核心工具:Android Studio Koala | 2024.1.1 Patch 2,NDK 27.0

适配(迁移)安卓开始

因为有了上一次迁移的经验,本次只着重解决核心问题。关于NDK等基础内容,请参考《手把手部署YOLOv5到RK3588安卓端:NPU加速与JNI/C/Kotlin接口开发指南》。

0. 新建kotlin项目

创建一个空界面的kotlin项目。MainActivity作为入口,再新建包ui.activity和paddle,并在activity包下创建RKNNPaddleOcrActivity。
结构如下:

1.接口设计

本例中准备在native层暴露三个方法,分别是初始化、识别和释放。
kotlin层先创建接口
创建InferenceWrapper类:

package .paddleimport android.graphics.Bitmapclass InferenceWrapper {companion object {init {System.loadLibrary("rknn_paddle_ocr")}}external fun init(detModelPath: String?,recModelPath: String?,): Booleanexternal fun detect(originalImage: Bitmap?): Booleanexternal fun release(): Boolean
}

native层随后创建对应接口
在src->main下新建cpp目录,并新建一个cpp文件叫native-lib.cpp。
对应按规则直接写Cpp对应的方法,如下:

#include <jni.h>extern "C"
JNIEXPORT jboolean JNICALL Java_com_linc_rknn_paddle_InferenceWrapper_init(JNIEnv *env, jobject thiz, jstring jdet_model_path, jstring jrec_model_path);extern "C"
JNIEXPORT jboolean JNICALL Java_com_linc_rknn_paddle_InferenceWrapper_detect(JNIEnv *env, jobject thiz, jobject jbitmap);extern "C"
JNIEXPORT jboolean JNICALL Java_com_linc_rknn_paddle_InferenceWrapper_release(JNIEnv *env, jobject thiz);

2.依赖so和源文件迁移

OpenCV

本例中对图像的处理用到了OpenCV,在rknn_model_zoo\3rdparty\opencv\opencv-android-sdk-build可以找到,版本是v3.4.5.(现在版本是OpenCV4.11,但能解决问题就是合适的版本)。

其他源文件

其他文件的迁移我参考了上一次,结构如下:

模型

检测模型和识别模型已经转换为rknn格式,放入assets目录:

3.接口实现

3.1 两种图片像素格式(色彩模式)ARGB_8888与RGB_888

安卓系统中常用的图片bitmap的像素格式是ARGB_8888, 其中A表示Alpha通道,R表示红色通道,G表示绿色通道,B表示蓝色通道,8888表示每个通道使用8位来表示,因此总共需要32位(4个字节)来表示一个像素。
而在RGB_888则少了一个Alpha通道,只有红绿蓝三个通道,每个通道用8位表示,也即24位(3个字节)表示一个像素。正巧,在rknn的推理中,需要用到RGB_888格式。

特性ARGB_8888RGB888
像素大小4 字节(32 位)3 字节(24 位)
包含通道Alpha、Red、Green、BlueRed、Green、Blue
内存占用较高(1080p 图像 ≈ 8.3MB)较低(1080p 图像 ≈ 6.2MB)
透明度支持
Android 支持原生支持(Bitmap.Config)需手动转换或使用第三方库
硬件加速兼容性通用 GPU 渲染更适合 NPU 推理(如 RKNN)

3.2 ARGB_8888转为RGB_888

我尝试了几种方案,最终决定用最省心的方式,就是OpenCV,性价比最高!

    void *dstBuf;if (ANDROID_BITMAP_RESULT_SUCCESS != AndroidBitmap_lockPixels(env, jbitmap, &dstBuf)) {LOGE("lock dst bitmap failed");return JNI_FALSE;}// 创建 OpenCV Mat(ARGB_8888 → RGBA)cv::Mat argbMat(dstInfo.height, dstInfo.width, CV_8UC4, dstBuf);// 转换为 RGB888cv::Mat rgbMat;cv::cvtColor(argbMat, rgbMat, cv::COLOR_RGBA2RGB);

3.3 Mat格式转为image_buffer_t结构体

为了最大限度的服用原有代码,上述我们得到的rgbMat需要转为image_buffer_t结构体。结构体的定义如下:

typedef struct {int width;int height;int width_stride;int height_stride;image_format_t format;unsigned char* virt_addr;int size;int fd;
} image_buffer_t;

我们一一将结构体的成员赋值,转为函数如下:

static void convertMatToImageBuffer(const cv::Mat& mat, image_buffer_t& buffer) {// 1. 检查输入 Mat 的格式是否为 RGB888 (CV_8UC3)CV_Assert(mat.type() == CV_8UC3);// 2. 填充结构体字段buffer.width = mat.cols;         // 图像宽度(像素)buffer.height = mat.rows;        // 图像高度(像素)buffer.width_stride = mat.step;  // 每行字节数(包含可能的填充)buffer.height_stride 
http://www.xdnf.cn/news/907.html

相关文章:

  • 2025高频面试算法总结篇【其他】
  • 《Java面试通关宝典:基础篇》——Java面试题系列(持续更新)
  • LabVIEW 开发中数据滤波方式的选择
  • 【C++】模板2.0
  • GitHub 趋势日报 (2025年04月20日)
  • Unity-微信截图功能简单复刻-04修改纹理
  • 上海共荣应用营养研究所SAT-3D膳食诊断:从5岁到60岁,你的饮食习惯决定寿命长短
  • 24.中医知识问答删除历史对话功能前端代码实现
  • 搭建哨兵架构
  • 读文献先读图:火山图怎么看?
  • SATA——PHY层状态机
  • 工作记录7
  • 详解.vscode 下的json .vscode文件夹下各个文件的作用
  • STM32 HAL库 FreeRTOS 软件定时器的使用
  • 新书速览|OpenCV计算机视觉开发实践:基于Qt C++
  • 百度地图MCP:AI助手的地理智能跃升——让位置服务“触手可及”
  • SBTI科学碳目标认证有什么要求?SBTI认证的好处?
  • 【英语语法】词法---连词
  • lmgrd web api调用
  • 【英语语法】词法---介词
  • 数据结构第六章(五)-拓扑排序、关键路径
  • Mysql卸载
  • 电力MOSFET漏源过电压与窄脉冲自保护驱动电路
  • TM1640学习手册及示例代码
  • 博客系统-邮件发送-nginx-服务部署
  • 《深入解析C++中的explicit关键字:防止隐式转换的利器》
  • word显示段落标记符(¶)而不是回车符
  • spring boot使用Scheduling实现动态增删启停定时任务
  • 【sylar-webserver】重构日志系统
  • 数据仓库 vs 数据湖:架构、应用场景与技术差异全解析