变更总览
|
模块
|
变更
|
类型
|
|
mica-ppocr-core
|
预处理内存融合(堆 -50%、检测提速 2.6×);mica.ai.ppocr.pdf.* 接通引擎;输入校验修复
|
perf / feat / fix
|
|
mica-ppocr-structured
|
热路径分配优化;新增 detParams() 钩子;拼多多福袋类型识别
|
perf / feat
|
|
mica-ppocr-spring-boot-starter
|
总开关闸门补齐;PDF 配置默认值对齐
|
fix
|
|
mica-ppocr-solon-plugin
|
总开关闸门对齐;补注册 PdfAutoConfiguration
|
fix
|
一、预处理内存砍半,检测提速 2.6 倍
三处预处理(det / rec / doc_ori)改成「归一化结果直接写入 CHW / NCHW 输出数组」,不再 materialize 中间 HWC 数组,也不再生成 CV_32F 中间 Mat。
|
场景
|
堆分配
|
耗时
|
|
det 预处理(3000×4000 图)
|
275 MB → 137 MB(-50%)
|
110 ms → 42 ms(2.6×)
|
|
rec 预处理(50 框 × 1200px 宽)
|
79.1 MB → 39.8 MB(-50%)
|
21.1 ms → 15.9 ms(-25%)
|
|
另省约 40 MB native 内存。
|
|
|
数值一个字节都没变
uint8 → CV_32F 与 uint8 → 提升为 float 在 0~255 上逐位相同,所以「先转 float 再算」与「直接提升再算」结果一致 —— 这正是省掉 CV_32F 中间 Mat 的依据。
三个预处理测试各保留了一个 reference* 方法(旧实现的副本)做 assertArrayEquals 逐位比对。后续再做优化时,按同样模式把参照实现留在测试里 —— 那是数值真相源,不是死代码。
顺手修掉的 native 内存滞留
文档方向预处理的中心裁剪子 Mat 视图与 resize 本体原先释放顺序颠倒(先放本体、后放视图),现改为「先视图、后本体」,引用计数 2 → 1 → 0 依次归零。
写反了不会立刻报错,只是 native 缓冲滞留到 GC —— 长时间跑批处理时,这是一笔看不见的账。
二、PDF 通道配置接通了
背景
v1.2.2 引入 PDF 双通道(文本层坐标抽取 + 渲染位图 OCR)时,mica.ai.ppocr.pdf.* 只停留在配置对象上,没有传到引擎。引擎的 PDF 入口始终用 PdfOcrConfig.defaults()。
现在
PPOcrV6Config 新增 pdfOcrConfig 字段,PPOcrV6Engine 构造期取它,PDF 入口(run(byte[]) / run(Path) 嗅探到 %PDF- 时)实际消费。图片通道不受影响。
|
参数
|
默认值
|
作用
|
|
render-dpi
|
200
|
渲染通道输出 DPI。扫描件内嵌位图有原始分辨率,超过原图信息量的重采样只会放大噪声,发票 / 证件类 200~300 为宜
|
|
min-text-chars
|
20
|
文本层可用所需的最小非空白字符数,低于则判定无文本层
|
|
min-readable-ratio
|
0.90
|
文本层可读字符占比下限。缺 ToUnicode 映射的 CID 字体会抽出一批私有区字符,拉低占比
|
|
force-ocr
|
false
|
跳过文本层探测,所有页面强制走渲染 + OCR,用于竖排、页面旋转等文本层坐标不可信的版式
|
|
|
|
|
mica:
ai:
ppocr:
pdf:
enabled: true
render-dpi: 200
min-text-chars: 20
min-readable-ratio: 0.90
force-ocr: false
也可以直接用代码覆盖 —— 自定义一个 PdfOcrConfig Bean 即可(Spring @Bean / Solon @Configuration),引擎会直接采用它,无需再改 yml。
两处需要留意的行为变更
1. PdfOcrConfig Bean 现在就是引擎使用的配置,不再是只读副本。此前业务方自定义同名 Bean 会被静默忽略(容器里是自定义值、引擎仍用 yml 或默认值),现在会直接改变引擎行为。
2. pdf.enabled=false 时 Bean 仍然存在,取 PdfOcrConfig.defaults()(此前是不注册这个 Bean)。两端都容忍该 Bean 缺失(回落到 yml 派生值),不会因为排除自动配置类而启动失败。
两端默认值对齐了
v1.2.3 时 Starter 暴露的默认值是 minTextChars=10 / minReadableRatio=0.6,而引擎实际在用的是 20 / 0.90 —— 文档写 10、引擎跑 20。两端现已统一为 20 / 0.90,不配置即保持原有行为。
Solon 端此前还漏了 PdfAutoConfiguration 的注册,压根拿不到 PdfOcrConfig Bean,本次补上。
三、关掉总开关不再启动失败
背景
Spring 端的 StructuredParserAutoConfiguration 漏挂了 mica.ai.ppocr.enabled 这个闸门。
10 个解析器 Bean 都以 PPOcrV6Engine 为构造参数注入。主配置被关掉 ⇒ 引擎 Bean 不存在 ⇒ 抛 NoSuchBeanDefinitionException ⇒ 容器 refresh 直接失败。
也就是说,想用这个开关在某些环境关掉 OCR,结果应用启动失败。
现在
-
三个配置类统一挂到同一个闸门:
-
Spring:@ConditionalOnProperty(prefix = "mica.ai.ppocr", name = "enabled", havingValue = "true", matchIfMissing = true)
-
Solon:@Condition(onExpression = "${mica.ai.ppocr.enabled:true} == true")
关闭时容器里不注册任何 PP-OCR 功能 Bean(引擎 / 10 个解析器 / PPOcrTemplate / 配置对象),应用照常启动,可用于「同一套代码在部分环境不启用 OCR」的场景。
-
⚠️ 行为变更: 关闭时两端都不再留下 PdfOcrConfig Bean —— Spring 端此前会残留一个(它的 PdfAutoConfiguration 只挂在 mica.ai.ppocr.pdf.enabled 上),Solon 端此前压根没注册过 PdfAutoConfiguration。
-
例外: OpenCVNativeLoader 不受该开关约束,OpenCV 原生库仍会加载。业务方若自行使用 org.opencv.*,需知晓这一点。
四、按版面类型声明 DB 检测参数
一个容易被误判的现象
海报类版面(大字号稀疏数字 + 满屏背景水印),rec 单独跑同一张图完全正确,det 却一个框都没给。
解法:解析器自己声明检测参数
BaseStructuredParser 新增 detParams() 钩子(默认 null = 引擎默认),一站式 parse(...) 自动带上,显式传入的 DbDetParams 优先。解析器可以按自己的版面类型声明专属参数,不影响同引擎上的其它解析器。
public class MyPosterParser extends BaseStructuredParser {
@Override
protected DbDetParams detParams() {
// 放宽 boxThresh 让稀疏大字符框过关,同时收紧 unclipRatio 避免外扩把上下水印卷进来
return DbDetParams.of(0.3f, 0.4f, 1.0f);
}
// ...
}
参数顺序是 DbDetParams.of(thresh, boxThresh, unclipRatio)。已落地在 PddLuckyBagParser.DET_PARAMS(0.3f / 0.4f / 1.0f)。
但别照抄这个参数
证件 / 票据类版面沿用引擎默认(min/64 + 0.6/1.5)。
五、拼多多福袋类型识别
PddLuckyBagResult 新增 getType(),返回 PddLuckyBagType。两类分享图版式几乎一致(搜索邀请码 → 组队双方必得 → 大字号邀请码),仅靠文案区分:
|
枚举
|
含义
|
标题
|
口号
|
|
LUCKY_BAG
|
福袋券
|
百亿补贴 抽福袋
|
组队双方 必得现金或券
|
|
FRUIT
|
水果券
|
百亿补贴 水果分享券
|
组队双方 必得水果券
|
|
UNKNOWN
|
无法判定
|
特征文案缺失(如只识别出邀请码数字框)
|
—
|
|
fieldBoxes 同步回填 type 关键框。
|
|
|
|
六、其他修复与优化
-
识别 / 文档方向预处理显式校验输入为 8bit 3 通道:归一化按「每像素 3 字节」逐行读,而 Mat.get(row, 0, byte[]) 是从 (row, 0) 起连续读满数组长度 —— 通道数 3 会通道步长错位。OpenCV 虽有「缓冲长度须为通道数整数倍」的前置校验,但 1 通道(灰度图)恒能绕过。旧实现越界即抛 ArrayIndexOutOfBoundsException,故障模式由「立刻报错」退化为「静默产出错误张量」,现改为显式抛 IllegalArgumentException。
-
MemoryLeakReproTest 误报:判据参考点由 round 5 改为 max(round 5, round 10),并移除 stabilizeJvmMemory() 的早退守卫。round 5 紧跟强制 GC,是堆刚被 uncommit 的人为凹点,后续正常回升被算成「增长」;实测误报样本 round 20 仍比 baseline 低 26.8 MB,却因以 round 5 为参考被判成 +87 MB 泄漏。
-
结构化解析热路径分配优化:火车票解析器 3 处 Pattern.compile 提为类常量;户口本解析器标签片段数组提为类常量(消除逐框每次约 110 个 String 引用分配);银行卡持卡人反查 O(n²) → O(n)(语义不变)。
-
死代码清理:Offset.toFloat,以及 PDF 通道三个无 detParams 的私有重载。
升级指引
net.dreamlu
mica-ppocr-spring-boot-starter
1.2.4
Solon 用户换 mica-ppocr-solon-plugin,纯 Java 用户换 mica-ppocr-core + mica-ppocr-structured。
升级前必读:行为变更汇总
|
变更
|
影响
|
应对
|
|
mica.ai.ppocr.pdf.* 真的生效了
|
之前靠改 yml 调 PDF 参数的用户会发现行为变了 —— 之前根本没生效
|
不配置即保持原行为;默认值两端已对齐
|
|
PdfOcrConfig Bean 会被引擎直接采用
|
自定义同名 Bean 会改变引擎行为,此前是静默忽略
|
检查自定义 Bean 是否符合预期
|
|
pdf.enabled=false 时 Bean 仍存在
|
取默认值
|
如依赖 Bean 缺失做判断,需调整
|
|
mica.ai.ppocr.enabled=false 时不再留下 PdfOcrConfig Bean
|
此前 Spring 会残留一个
|
按需改成读配置属性而非读 Bean
|
|
识别 / 文档方向预处理对非 8bit 3 通道 Mat 抛 IllegalArgumentException
|
此前要么越界异常,要么静默产出错误张量
|
传入前先转成 CV_8UC3
|
兼容性
-
Java 8 兼容不变,运行依赖字节码均为 major 52。
-
依赖版本:onnxruntime 1.18.0 / opencv 4.9.0-0 / jts-core 1.20.0 / pdfbox 3.0.8 / slf4j 2.0.20 / spring-boot 2.7.18 / mica-auto 2.3.5 / solon 4.1.1。
-
本版实际升级的依赖只有两项:slf4j 2.0.19 → 2.0.20、solon 4.1.0 → 4.1.1(均为小版本,向后兼容)。其余依赖版本未动。
-
Spring Boot Starter 与 Solon 插件能力对齐,类名一一对应。