Lucent's Blog

Lucent's Blog

当时明月在 曾照彩云归


人生不相见,动如参与商。


Java 首款 PP-OCR 原生库:零 Python 依赖,Maven 引入即用

写在前面:Java 开发者的 OCR 之痛

做 Java 后端的朋友,应该都有过这样的经历:

项目里要接 OCR(光学字符识别,Optical Character Recognition),第一反应是调云服务,但数据要出网,合规过不去;
想本地部署,翻遍 GitHub,教程清一色 Python + PaddleOCR,Java 生态不是没有库,但要么识别质量堪忧,要么依赖一堆本地动态库;
好不容易跑通,推理结果和 Python 版对不上,同一张图识别结果不一样,排查到怀疑人生。
难道 Java 就只能当「调用方」吗?

今天给大家介绍一个刚开源上线的 Java 原生 OCR 库——mica-ppocr,把 PP-OCRv6 完整搬到了 JVM 上。

什么是 mica-ppocr?

mica-ppocr 是 PP-OCRv6 文字检测 + 识别的 Java 17 实现,由 mica(如梦技术)社区出品。它有两个关键词:

  • 纯 ONNX Runtime 推理:零 PaddlePaddle 依赖,不用装 Python,不用装 Paddle 全家桶;
  • bit-exact 移植:逐行移植自 AIwork4me/ppocrv6_onnx 的单文件 Python 参考实现,预处理 / 后处理(DB 后处理、CTC 解码、pyclipper 等价的多边形 unclip)完整复现,默认 CPU 单线程,保证与 Python 版逐位一致

核心特性一览

  • 零 Python 依赖:Maven 引入即用,OpenCV、ONNX Runtime 原生库自动拉取,Windows / Linux / macOS 开箱即用;
  • bit-exact 复现:与 Python 参考实现逐位一致,结果可预期、可对拍;
  • 三档模型可选:tiny / small / medium,从轻量到高精度自由切换;
  • Spring Boot Starter:一行配置注入引擎,开箱即用;
  • 核心零框架依赖:core 模块不依赖 Spring,任何 Java 项目都能直接用;
  • Apache 2.0 开源:商用友好,放心使用。

三档模型,按需选择

mica-ppocr 内置了 PP-OCRv6 官方 ONNX 模型(det + rec),放在 models/ppocr-v6/{tier}/ 目录即可按需选用:

档次
det 模型
rec 模型
字符表
定位
tiny
1.7 MB
4.3 MB
约 2855 字符
轻量优先,速度快,精度一般
small
9.4 MB
20.2 MB
约 2855 字符
速度与精度均衡,推荐默认
medium
59.2 MB
73.0 MB
约 7180 字符
精度优先,覆盖更全字符集

不同场景怎么选?给大家一个参考:

  • 移动端 / 嵌入式设备:选 tiny,模型体积小、内存占用低,适合资源受限环境;
  • 实时视频流 / 高并发调用:选 tiny,推理延迟低,吞吐高;
  • 通用文档识别、日常开发调试:选 small,各项指标均衡,覆盖大多数场景;
  • 复杂版面 / 低质量图片:选 medium,检测与识别精度最高;
  • 生僻字及全字符集场景:选 medium,字符表约 7180 个,覆盖面更广。

快速上手:三步跑通 OCR

引入依赖:

<dependency>
    <groupId>net.dreamlu.mica.ai</groupId>
    <artifactId>mica-ppocr-core</artifactId>
    <version>${mica.ppocr.version}</version>
</dependency>

核心 API 是 net.dreamlu.mica.ai.ppocr.engine.PPOcrV6Engine,实现 Closeable,推荐用 try-with-resources:

import net.dreamlu.mica.ai.ppocr.config.PPOcrV6Config;
import net.dreamlu.mica.ai.ppocr.config.PPOcrV6Result;
import net.dreamlu.mica.ai.ppocr.engine.PPOcrV6Engine;
import org.opencv.core.Mat;
import org.opencv.imgcodecs.Imgcodecs;
import nu.pattern.OpenCV;
 
import java.util.List;
 
public class Demo {
    public static void main(String[] args) {
        OpenCV.loadShared();
        Mat img = Imgcodecs.imread("test.png");
        PPOcrV6Config config = PPOcrV6Config.builder()
            .detModelPath("models/ppocr-v6/tiny/det.onnx")
            .recModelPath("models/ppocr-v6/tiny/rec.onnx")
            .recCharDictPath("models/ppocr-v6/tiny/dict.txt")
            .build();
        try (PPOcrV6Engine engine = new PPOcrV6Engine(config)) {
            List<PPOcrV6Result> results = engine.run(img);
            for (PPOcrV6Result r : results) {
                System.out.printf("%s  (%.3f)%n", r.text(), r.score());
            }
        }
    }
}

引擎默认 CPU 单线程(intraOp = interOp = 1),保证跨平台输出确定。想要调参也方便:DB 阈值、识别批大小、ORT 线程数、GPU 加速等,全部通过 PPOcrV6Config 的 Builder 配置。

Spring Boot 项目:配置即用

如果项目是 Spring Boot 3.x,更简单,直接引入 Starter:

<dependency>
    <groupId>net.dreamlu.mica.ai</groupId>
    <artifactId>mica-ppocr-spring-boot-starter</artifactId>
    <version>${mica.ppocr.version}</version>
</dependency>

application.yml 里配置模型路径:

mica:
  ai:
    ppocr:
      enabled: true# 设为 false 关闭 Starter
      det-model-path: models/ppocr-v6/tiny/det.onnx
      rec-model-path: models/ppocr-v6/tiny/rec.onnx
      rec-char-dict-path: models/ppocr-v6/tiny/dict.txt

然后直接注入引擎使用:

@Service
public class OcrService {
    private final PPOcrV6Engine engine;
    public OcrService(PPOcrV6Engine engine) { this.engine = engine; }
 
    public List<PPOcrV6Result> recognize(Mat image) {
        return engine.run(image);
    }
}

更贴心的是,Starter 提供了 PPOCRPropertiesCustomizer SPI,业务方可以在配置文件之外做旁路覆盖——比如按环境变量切换模型档次:

@Bean
PPOCRPropertiesCustomizer tierEnvCustomizer() {
    return builder -> {
        String tier = System.getenv("PPOCR_TIER");
        if (tier != null) {
            builder.detModelPath("models/ppocr-v6/" + tier + "/det.onnx")
                   .recModelPath("models/ppocr-v6/" + tier + "/rec.onnx")
                   .recCharDictPath("models/ppocr-v6/" + tier + "/dict.txt");
        }
    };
}

从配置中心、环境变量、甚至是 Nacos 里动态下发模型路径,都不是问题。

架构一览:检测 → 排序 → 裁剪 → 识别

mica-ppocr 完整复现了 PP-OCRv6 的标准流水线,模块划分清晰:

mica-ppocr-core/                                 # 核心引擎,零 Spring 依赖
├── engine/PPOcrV6Engine.java                    # 唯一公开入口(Closeable)
├── config/PPOcrV6Config.java                    # Builder 配置
├── config/PPOcrV6Result.java                    # record (text, score, box)
├── preprocessor/                                # 检测 / 识别预处理
├── postprocessor/                               # DB 后处理 / CTC 解码
└── utils/                                       # BoxUtil / CropUtil / Offset / NdArrayUtils
mica-ppocr-spring-boot-starter/                  # Spring Boot 自动配置
    ├── PPOCRAutoConfiguration.java
    ├── PPOCRProperties.java
    └── OpenCVNativeLoader.java

整个流水线是 detect → sort boxes → crop → recognize

  1. DetectionPreprocessor 按限边长约束缩放、归一化、HWC → NCHW;
  2. DbPostProcessor 对 DB 二值图做轮廓提取,得到文字框;
  3. BoxUtil 按阅读顺序排序四边形框;
  4. CropUtil 做透视变换裁剪,非法裁剪返回 null 自动跳过;
  5. RecognitionPreprocessor 批量缩放、补齐到统一宽度;
  6. CtcLabelDecoder 加载字符表,CTC 贪心解码输出文本 + 置信度。

值得一提的移植细节:Python 里的 numpy 对应 NdArrayUtilspyclipper 用 JTS BufferOp 等价实现(unclip 差异 < 1px),cv2.minAreaRect 对应 Imgproc.minAreaRectnp.rot90 对应 Core.ROTATE_90_COUNTERCLOCKWISE。这些底层组件的打磨,正是「bit-exact」的保障。

实际效果:行驶证结构化解析

以 test_images/1.png 为例(模型档次 tiny),识别结果可视化如下:

输入图片
识别结果可视化
图片
图片

注:测试的行驶证来源于网络,如有侵权,请联系删除。

识别结果:

--- 行驶证结构化解析 ---
plateNo:      鲁GH9P12
owner:        盛瑞传动股份有限公司
vehicleType:  小型普通客车
vin:          LJ8F3D5H910700001
issueDate: 2018-02-24

适合哪些场景?

  • 证照识别:行驶证、身份证、营业执照等结构化字段提取;
  • 票据 / 单据录入:报销单、快递单、发票信息自动录入;
  • 文档数字化:扫描件、拍照件批量转文字;
  • 合规本地化部署:数据不出内网,无需调用外部云 API;
  • Java 技术栈统一:OCR 能力直接集成进现有 Spring Boot 服务,不再单独维护 Python 服务。

结语:Java 生态的 OCR 拼图,补上了

mica-ppocr 的价值,在于把「Python 才能跑的高质量 OCR」变成了「Maven 依赖一句话」的事:零 Python 依赖、bit-exact 复现、三档模型、Spring Boot Starter,还有 Apache 2.0 的宽松许可。

如果你正在为 Java 项目的文字识别发愁,不妨 clone 下来试试,模型放好、引擎一 new,剩下的交给 mica-ppocr。

  • Gitee: https://gitee.com/dreamlu/mica-ppocr
  • GitHub: https://github.com/lets-mica/mica-ppocr
  • 许可证:Apache License 2.0

欢迎 Star、Issue、PR,一起把 Java 生态的 OCR 体验做得更好。