Skip to content

MongoTap/PP-OCRv6-Java-OCR-Service

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 

Repository files navigation

PP-OCRv6 OCR Service (最小实现)

中文 · English

基于 Java SpringBoot + ONNX Runtime 的 PP-OCRv6 OCR 识别服务,提供文本检测、文本识别和完整流水线的 REST API。

项目概述

本项目使用 PaddleOCR 团队发布的 PP-OCRv6_medium 系列 ONNX 模型,在 Java 生态中实现完整的 OCR 能力。核心技术路线严格对齐 PaddleOCR Python 参考实现,确保预处理(图像归一化、尺寸缩放、通道顺序)和后处理(CTC 解码、DBPostProcess)与官方版本一致。

模型 参数量 用途 来源
PP-OCRv6_medium_rec 19M 文本识别 ModelScope
PP-OCRv6_medium_det 15.5M 文本检测 ModelScope

功能特性

已实现功能

  • 文本检测 (Text Detection) — DB(Differentiable Binarization)算法检测图像中文本区域,返回四边形边界框坐标
    • Moore-Neighbor 轮廓追踪
    • 凸包 + 旋转卡壳最小外接矩形
    • Unclip 多边形扩展
    • 阅读顺序排序(自上而下,从左到右)
  • 文本识别 (Text Recognition) — CTC 解码,支持 50 种语言,18708 字符字典
    • 双 Softmax 头(CTC + NRTR Attention)
    • 空白符去重(Blank Index = 0)
    • 模型索引偏移(Index 1 → charDict[0])
  • 完整流水线 — 检测 → 裁剪 → 识别
    • 透射变换(DLT Homography)校正文本行角度
    • 自动旋转竖向文本(宽高比 ≥ 1.5)
    • 双线性插值图像缩放
  • Markdown 文档输出 — 布局分析 + Markdown 格式化
    • 多栏检测(XY-Cut 投影分析)
    • 段落合并(基于垂直间距和缩进)
    • 标题级别检测(基于字体高度比)
    • 列表格式自动识别
  • 5 个 REST API 端点

待优化方向

  • 版面分析增强 — 支持表格识别、页眉/页脚/页码检测、图片标题识别
  • 公式识别 — 集成 LaTeX 公式 OCR 模型
  • 文档方向分类 — 自动检测并纠正文档旋转角度
  • 文档扭曲校正 — 对弯曲/折叠文档进行展平校正
  • 流式输出 — 大文档分块处理,SSE 流式返回结果
  • 批量处理 — 支持多图片并发提交
  • 结果缓存 — 相同图片的 MD5 缓存,避免重复处理
  • 模型预热 — 启动时预跑一次推理,避免首次请求延迟
  • 性能优化 — 检测/识别模型异步并行执行(当前检测为串行瓶颈)
  • 更多输出格式 — 支持 HTML、LaTeX、纯文本等输出格式
  • 可配置参数 — 检测阈值、识别 batch size 等通过 yaml 配置
  • Docker 部署 — 提供 Dockerfile 和 docker-compose.yml

技术架构

graph TB
    subgraph Controller["API 层 (OcrController)"]
        RC["POST /recognize<br/>文本识别"]
        DT["POST /detect<br/>文本检测"]
        PL["POST /pipeline<br/>完整流水线"]
        MD["POST /markdown<br/>Markdown 输出"]
    end

    subgraph Service["服务层"]
        OcrSvc["OcrService<br/>文本识别服务"]
        DetSvc["DetService<br/>文本检测服务"]
        PipeSvc["OcrPipelineService<br/>流水线编排"]
    end

    subgraph Preprocess["预处理"]
        RecPrep["ImagePreprocessor<br/>resize_norm_img<br/>HWC→CHW → 归一化 → pad"]
        DetPrep["DetPreprocessor<br/>DetResizeForTest<br/>NormalizeImage → ToCHWImage"]
    end

    subgraph Postprocess["后处理"]
        DetPost["DetPostProcessor<br/>DBPostProcess<br/>阈值化→轮廓→minAreaRect→unclip"]
        CTCDecode["CTC Decode<br/>Argmax→去重→去空白→字典映射"]
    end

    subgraph Layout["布局分析"]
        LA["LayoutAnalyzer<br/>XY-Cut 分栏 → 段落合并<br/>→ 标题级别检测"]
        MC["MarkdownConverter<br/>Markdown 格式化输出"]
    end

    subgraph Models["ONNX 模型"]
        RecModel["inference.onnx<br/>PP-OCRv6_medium_rec<br/>19M params"]
        DetModel["inference_det.onnx<br/>PP-OCRv6_medium_det<br/>15.5M params"]
    end

    RC --> OcrSvc
    DT --> DetSvc
    PL --> PipeSvc
    MD --> PipeSvc

    OcrSvc --> RecPrep --> RecModel --> CTCDecode
    DetSvc --> DetPrep --> DetModel --> DetPost
    PipeSvc --> DetSvc
    PipeSvc --> OcrSvc
    PipeSvc --> LA --> MC
