PaddleOCR Android 端到端部署实战:基于 ONNX Runtime 的 PP-OCRv6 SDK 集成指南
2026/9/18 3:46:30 网站建设 项目流程

PaddleOCR Android 端到端部署实战:基于 ONNX Runtime 的 PP-OCRv6 SDK 集成指南

【免费下载链接】PaddleOCR飞桨多语言OCR工具包(实用超轻量OCR系统,支持80+种语言识别,提供数据标注与合成工具,支持服务器、移动端、嵌入式及IoT设备端的训练与部署) Awesome multilingual OCR toolkits based on PaddlePaddle (practical ultra lightweight OCR system, support 80+ languages recognition, provide data annotation and synthesis tools, support training and deployment among server, mobile, embedded and IoT devices)项目地址: https://gitcode.com/paddlepaddle/PaddleOCR

本文以 PaddleOCR 官方 Android 部署示例(deploy/ppocr-android)及其配套部署文档(android_deployment.md)为主线,系统讲解 PP-OCRv6 系列模型在 Android 平台上的完整落地流程:从 SDK/Demo 分离的工程架构、模型准备与 Gradle 构建,到公开 API 的调用方式、推理参数语义、端到端识别流水线的源码级实现,再到自动化性能基准测试。读完本文,你将能够把 PaddleOCR 文本检测 + 识别能力以 AAR 或源码依赖的形式集成进自己的 Android 应用,并精确掌控各阶段耗时。

项目定位:SDK 与 Demo 分离的移动端 OCR 方案

本项目是 PaddleOCR v6 在 Android 平台的部署示例,核心特点是不依赖 Paddle Lite,而是基于 ONNX Runtime 实现移动端 OCR 推理,并使用 OpenCV 完成图像预处理与后处理。整个工程采用SDK 与 Demo 分离架构:ppocr-sdk是一个可独立打包发布的 Android Library,第三方应用可以直接集成;app则是一个基于 MVVM + Jetpack Compose 的参考 Demo,演示 SDK 的标准用法。

从官方文档归纳的核心能力包括:

  • 文本检测 + 文本识别端到端流程;
  • 支持 PP-OCRv6 系列 ONNX 模型(同时兼容 PP-OCRv5_mobile);
  • 详细的性能计时,检测/识别各阶段(预处理、推理、后处理)耗时独立统计;
  • MVVM + Jetpack Compose Demo 应用;
  • 支持 AAR 方式集成。

项目结构解析

官方文档给出的工程结构如下:

ppocr-android/ ├── ppocr-sdk/ # OCR SDK(Android Library) │ ├── src/main/ │ │ ├── assets/models/ # 模型文件目录 │ │ │ ├── det/ # 检测模型:inference.onnx │ │ │ └── rec/ # 识别模型:inference.onnx, inference.yml │ │ └── java/com/paddle/ocr/ │ │ ├── PaddleOCR.kt # [公开 API] SDK 入口 │ │ ├── PaddleOCRConfig.kt # [公开 API] 推理参数配置 │ │ └── ... │ └── build.gradle.kts ├── app/ # Demo App │ ├── src/main/java/com/paddle/ocr/demo/ │ │ ├── OCRApplication.kt # 初始化 SDK │ │ └── ui/ # Compose UI │ └── build.gradle.kts ├── run_benchmark.sh # 性能测试脚本 └── README.md

对照仓库实际源码,ppocr-sdk内部进一步细分为若干职责清晰的包(见 ppocr-sdk/src/main/java/com/paddle/ocr):

  • engine/:核心推理引擎层,包含OCREngine.kt(端到端编排)、DetectionEngine.kt(文本检测)、RecognitionEngine.kt(文本识别)、ORTSessionManager.kt(ONNX Runtime 会话与模型加载管理);
  • preprocess/:预处理层,DetPreprocessor.kt负责检测输入缩放,RecPreprocessor.kt负责识别文本行裁剪批处理;
  • postprocess/:后处理层,DBPostProcessor.kt实现 DB 检测结果的二值化与文本多边形还原,CTCDecoder.kt实现 CTC 解码,BoxSorter.kt按阅读顺序排序文本框,QuadTextCrop.kt负责按四边形裁剪文本行,另有PolygonUnclip.ktQuadGeometry.kt等几何工具;
  • model/:数据模型层,定义OCRResultOCRRunResultOCRBoxOCRError等;
  • util/:工具层,包含BitmapUtilsImageUtilsMathUtilsOpenCVUtilsYamlUtils(解析识别模型的inference.yml字符表)。

