---
url: https://www.dreamlu.net/blog/2026-11-14-mica-ppocr-1.2.6-release.md
description: >-
  Java 后端做
  OCR，比「谁的识别率高」更该先问三件事：给的是散落文字框还是能入库的业务字段、换台机器结果是否一致、装它要拖多少依赖。mica-ppocr 1.2.6
  把这三件事做实了 —— 10 类证件直出字段、输出确定可复现、运行时只要 2 个 jar，纯 CPU 进百毫秒级，JDK 8 起步。
---

> 纯 ONNX Runtime　·　零 PaddlePaddle　·　Java 8 起　·　10 类证件票据直出字段　·　输出确定可复现

先贴一段线上日志，这是最近的真实记录：

```
"POST /api/ocr/pdd HTTP/1.1" 200 ... req_time=0.312 upstream_time=0.181
"POST /api/ocr/pdd HTTP/1.1" 200 ... req_time=0.271 upstream_time=0.183
"POST /api/ocr/pdd HTTP/1.1" 200 ... req_time=0.265 upstream_time=0.184
```

`#小程序:多多福袋帮` 生产环境的 OCR 接口，腾讯轻量云 4 核、Linux，**纯 CPU 推理，没有 GPU**。近 2 小时 25 次请求，**全部 200**。OCR 链路本身 p50 200 ms，上面这三行是最快的三次（181 / 183 / 184 ms）；算上客户端传输和网关，端到端 p50 **290 ms**。

这个接口背后没有云 OCR、没有 Python 服务、没有 GPU —— 4 核轻量云的纯 CPU 推理，就是一个 Spring Boot 应用加一个 jar。**而这个 jar，JDK 8 就能跑。**

但今天不想推销这个接口。真正想聊的是：**Java 后端做 OCR，有三个问题比「谁的识别率高」重要得多**，而市面上大多数方案在这三件事上是含糊的。

***

## 一、它给你的是一堆文字框，还是能直接入库的字段？

这是第一个问题，也是最耗时间的那个。

OCR 的原始输出是散落的文字框和文本。然后呢？「姓名」后面那个值在哪个框里？标签被 OCR 拆成「姓」和「名」两半怎么办？两个字段串行到同一行怎么切？换一种证件版式，整套规则重写一遍。

![散落的文字框 vs 直接可用的业务字段](/blog/ppocr-1.2.6-fig-fields.webp)

mica-ppocr 的做法是**把这一步内置**。10 类证件票据 —— 行驶证、身份证、银行卡、驾驶证、营业执照、发票、火车票、出租车票、户口本、拼多多福袋 —— 直接吐出业务字段：

```java
@Autowired
private PPOcrTemplate ppocr;

@PostMapping("/ocr/vehicle")
public VehicleLicenseResult vehicle(@RequestParam MultipartFile file) throws IOException {
    return ppocr.vehicleLicense().parse(file.getBytes());
}
```

**1.2.6 这一版，10 个解析器全部支持 `fieldBoxes` 了。** 以前身份证、驾驶证、银行卡这三家是没有的，你拿到结果想在前端高亮「哪个框是车牌号」，得自己按文本二次匹配。现在字段值和坐标一起给你，画框是前端一行循环的事。

还有几个细节更值得说：

**它会告诉你这个值从哪来、能不能信。** 字段来源分五档 —— 标签命中、正则兜底、推导、回填、缺失，一目了然。校验位三态判定：PASS / FAIL / UNCHECKABLE。校验不过时置信度直接归零 —— 但**字段值仍然保留**，丢值对下游更糟。同时给 `needsReview` 和 `reviewReasons`，该不该人工复核显式交给你。

**它不会把长数字串修成日期。** 日期归一化以前会把 18 位身份证号「修复」成 `1101-05-19` 这种恰好合法的日期，还能通过形态校验拿到满置信度。现在只有「恰好 8 位数字」或「含日期分隔符」的文本才进修复流程。

还有一类坑叫「值明明在，就是取不出来」：数电票那种数值列右对齐的版面，明细金额 / 税额以前整列漏掉；银行卡「VALID THRU 12/25」被合成一框时有效期整条静默丢失。这些 1.2.6 都修了。

**新单据怎么办？** 写一份声明式 schema —— 字段名、标签、正则、校验规则、归一化，声明完就能抽，不用再实现解析器类。

***

## 二、换台服务器跑，结果还一样吗？

第二个问题，也是 Java OCR 最常被吐槽的地方：「本地能跑，CI 上跑不出」。