Loading

数据流

flowchart TB
    IMG["📷 JPEG / PNG"]

    subgraph DET["① 文本检测"]
        RESIZE["DetResizeForTest<br/>缩放至 736 边,对齐 32 的倍数"]
        NORM["NormalizeImage<br/>÷255 → (x - μ) / σ"]
        INFER_D["ONNX 推理 (det)"]
        DBPOST["DBPostProcess<br/>阈值 0.3 → 轮廓追踪<br/>→ minAreaRect → unclip"]
    end

    SORT["② 阅读顺序排序<br/>按 Y 分组 → 行内 X 排序"]

    CROP["③ 透视变换裁剪<br/>DLT Homography → 双线性采样"]

    subgraph REC["④ 文本识别"]
        RCPREP["resize_norm_img<br/>高 48,宽等比 ≤ 320"]
        INFER_R["ONNX 推理 (rec)"]
        CTC["CTC 解码<br/>blank=0 → argmax → 去重"]
    end

    subgraph LAYOUT["⑤ 布局分析 + Markdown"]
        XY["XY-Cut 分栏检测"]
        MERGE["段落合并"]
        HEADING["标题级别检测"]
        MD_OUT["Markdown 格式化"]
    end

    OUTPUT["📄 Markdown 文档"]

    IMG --> DET
    DET --> RESIZE --> NORM --> INFER_D --> DBPOST
    DBPOST --> SORT
    SORT --> CROP
    CROP --> REC
    REC --> RCPREP --> INFER_R --> CTC
    CTC --> LAYOUT
    LAYOUT --> XY --> MERGE --> HEADING --> MD_OUT
    MD_OUT --> OUTPUT
Loading

API 参考

基础路径: /api/ocr

1. 健康检查

GET /api/ocr/health

响应:

{"status": "UP", "model": "PP-OCRv6_medium_rec + PP-OCRv6_medium_det"}

2. 文本识别(需裁剪好的文本行图片)

POST /api/ocr/recognize
Content-Type: multipart/form-data

Body: image (File)

响应:

{"text": "3425698840", "confidence": 0.9999981}

3. 文本检测

POST /api/ocr/detect
Content-Type: multipart/form-data

Body: image (File)

响应:

{
  "boxes": [
    {
      "points": [[362,426], [1278,426], [1278,576], [362,576]],
      "score": 0.9135921
    }
  ]
}

4. 完整流水线(检测 → 识别)

POST /api/ocr/pipeline
Content-Type: multipart/form-data

Body: image (File)

响应:

{
  "results": [
    {"text": "3425698840", "confidence": 0.9999981}
  ]
}

5. Markdown 文档输出

POST /api/ocr/markdown
Content-Type: multipart/form-data

Body: image (File)

响应:

{
  "markdown": "# 文档标题\n\n这是第一段内容...\n\n这是第二段内容..."
}

代码架构

ocr-service/src/main/java/com/ppocrv6/ocr/
├── OcrApplication.java                # Spring Boot 入口
├── config/
│   └── OcrConfig.java                 # Bean 定义(ONNX 资源、环境、预处理器)
├── controller/
│   └── OcrController.java             # REST 端点(5 个 API)
├── model/
│   ├── OcrResult.java                 # 识别结果(text + confidence)
│   ├── TextBox.java                   # 检测文本框(4 角坐标 + score)
│   └── AnnotatedText.java             # 带坐标的识别结果(布局分析用)
├── service/
│   ├── OcrService.java                # 识别模型加载 + 推理 + CTC 解码
│   ├── DetService.java                # 检测模型加载 + 推理
│   └── OcrPipelineService.java        # 流水线编排(检测→裁剪→识别→Markdown)
└── util/
    ├── ImagePreprocessor.java         # 识别预处理(resize_norm_img NCHW)
    ├── DetPreprocessor.java           # 检测预处理(DetResizeForTest + NormalizeImage)
    ├── DetPostProcessor.java          # DBPostProcess(轮廓 + minAreaRect + unclip)
    ├── ImageUtils.java                # 透射变换裁剪 + 图像旋转
    ├── CharDictLoader.java            # 字符字典加载
    ├── LayoutAnalyzer.java            # 布局分析(分栏 + 段落合并 + 标题检测)
    └── MarkdownConverter.java         # Markdown 格式化输出