环境要求

官方文档明确的环境依赖如下:

依赖版本
Android StudioLadybug (2024.2+)
JDK17
Kotlin2.1.0
minSdk26 (Android 8.0)
ONNX Runtime1.21.1
OpenCV4.5.3

仓库中的版本目录文件 gradle/libs.versions.toml 给出了更完整的依赖清单,可作为核对基准:AGP 8.7.3、Kotlin 2.1.0、Compose BOM 2024.12.01、androidx.core-ktx 1.15.0、lifecycle-runtime 2.8.7、activity-compose 1.9.3、onnxruntime-android 1.21.1、opencv-android 4.5.3(com.quickbirdstudios)、kotlinx-coroutines-android 1.9.0、coil-compose 2.7.0,测试侧使用 androidx.test runner 1.2.0 与 JUnit 4.13.2。其中 OpenCV 采用com.quickbirdstudios:opencv封装,避免了繁琐的本地库初始化步骤,但注意在PaddleOCR.create()前仍须完成 OpenCV 初始化(见下文注意事项)。

快速开始

1. 克隆项目

git clone https://gitcode.com/paddlepaddle/PaddleOCR.git cd PaddleOCR/deploy/ppocr-android

2. 准备模型

本项目支持以下 ONNX 模型(检测与识别模型均以.tar压缩包形式提供,官方同时发布在 HuggingFace 与 BOS 渠道,可按需选择下载):

模型说明
PP-OCRv6_small检测模型PP-OCRv6_small_det_onnx/ 识别模型PP-OCRv6_small_rec_onnx
PP-OCRv6_tiny检测模型PP-OCRv6_tiny_det_onnx/ 识别模型PP-OCRv6_tiny_rec_onnx
PP-OCRv5_mobile检测模型PP-OCRv5_mobile_det_onnx/ 识别模型PP-OCRv5_mobile_rec_onnx

下载并解压后,将文件放入ppocr-sdk/src/main/assets/models/目录:

  • 检测模型:将inference.onnx放入models/det/
  • 识别模型:将inference.onnxinference.yml放入models/rec/

其中识别模型额外要求inference.yml配置文件——从源码看,它在 SDK 初始化阶段被ModelConfig.parse(context, recConfigAsset)解析,用于提取字符表(characterList)供 CTC 解码使用(见 OCREngine.kt 与 RecognitionEngine.kt 的构造函数)。因此只放入 ONNX 权重文件、缺少inference.yml时识别阶段将无法正确解码。

3. 编译运行

# 编译 Debug APK ./gradlew :app:assembleDebug # 安装到设备 ./gradlew :app:installDebug

或使用 Android Studio 直接打开deploy/ppocr-android目录运行。若本机 JDK 版本不匹配,可通过JAVA_HOME环境变量指定 JDK 17。

4. 体验 Demo

  1. 打开 "PP-OCRv6 Demo" 应用;
  2. 等待模型加载完成;
  3. 点击 "Select from Gallery" 选择图片;
  4. 查看识别结果和耗时统计。

Demo 端到端 UI 位于 app/src/main/java/com/paddle/ocr/demo,其中OCRApplication.kt负责应用启动时初始化 SDK,MainActivity.ktui/目录(HomeScreen.ktImagePicker.ktResultList.ktLoadingOverlay.ktTimingBar.ktErrorDialog.kt等)构成了基于 Compose 的完整交互界面,OCRViewModel.kt以 MVVM 方式封装识别状态。

SDK 集成:两种接入方式

方式一:源码依赖

  1. ppocr-sdk/复制到项目根目录;

  2. settings.gradle.kts添加模块:

    include(":ppocr-sdk")
  3. 在 App 模块build.gradle.kts添加依赖:

    implementation(project(":ppocr-sdk"))

方式二:AAR 依赖

# 构建 AAR ./gradlew :ppocr-sdk:assembleRelease

AAR 输出:ppocr-sdk/build/outputs/aar/ppocr-sdk-release.aar

将 AAR 放入 App 模块的libs/目录,并在build.gradle.kts中添加:

dependencies { implementation(files("libs/ppocr-sdk-release.aar")) // AAR 不传递依赖,需手动添加 implementation("com.microsoft.onnxruntime:onnxruntime-android:1.21.1") implementation("com.quickbirdstudios:opencv:4.5.3") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.9.0") }

注意 AAR 默认不传递传递依赖,因此 ONNX Runtime、OpenCV、协程这三个 SDK 的运行时依赖必须在宿主 App 中显式声明,版本与 gradle/libs.versions.toml 保持一致(onnxruntime 1.21.1、opencv 4.5.3、coroutines 1.9.0)。

API 参考:公开调用方式

创建实例

// 默认配置 val ocr = PaddleOCR.create(context) // 自定义配置 val ocr = PaddleOCR.create( context = context, config = PaddleOCRConfig( detThresh = 0.3f, detBoxThresh = 0.6f, recScoreThresh = 0.0f, recBatchSize = 1, ), engineConfig = EngineConfig(numThreads = 4), detModelAssetPath = "models/det/inference.onnx", recModelAssetPath = "models/rec/inference.onnx", recConfigAssetPath = "models/rec/inference.yml", )

从 PaddleOCR.kt 源码可以看到,create()suspend函数,内部通过withContext(Dispatchers.IO)在 IO 线程完成OCREngine构建(含 ONNX 模型加载与 YAML 解析),因此必须在协程中调用,且模型加载耗时可通过ocr.coldLoadTimeMs属性获取。EngineConfig目前仅暴露numThreads一个字段,默认 4,对应 ONNX Runtime 的线程数配置(见 EngineConfig.kt)。

执行 OCR

// 传入 Bitmap val result = ocr.recognize(bitmap) // 传入图片字节数据(推荐,与 Python 流程一致) val result = ocr.recognize(imageBytes) // 读取结果 result.results.forEach { item -> println("文本: ${item.text}, 置信度: ${item.confidence}") println("坐标: ${item.box.points}") } println("检测: ${result.detectionTimeMs}ms, 识别: ${result.recognitionTimeMs}ms")

recognize()同样为suspend函数。两种重载的差异在 OCREngine.kt 中体现得很清楚:Bitmap重载通过BitmapUtils.bitmapToBGRMat转成 BGR 的 OpenCVMat;字节数组重载则调用BitmapUtils.imdecodeBGR解码,并在解码结果为空(Mat.empty())时抛出OCRError.InvalidImage。字节数组方式与 Python 端cv2.imread的流程一致,官方推荐在流式或文件读取场景下使用。

释放资源

ocr.release()

release()内部调用engine.release(),最终释放 ORT 会话等底层资源(见 OCREngine.kt),在页面销毁等场景务必调用,避免内存泄漏。

配置参数

PaddleOCRConfig全部字段及其默认值如下(与 PaddleOCRConfig.kt 完全一致):

data class PaddleOCRConfig( val detImgMode: String = "BGR", // 输入色彩模式 val detLimitSideLen: Int = 64, // 检测侧边长限制 val detLimitType: String = "min", // 限制策略 val detMaxSideLimit: Int = 4000, // 最长边上限 val detThresh: Float = 0.3f, // 二值化阈值 val detBoxThresh: Float = 0.6f, // 检测框置信度阈值 val detUnclipRatio: Float = 1.5f, // 检测框扩展比例 val detMaxCandidates: Int = 3000, // 最大候选框数 val detUseDilation: Boolean = false, // 是否膨胀 val detScoreMode: String = "fast", // 打分模式 val detBoxType: String = "quad", // 检测框类型 val recScoreThresh: Float = 0.0f, // 识别置信度阈值 val recBatchSize: Int = 1, // 识别批大小 )

这些参数在源码中的实际消费路径如下:

  • 检测相关参数在 DetectionEngine.kt 中被完整使用:detLimitSideLendetLimitTypedetMaxSideLimitdetImgMode传入DetPreprocessor.preprocess控制输入缩放策略(限制最长边、保持比例);detThreshdetBoxThreshdetUnclipRatiodetMaxCandidatesdetUseDilationdetScoreModedetBoxType则全部透传给DBPostProcessor.process,与 PP-OCR Python 版 DB 后处理的语义一一对应;
  • 识别相关参数在 OCREngine.kt 中生效:recBatchSizecoerceAtLeast(1)保证最小为 1)控制文本行裁剪的批大小,recScoreThresh用于过滤低置信度结果(confidence >= recScoreThresh才进入输出列表)。

结果模型

data class OCRRunResult( val results: List<OCRResult>, // 识别结果列表 val detectionTimeMs: Long, // 检测耗时 val recognitionTimeMs: Long, // 识别耗时 val totalTimeMs: Long, // 总耗时 val lineCount: Int, // 识别行数 // 详细计时... ) data class OCRResult( val box: OCRBox, // 检测框坐标 val text: String, // 识别文本 val confidence: Float, // 置信度 )

除文档列出的字段外,对照 PaddleOCR.kt 的映射代码可知,OCRRunResult还携带了更细粒度的性能数据:detPreprocessMsdetInferenceMsdetPostprocessMsrecPreprocessMsrecInferenceMsrecPostprocessMspipelineOverheadMscoldLoadTimeMs,以及detInputShaperecInputShapes(实际推理输入张量形状)和perLineRecMs(单行识别耗时,仅在recBatchSize == 1时填充)。这些字段正是性能测试与耗时分析的数据来源。

源码级原理:端到端识别流水线

从 OCREngine.kt 可以完整还原一次recognize()的内部流程:

  1. 文本检测detectionEngine.detect(srcMat)依次执行——DetPreprocessor.preprocess(限长缩放 + BGR 归一化)→ortManager.runDetection(ONNX Runtime 推理)→DBPostProcessor.process(二值化、外接多边形还原、按detBoxType输出四边形框)。若检测框为空,直接返回空结果(识别耗时为 0,检测各阶段耗时照常上报);
  2. 阅读顺序排序BoxSorter.sortInReadingOrder(boxes)按从上到下、从左到右的阅读顺序对检测框排序,保证输出文本行顺序与人类阅读习惯一致;
  3. 批量裁剪识别:按recBatchSize分批,对每个检测框调用QuadTextCrop.crop做透视裁剪,裁剪失败的框(宽或高为 0)会被跳过;随后recognitionEngine.recognize(batchCrops)RecPreprocessor.preprocessBatchortManager.runRecognitionCTCDecoder.decode(基于 YAML 解析出的字符表做 CTC 解码),得到(text, confidence)对,经recScoreThresh过滤后写入结果列表;
  4. 计时汇总totalElapsed - detResult.timeMs - totalRecMs计算流水线开销(含排序与裁剪时间),与各阶段耗时一起封装进OCRRunResult

识别引擎的批处理能力(RecognitionEngine.kt)使得多行文本场景可以单次 ORT 调用完成整批识别,显著降低推理开销;测试用例可参考 OCRBenchmarkTest.kt(testLatencyBenchmark),其使用 android_ocr_benchmark_reference.png 作为基准输入图,通过 instrumentation 参数注入预热次数与迭代次数。

性能测试:自动化基准脚本

项目提供一键式性能测试脚本 run_benchmark.sh:

# 运行 benchmark(10次测试,3次预热) ./run_benchmark.sh 10 3

脚本行为拆解(与文档说明一致,并对照源码脚本确认):默认参数为 50 次迭代、30 次预热;脚本先adb logcat -c清空日志,再通过 Gradle 的connectedAndroidTest以 instrumentation 参数class=com.paddle.ocr.benchmark.OCRBenchmarkTest#testLatencyBenchmarkwarmupiterations驱动真机/模拟器上的基准测试,最后用adb logcat -d -s System.out:I | grep "OCRBenchmark"过滤出测试输出。

文档给出的典型输出示例:

╔═════════════════════════════════════════════════════════════════════════╗ ║ PP-OCRv6 Speed Benchmark Results ║ ╠═════════════════════════════════════════════════════════════════════════╣ ║ Device: GM1900 | OS: Android 9 | Lines: 5 ║ ║ Cold load: 158ms | Warmup: 3 | Measured: 10 ║ ╠═════════════════════════════════════════════════════════════════════════╣ +-----------------------------+----------+----------+----------+----------+ | Stage | Mean ms | Stdev | P90 | Min ms| +-----------------------------+----------+----------+----------+----------+ | Total pipeline | 420.40 | 6.37 | 427 | 413 | +-----------------------------+----------+----------+----------+----------+ | Detection (total) | 348.70 | 4.67 | 356 | 343 | | Preprocess | 33.30 | 2.90 | 36 | 28 | | Inference | 311.00 | 2.93 | 315 | 304 | | Postprocess | 4.40 | 0.49 | 5 | 4 | | Recognition (total) | 66.20 | 3.16 | 68 | 64 | | Preprocess | 3.00 | 0.89 | 4 | 2 | | Inference | 60.60 | 3.14 | 63 | 58 | | Postprocess | 2.60 | 0.92 | 4 | 1 | | Pipeline overhead | 5.50 | 0.50 | 6 | 5 | +-----------------------------+----------+----------+----------+----------+ ╚═════════════════════════════════════════════════════════════════════════╝

从输出可以直观看到:单帧端到端约 420ms,其中检测推理(约 311ms)是主要瓶颈,识别部分约 66ms,流水线开销约 5.5ms。这一细粒度计时的实现依据即上一节所述的OCRRunResult分段耗时字段(detInferenceMsrecInferenceMs等),开发者可以据此定位优化方向——例如调整EngineConfig(numThreads)或更换 PP-OCRv6_tiny 模型以压缩检测推理时间。需要注意的是,示例数据来自特定测试设备(GM1900 / Android 9),实际耗时随设备算力、模型规格与图片内容(文本行数)不同而变化,应以本机实测为准。

注意事项与最佳实践

官方文档明确强调以下四点,结合源码可以进一步给出实操建议:

  1. OpenCV 初始化:调用PaddleOCR.create()前需先调用OpenCVUtils.init(context)(位于 OpenCVUtils.kt),否则后续图像转Mat、透视裁剪等操作会失败;
  2. 协程调用create()recognize()都是suspend函数,需在协程中调用;SDK 内部已将重活调度到Dispatchers.IO,因此 UI 线程只需发起协程即可,无需额外切线程;
  3. 内存管理:不再使用时调用release()释放资源,同时 SDK 内部对临时Mat采用try/finally确保释放(如 OCREngine.kt 的runWithOwnedMat),第三方集成时勿重复持有 Bitmap 引用;
  4. 混淆规则:参考 ppocr-sdk/proguard-rules.pro,在开启混淆的 Release 构建中需保留 ONNX Runtime 与 OpenCV 相关的类与 JNI 方法,否则运行时可能抛出UnsatisfiedLinkError或类缺失异常。

另外,若需在 Release 包中内置模型,应将模型文件放置于ppocr-sdk/src/main/assets/models/并确认打包进 AAR;若模型体积过大,也可考虑运行时从外部存储或网络加载,此时需自行实现 assets 路径以外的模型读取逻辑(当前 SDK 公开 API 默认从 assets 读取)。

总结

PaddleOCR 的 Android 部署方案通过 ONNX Runtime 将 PP-OCRv6 的检测与识别能力完整迁移到移动端,以 SDK/Demo 分离的架构兼顾了开箱即用与二次集成。本文从工程结构、环境配置、模型准备、构建运行、SDK 集成、公开 API、源码级流水线原理到性能基准测试,完整覆盖了官方部署文档的全部要点,并逐一对照 ppocr-sdk 源码验证了配置参数的消费路径与端到端执行流程。开发者可以直接基于 deploy/ppocr-android 目录开始实践,更多跨平台部署方案(iOS、Web 等)可参考 cross_platform 部署文档目录。

【免费下载链接】PaddleOCR飞桨多语言OCR工具包(实用超轻量OCR系统,支持80+种语言识别,提供数据标注与合成工具,支持服务器、移动端、嵌入式及IoT设备端的训练与部署) Awesome multilingual OCR toolkits based on PaddlePaddle (practical ultra lightweight OCR system, support 80+ languages recognition, provide data annotation and synthesis tools, support training and deployment among server, mobile, embedded and IoT devices)项目地址: https://gitcode.com/paddlepaddle/PaddleOCR

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询