mica-ppocr 的答案是**确定性**：同一份输入，在任何机器、任何线程数下跑出来，结果完全一样。这不是调参调出来的，是几个决定堆出来的：

**默认 CPU 单线程**（`intraOp = interOp = 1`）、**默认不开加速器** —— 绕开 GPU / CPU 的浮点差异，也绕开线程调度顺序对累加顺序的影响。

而且不开加速器不代表慢 —— 开头那台 4 核轻量云，**纯 CPU 就跑进了百毫秒级**。当然要 GPU 也行（换 `onnxruntime_gpu` + `preferAccelerator(true)`），但先把 CPU 这条路的确定性拿到手，通常比追 GPU 吞吐更划算。

**1.2.6 把检测框坐标的整数化去掉了。** 以前坐标是取整的近似值，现在小数坐标一路贯通到裁剪边界 —— 约 98% 的框位移 ≤3px。做像素级判断的下游，能感觉到这个差异。

**PDF 双通道的坐标系也统一了。** 同一份 PDF 里，「文本层抽出来的框」和「渲染后 OCR 的框」以前是整体错位的（一个按 point，一个按像素），1.2.6 把它们统一到渲染图像素坐标。

每个改动都有回归测试钉住 —— 44 张样图 × 10 个解析器比对，**没有字段变成 null**，6 个字段有单字抖动。

***

## 三、装它要拖进来多少东西？

第三个问题：部署账单。这个可以量化 —— **mica-ppocr-core 的运行时依赖只有两个 jar**：

![纯 CPU、4 核轻量云、181 ms、只有 2 个 jar](/blog/ppocr-1.2.6-fig-cpu.webp)

```text
net.dreamlu:mica-ppocr-core:jar:1.2.6
+- com.microsoft.onnxruntime:onnxruntime:jar:1.18.0:compile
\- org.openpnp:opencv:jar:4.9.0-0:compile
```

`mica-ppocr-structured` 只依赖 core，**不再引入任何第三方运行时依赖**。`pdfbox`（连同 pdfbox-io / fontbox / commons-logging）标了 optional，只做图片 OCR 的项目不会被它传染。

1.2.6 还顺手把 **JTS 移除了** —— 多边形偏移（unclip）改成纯 Java 实现，单次调用 5.34 → 1.63 μs、堆分配 12.7 KB → 2.7 KB，检测框坐标与识别文本逐位不变。运行时第三方几何库，现在归零。

内存账单也压下来了：

* **输出张量零拷贝读取** —— 每次 OCR 的堆分配降 32%~40%、峰值存活堆降 26%~46%，识别文本与置信度逐位不变
* **模型与 PDF 不再整份进堆** —— 堆上不再出现与模型等大的数组（medium 档 rec 模型约 73 MiB）
* **解析层正则全部预编译** —— 单次正则调用快 5.4 倍，解析耗时降约 22%，堆分配降 60%~68%
* **检测最大边长默认 4000 → 1920** —— 2K~4K 图的检测耗时大幅下降

还有一条对存量项目挺重要：**JDK 8 起就能跑。** 不是 Java 11+，也不是 17 —— 源码是按 Java 8 标准库编译校验的，Spring Boot 2.5~4.x 全通吃。老项目不用为了加个 OCR 功能就把 JDK 升上去。而且整个推理在本地 —— **证件照不出本机，不按次计费**。

***

## 四、顺带说说 PDF：不该 OCR 的就别 OCR

很多方案对所有 PDF 都是「渲染成图 → 全部走 OCR」。慢，而且白白丢质量。

![PDF 双通道：文字型直接抽文本层，扫描件才渲染 + OCR，坐标统一](/blog/ppocr-1.2.6-fig-pdf.webp)

mica-ppocr 是**逐页判断**的：

* 先抽文本层，评估质量（字符数 ≥ 20、可读占比 ≥ 0.90）→ 达标就直接用文本层，**整页不跑 OCR**
* 不达标（扫描件）才渲染成位图（200 DPI 可配）→ 走完整 OCR 链路

两条通道的框最后统一到渲染图像素坐标，所以调用方拿任一页的框，都能直接对照同一张渲染图定位。

每页的结果都带 `pageIndex` 和 `viaOcr` 标记 —— 一份混合 PDF 里哪几页走了 OCR，一眼就知道。

***

## 五、什么时候别用它

选型文章不写边界就没意思了，这几条请先看完。

* **要处理 PDF 就自己加依赖** —— 显式引入 `org.apache.pdfbox:pdfbox:3.0.8`。没引入时 `run(byte[])` 收到 PDF 会抛 `IllegalStateException` 并指明要补哪个包，图片输入不受影响
* **单独引 core 的项目要自己引 slf4j-api** —— 1.2.6 把 core 的 slf4j-api 改成 `provided`，避免给下游强塞 2.0.20（跟 Spring Boot 2.7 的 logback 不兼容，会让全站日志哑掉）。走 starter / plugin 不用管
* **默认检测分辨率是 1920** —— 你如果用 `detLimitType = max` 且 `detLimitSideLen` 大于 1920，需要自己调大
* **有几处行为变更要复核** —— 检测框坐标会变；PDF 文本层 `box` 坐标整体放大 `renderDpi / 72` 倍（200 DPI 下约 2.78×），按 point 解读的代码要调整；火车票与发票的金额货币符前缀恒为半角 `¥`
* **CPU arena 与内存模式优化默认是关闭的**（v1.2.0 起，为解决动态分辨率下内存涨到 OOM）—— 只有输入分辨率固定、又追求极致吞吐时才值得开，吞吐约损 10%

***

## 六、上手其实很快

模型**已经随仓库入库**（`models/ppocr-v6/`），clone 完就能跑：

| 档次 | 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 字符 | 精度优先，覆盖更全字符集 |

原生库（ONNX Runtime / OpenCV，Windows / Linux / macOS）随 Maven 引入，不用手动装。

```xml
<dependency>
    <groupId>net.dreamlu</groupId>
    <artifactId>mica-ppocr-spring-boot-starter</artifactId>
    <version>1.2.6</version>
</dependency>
```

***

## 数据口径说明

正文里出现了两类数字，来源不同，别混着看。

**线上真实数据（绝对值，可直接引用）**

| 项 | 说明 |
|---|---|
| 来源 | nginx 访问日志，`POST /api/ocr/pdd` |
| 时间 | 2026-11-14 09:08:38 ~ 11:02:15 |
| 样本 | 25 次请求，HTTP 状态码全部 200 |
| 机器 | 腾讯轻量云 4 核，Linux |
| 负载 | 拼多多福袋图，1200×1500 |
| `req_time` | nginx 端到端（含客户端传输与网关开销），p50 **290 ms** |
| `upstream_time` | 后端 OCR 处理耗时，p50 200 ms |
| 局限 | 样本量小、单一负载、时段分散；**不代表并发吞吐能力**，仅用于说明单请求耗时水位 |

**本地 benchmark（相对值，不可当线上耗时引用）**

* 同一台机器、同一套参数的前后对比（开发机、Windows、单线程）
* 绝对值随机器与线程配置浮动，**只应引用降幅**
* 正文里「行驶证 1638 → 951 ms」「DB 后处理 10.2 → 6.8 ms」这类数字属此类

**依赖树**：由 `mvn dependency:tree -Dscope=runtime` 实测导出，非手写。

***

## 写在最后

回到开头那三个问题：

**它给的是框，还是字段？** —— 10 类证件票据直出字段，还带来源、置信度、校验位结论和坐标。
**换台机器结果还一样吗？** —— 输出确定性，检测框坐标小数贯通，换机器不飘。
**装它要拖进来多少东西？** —— 运行时 2 个 jar，无 Python 生态，JDK 8 起，纯 CPU 百毫秒级，证件照不出本机。

哪个问题是你正在头疼的，值得花五分钟看看：

* Gitee：gitee.com/dreamlu/mica-ppocr
* GitHub：github.com/lets-mica/mica-ppocr

有踩坑、或者想要某个单据的解析器，都欢迎来 Issue 里聊 —— 想听的是「你那套证件是啥版式」这种具体问题。

**你们团队选 OCR，最头疼的是哪个问题？我猜大多数人是第一个 —— 识别完那堆正则。**

***

## 相关链接

* [mica-ppocr 文档](/mica-ppocr/)：依赖坐标、配置项与 10 类解析器清单
* [完整变更记录](https://gitee.com/dreamlu/mica-ppocr/blob/master/CHANGELOG.md)
* [Gitee 仓库](https://gitee.com/dreamlu/mica-ppocr)　·　[GitHub 仓库](https://github.com/lets-mica/mica-ppocr)
* 站内相关：[mica-ppocr 1.2.4：OCR 预处理内存砍半，检测提速 2.6 倍](/blog/2026-10-25-mica-ppocr-1.2.4-release.html)