设计原则

  1. 与 PaddleOCR 对齐 — 每个预处理/后处理步骤严格匹配 PaddleOCR Python 源码
  2. 零外部计算机视觉依赖 — 检测后处理(轮廓追踪、凸包、旋转卡壳、多边形扩展、透视变换)全部使用纯 Java 实现,无需 OpenCV/BoofCV
  3. 向后兼容 — 新增端点不影响已有 API
  4. 无状态设计 — 服务不保存用户数据,适合容器化部署

关键算法实现

算法 文件 说明
Moore-Neighbor 轮廓追踪 DetPostProcessor 8-连通边界跟踪
Andrew's Monotone Chain 凸包 DetPostProcessor 计算点集凸包
Rotating Calipers 最小外接矩形 DetPostProcessor 旋转卡壳求最小面积包围盒
Ramer-Douglas-Peucker 轮廓简化 DetPostProcessor 简化轮廓折线
DLT 透射变换 ImageUtils 直接线性变换 + 高斯消元解 8x8 方程
Scanline 多边形填充 DetPostProcessor 扫描线填充算法计算多边形内均值
XY-Cut 分栏检测 LayoutAnalyzer X 轴投影分析检测多栏布局
CTC 解码 OcrService Argmax → 去重 → 去空白 → 字典映射

环境要求

  • JDK: 17+
  • Maven: 3.6+
  • 内存: ≥ 4GB(两个 ONNX 模型合计约 134MB,推理时需额外内存)
  • 无外部服务依赖(无需数据库、缓存、消息队列)

模型准备

模型文件较大(合计约 134MB),未包含在 Git 仓库中。请手动下载并放置到对应目录:

# 1. 下载识别模型
# 从 https://www.modelscope.cn/models/PaddlePaddle/PP-OCRv6_medium_rec_onnx/files
# 下载所有文件,解压到:
mkdir -p PP-OCRv6_medium_rec_onnx
# 将 inference.onnx 和 char_dict.json 放入 PP-OCRv6_medium_rec_onnx/

# 2. 下载检测模型
# 从 https://www.modelscope.cn/models/PaddlePaddle/PP-OCRv6_medium_det_onnx/files
# 下载所有文件,解压到:
mkdir -p PP-OCRv6_medium_det_onnx
# 将 inference.onnx 放入 PP-OCRv6_medium_det_onnx/

# 3. 复制模型文件到服务资源目录
cp PP-OCRv6_medium_rec_onnx/inference.onnx ocr-service/src/main/resources/
cp PP-OCRv6_medium_rec_onnx/char_dict.json ocr-service/src/main/resources/
cp PP-OCRv6_medium_det_onnx/inference.onnx ocr-service/src/main/resources/inference_det.onnx

快速开始

# 1. 启动服务
cd ocr-service && mvn spring-boot:run

# 2. 测试健康检查
curl http://localhost:8080/api/ocr/health

# 3. 测试完整流水线(用你的图片替换 test.png)
curl -X POST http://localhost:8080/api/ocr/pipeline \
  -F "image=@/path/to/your/image.png"

# 4. 测试 Markdown 输出
curl -X POST http://localhost:8080/api/ocr/markdown \
  -F "image=@/path/to/your/image.png"

测试

cd ocr-service && mvn test

目前包含 8 个集成测试,覆盖:

  • 模型加载和 Spring 容器初始化
  • 识别预处理(张量形状、空值、灰度图)
  • 识别端到端(合成文本图片 → 识别)
  • 边界情况(空文件、无效数据)

License

Apache 2.0

参考资料

About

A Java SpringBoot + ONNX Runtime OCR service powered by PaddleOCR's PP-OCRv6_medium models, providing REST APIs for text detection, recognition, and full pipeline processing.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages