ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

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

PaddleOCR Android 端到端部署实战:基于 ONNX Runtime 的 PP-OCRv6 SDK 集成指南 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 SDKAndroid 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/ocrengine/核心推理引擎层包含OCREngine.kt端到端编排、DetectionEngine.kt文本检测、RecognitionEngine.kt文本识别、ORTSessionManager.ktONNX Runtime 会话与模型加载管理preprocess/预处理层DetPreprocessor.kt负责检测输入缩放RecPreprocessor.kt负责识别文本行裁剪批处理postprocess/后处理层DBPostProcessor.kt实现 DB 检测结果的二值化与文本多边形还原CTCDecoder.kt实现 CTC 解码BoxSorter.kt按阅读顺序排序文本框QuadTextCrop.kt负责按四边形裁剪文本行另有PolygonUnclip.kt、QuadGeometry.kt等几何工具model/数据模型层定义OCRResult、OCRRunResult、OCRBox、OCRError等util/工具层包含BitmapUtils、ImageUtils、MathUtils、OpenCVUtils、YamlUtils解析识别模型的inference.yml字符表。环境要求官方文档明确的环境依赖如下依赖版本Android StudioLadybug (2024.2)JDK17Kotlin2.1.0minSdk26 (Android 8.0)ONNX Runtime1.21.1OpenCV4.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.3com.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-android2. 准备模型本项目支持以下 ONNX 模型检测与识别模型均以.tar压缩包形式提供官方同时发布在 HuggingFace 与 BOS 渠道可按需选择下载模型说明PP-OCRv6_small检测模型PP-OCRv6_small_det_onnx/ 识别模型PP-OCRv6_small_rec_onnxPP-OCRv6_tiny检测模型PP-OCRv6_tiny_det_onnx/ 识别模型PP-OCRv6_tiny_rec_onnxPP-OCRv5_mobile检测模型PP-OCRv5_mobile_det_onnx/ 识别模型PP-OCRv5_mobile_rec_onnx下载并解压后将文件放入ppocr-sdk/src/main/assets/models/目录检测模型将inference.onnx放入models/det/识别模型将inference.onnx和inference.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打开 PP-OCRv6 Demo 应用等待模型加载完成点击 Select from Gallery 选择图片查看识别结果和耗时统计。Demo 端到端 UI 位于 app/src/main/java/com/paddle/ocr/demo其中OCRApplication.kt负责应用启动时初始化 SDKMainActivity.kt与ui/目录HomeScreen.kt、ImagePicker.kt、ResultList.kt、LoadingOverlay.kt、TimingBar.kt、ErrorDialog.kt等构成了基于 Compose 的完整交互界面OCRViewModel.kt以 MVVM 方式封装识别状态。SDK 集成两种接入方式方式一源码依赖将ppocr-sdk/复制到项目根目录在settings.gradle.kts添加模块include(:ppocr-sdk)在 App 模块build.gradle.kts添加依赖implementation(project(:ppocr-sdk))方式二AAR 依赖# 构建 AAR ./gradlew :ppocr-sdk:assembleReleaseAAR 输出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 中被完整使用detLimitSideLen、detLimitType、detMaxSideLimit、detImgMode传入DetPreprocessor.preprocess控制输入缩放策略限制最长边、保持比例detThresh、detBoxThresh、detUnclipRatio、detMaxCandidates、detUseDilation、detScoreMode、detBoxType则全部透传给DBPostProcessor.process与 PP-OCR Python 版 DB 后处理的语义一一对应识别相关参数在 OCREngine.kt 中生效recBatchSizecoerceAtLeast(1)保证最小为 1控制文本行裁剪的批大小recScoreThresh用于过滤低置信度结果confidence recScoreThresh才进入输出列表。结果模型data class OCRRunResult( val results: ListOCRResult, // 识别结果列表 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还携带了更细粒度的性能数据detPreprocessMs、detInferenceMs、detPostprocessMs、recPreprocessMs、recInferenceMs、recPostprocessMs、pipelineOverheadMs、coldLoadTimeMs以及detInputShape、recInputShapes实际推理输入张量形状和perLineRecMs单行识别耗时仅在recBatchSize 1时填充。这些字段正是性能测试与耗时分析的数据来源。源码级原理端到端识别流水线从 OCREngine.kt 可以完整还原一次recognize()的内部流程文本检测detectionEngine.detect(srcMat)依次执行——DetPreprocessor.preprocess限长缩放 BGR 归一化→ortManager.runDetectionONNX Runtime 推理→DBPostProcessor.process二值化、外接多边形还原、按detBoxType输出四边形框。若检测框为空直接返回空结果识别耗时为 0检测各阶段耗时照常上报阅读顺序排序BoxSorter.sortInReadingOrder(boxes)按从上到下、从左到右的阅读顺序对检测框排序保证输出文本行顺序与人类阅读习惯一致批量裁剪识别按recBatchSize分批对每个检测框调用QuadTextCrop.crop做透视裁剪裁剪失败的框宽或高为 0会被跳过随后recognitionEngine.recognize(batchCrops)走RecPreprocessor.preprocessBatch→ortManager.runRecognition→CTCDecoder.decode基于 YAML 解析出的字符表做 CTC 解码得到(text, confidence)对经recScoreThresh过滤后写入结果列表计时汇总totalElapsed - detResult.timeMs - totalRecMs计算流水线开销含排序与裁剪时间与各阶段耗时一起封装进OCRRunResult。识别引擎的批处理能力RecognitionEngine.kt使得多行文本场景可以单次 ORT 调用完成整批识别显著降低推理开销测试用例可参考 OCRBenchmarkTest.kttestLatencyBenchmark其使用 android_ocr_benchmark_reference.png 作为基准输入图通过 instrumentation 参数注入预热次数与迭代次数。性能测试自动化基准脚本项目提供一键式性能测试脚本 run_benchmark.sh# 运行 benchmark10次测试3次预热 ./run_benchmark.sh 10 3脚本行为拆解与文档说明一致并对照源码脚本确认默认参数为 50 次迭代、30 次预热脚本先adb logcat -c清空日志再通过 Gradle 的connectedAndroidTest以 instrumentation 参数classcom.paddle.ocr.benchmark.OCRBenchmarkTest#testLatencyBenchmark、warmup、iterations驱动真机/模拟器上的基准测试最后用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分段耗时字段detInferenceMs、recInferenceMs等开发者可以据此定位优化方向——例如调整EngineConfig(numThreads)或更换 PP-OCRv6_tiny 模型以压缩检测推理时间。需要注意的是示例数据来自特定测试设备GM1900 / Android 9实际耗时随设备算力、模型规格与图片内容文本行数不同而变化应以本机实测为准。注意事项与最佳实践官方文档明确强调以下四点结合源码可以进一步给出实操建议OpenCV 初始化调用PaddleOCR.create()前需先调用OpenCVUtils.init(context)位于 OpenCVUtils.kt否则后续图像转Mat、透视裁剪等操作会失败协程调用create()和recognize()都是suspend函数需在协程中调用SDK 内部已将重活调度到Dispatchers.IO因此 UI 线程只需发起协程即可无需额外切线程内存管理不再使用时调用release()释放资源同时 SDK 内部对临时Mat采用try/finally确保释放如 OCREngine.kt 的runWithOwnedMat第三方集成时勿重复持有 Bitmap 引用混淆规则参考 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),仅供参考
返回列表