# 金融文档处理统一框架
参考 MinerU 实现的模型统一框架,针对金融场景设计。
## 支持场景
| 场景类型 | 特点 | 表格形式 |
|---------|------|---------|
| **银行交易流水** | 单栏列表形式,无合并单元格 | 有线表格 / 无线表格 |
| **财务报表** | 多栏列表形式,有合并单元格,表头复杂 | 有线表格 / 无线表格 |
## 模型选择
| 模型类型 | 推荐模型 | 说明 |
|---------|---------|------|
| **版式检测** | Docling Layout / DocLayout-YOLO | HuggingFace 或 MinerU 模型 |
| **文字识别** | PaddleOCR (PyTorch) | 效果好,支持角度校正 |
| **表格结构识别** | MinerU VLM / PaddleOCR-VL | VLM 返回 HTML 结构 |
| **公式识别** | MinerU VLM | 返回 LaTeX |
| **方向识别** | PP-LCNet | 沿用 MinerU 实现 |
| **单元格坐标匹配** | TableCellMatcher | OCR 检测框与 VLM 结构匹配 |
---
## 处理流程
```mermaid
graph TB
A[输入 PDF/图片] --> B{PDF 分类}
B -->|扫描件/图片| C1[页面方向识别
PP-LCNet]
B -->|数字原生PDF| D
C1 --> D[Layout 检测
去重叠框]
D --> E[整页 OCR
获取所有 text spans]
E --> F[Span-Block 匹配
SpanMatcher]
F --> G{元素分类}
G --> H[文本类]
G --> I[表格类]
G --> J[图片类]
G --> K[公式类]
G --> L[丢弃类]
subgraph 文本处理
H --> H1{有匹配的spans?}
H1 -->|是| H2[合并 spans 文本]
H1 -->|否| H3{PDF类型?}
H3 -->|数字PDF| H4[PDF 字符提取]
H4 --> H5{成功?}
H5 -->|否| H6[裁剪区域 OCR]
H5 -->|是| H7[文本结果]
H3 -->|扫描件| H6
H6 --> H7
H2 --> H7
end
subgraph 表格处理
I --> I1[OCR 检测
获取文本框坐标]
I --> I2[VLM 结构识别
返回 HTML]
I1 --> I3[坐标匹配
TableCellMatcher]
I2 --> I3
I3 --> I4[带坐标的表格]
end
subgraph 图片处理
J --> J1[裁剪保存]
end
subgraph 公式处理
K --> K1[VLM 识别
返回 LaTeX]
end
subgraph 丢弃元素
L --> L1{有匹配的spans?}
L1 -->|是| L2[合并 spans 文本]
L1 -->|否| L3[裁剪区域 OCR]
L2 --> L4[保留备用]
L3 --> L4
end
H7 --> M[合并所有结果]
I4 --> M
J1 --> M
K1 --> M
L4 --> M
M --> N[按阅读顺序排序]
N --> O[坐标转换回原图]
O --> P[合并跨页表格]
P --> Q[金额数字标准化]
Q --> R[多格式输出]
```
### 关键改进:整页 OCR + Span 匹配
参考 MinerU 的处理方式,新流程采用 **整页 OCR → Span-Block 匹配** 策略:
1. **整页 OCR**:先对整个页面进行 OCR,获取所有 text spans(包含坐标和文本)
2. **Span 去重**:移除高 IoU 重叠的 spans,保留置信度高的
3. **Span-Block 匹配**:将 OCR spans 按重叠比例匹配到对应的 layout blocks
4. **文本合并**:将匹配到同一 block 的 spans 按阅读顺序合并
**优势**:
- ✅ 避免裁剪小图 OCR 失败的问题
- ✅ OCR 可以利用更多上下文信息
- ✅ 坐标更精确(整页坐标系)
- ✅ 与 MinerU 处理方式一致
### 元素分类说明
| 元素类别 | 包含类型 | 处理方式 |
|---------|---------|---------|
| **文本类** | text, title, header, footer, ref_text, table_caption, image_caption 等 | 优先使用匹配的 spans,否则 PDF 提取或裁剪 OCR |
| **表格类** | table, table_body | OCR 坐标 + VLM 结构 |
| **图片类** | image, image_body, figure | 裁剪保存 |
| **公式类** | interline_equation, equation | VLM 识别 |
| **丢弃类** | abandon, discarded | 优先使用匹配的 spans,否则裁剪 OCR |
---
## 方向识别策略
| 处理阶段 | 方向识别 | 建议 |
|---------|---------|------|
| **页面级** | PP-LCNet | 可配置,扫描件开启,数字PDF关闭 |
| **表格区域** | - | 可选,VLM 有一定容忍度,OCR 自带角度校正 |
| **文本区域** | - | 不需要,OCR 自带校正 |
---
## Layout 后处理
### 大面积文本块转表格
当Layout检测将大面积的表格区域误识别为文本框时,可以通过后处理自动转换:
**判断规则**:
- 面积占比:占页面面积超过阈值(默认25%)
- 尺寸比例:宽度和高度都超过一定比例(避免细长条)
- 表格冲突:如果页面已有表格,不进行转换(避免误判)
**配置示例**:
```yaml
layout:
convert_large_text_to_table: true # 是否启用
min_text_area_ratio: 0.25 # 最小面积占比(25%)
min_text_width_ratio: 0.4 # 最小宽度占比(40%)
min_text_height_ratio: 0.3 # 最小高度占比(30%)
```
详细说明请参考:`Layout后处理-文本转表格.md`
---
## OCR 使用策略
| PDF 类型 | 文字块处理 | 表格处理 |
|---------|-----------|---------|
| **扫描件/图片** | 整页 OCR → Span 匹配 | OCR 检测(坐标) + VLM(结构) |
| **数字原生 PDF** | 整页 OCR → Span 匹配 / PDF 字符提取 | OCR 检测(坐标) + VLM(结构) |
**关键点**:
- **整页 OCR 优先**:先对整页进行 OCR,再将结果匹配到 layout blocks
- 数字原生 PDF 在 spans 匹配失败时,会尝试 PDF 字符提取
- **表格处理无论 PDF 类型都需要 OCR 检测**,用于获取单元格内文本的精确坐标
- VLM 只返回表格结构(HTML),不返回单元格坐标,需要与 OCR 检测结果匹配
- 当前实现仅使用 VLM(MinerU VLM 或 PaddleOCR-VL)进行表格结构识别
### OCR 参数配置
**默认参数(已优化,参考PPStructureV3)**:
- `det_threshold`: 0.6(检测框置信度阈值,提高可减少噪声框)
- `unclip_ratio`: 1.5(检测框扩展比例,降低可提高框精确度)
- `enable_merge_det_boxes`: False(是否合并检测框,表格场景建议False)
**配置示例**:
```yaml
ocr:
det_threshold: 0.6 # 检测阈值(0.3-0.7,越高越严格)
unclip_ratio: 1.5 # 扩展比例(1.3-1.8,越低越精确)
enable_merge_det_boxes: false # 合并框(表格场景建议false)
language: ch # 语言(ch/ch_lite/en等)
```
**参数调优建议**:
- **表格密集场景**:`det_threshold=0.6`, `enable_merge_det_boxes=false`
- **文本稀疏场景**:`det_threshold=0.4`, `enable_merge_det_boxes=true`
- **扫描件质量差**:`det_threshold=0.3`, `unclip_ratio=1.8`
详细分析请参考:`OCR识别差异分析与改进方案.md`
---
## 目录结构
```
universal_doc_parser/
├── config/ # 配置文件
│ ├── bank_statement_yusys_v2.yaml # 银行流水配置(Docling + PaddleOCR-VL)
│ ├── bank_statement_mineru_v2.yaml # 银行流水配置(MinerU layout + MinerU VLM)
│ ├── bank_statement_mineru_vl.yaml # 银行流水配置(MinerU VLM)
│ └── bank_statement_paddle_vl.yaml # 银行流水配置(PaddleOCR-VL)
│
├── core/ # 核心处理模块
│ ├── pipeline_manager_v2.py # 主流水线管理器 ⭐
│ ├── element_processors.py # 元素处理器(文本、表格、图片等)
│ ├── coordinate_utils.py # 坐标转换工具
│ ├── layout_utils.py # 布局处理工具(排序、去重、SpanMatcher)⭐
│ ├── pdf_utils.py # PDF 处理工具
│ ├── config_manager.py # 配置管理
│ └── model_factory.py # 模型工厂
│
├── models/ # 模型适配器
│ └── adapters/
│ ├── base.py # 适配器基类
│ ├── mineru_adapter.py # MinerU 适配器
│ ├── paddle_vl_adapter.py # PaddleOCR-VL 适配器
│ ├── paddle_layout_detector.py # PaddleX RT-DETR 布局检测器
│ └── docling_layout_adapter.py # Docling 布局检测器 ⭐
│
├── utils/ # 输出工具模块
│ ├── output_formatter_v2.py # 统一输出格式化器 ⭐
│ ├── json_formatters.py # JSON 格式化(middle.json, page.json)
│ ├── markdown_generator.py # Markdown 生成器
│ ├── html_generator.py # HTML 生成器
│ ├── visualization_utils.py # 可视化工具(layout/OCR 图片)
│ └── normalize_financial_numbers.py # 金额数字标准化
│
├── main_v2.py # 命令行入口 ⭐
└── 模型统一框架.md # 本文档
```
---
## 使用方法
### 命令行
```bash
# 处理单个 PDF 文件
python main_v2.py -i document.pdf -c config/bank_statement_yusys_v2.yaml
# 处理图片目录
python main_v2.py -i ./images/ -c config/bank_statement_yusys_v2.yaml
# 开启 debug 模式(输出可视化图片)
python main_v2.py -i doc.pdf -c config/bank_statement_yusys_v2.yaml --debug
# 指定输出目录
python main_v2.py -i doc.pdf -c config/bank_statement_yusys_v2.yaml -o ./my_output/
```
### Python API
```python
from core.pipeline_manager_v2 import EnhancedDocPipeline
from utils import OutputFormatterV2
# 初始化流水线
with EnhancedDocPipeline("config/bank_statement_yusys_v2.yaml") as pipeline:
# 处理文档
results = pipeline.process_document("document.pdf")
# 保存结果
formatter = OutputFormatterV2("./output")
output_paths = formatter.save_results(results, {
'save_json': True,
'save_markdown': True,
'save_html': True,
'save_layout_image': True, # debug
'save_ocr_image': True, # debug
'normalize_numbers': True, # 金额标准化
})
```
---
## 输出文件说明
| 输出文件 | 说明 |
|---------|------|
| `{doc}_middle.json` | MinerU 标准格式 JSON |
| `{doc}_page_001.json` | 每页独立 JSON(包含单元格坐标) |
| `{doc}.md` | 完整文档 Markdown |
| `{doc}_page_001.md` | 每页独立 Markdown(带坐标注释) |
| `tables/*.html` | 表格 HTML 文件(带 data-bbox 坐标) |
| `images/` | 提取的图片元素 |
| `{doc}_page_001_layout.png` | Layout 可视化图片(debug 模式) |
| `{doc}_page_001_ocr.png` | OCR 可视化图片(debug 模式) |
| `*_original.*` | 标准化前的原始文件(如有修改) |
---
## 配置说明
配置文件采用 YAML 格式,主要配置项:
```yaml
# 场景名称
scene_name: "bank_statement"
# 输入配置
input:
supported_formats: [".pdf", ".png", ".jpg", ".jpeg"]
dpi: 200 # PDF 转图片的 DPI
# 预处理(方向识别)
preprocessor:
module: "mineru"
orientation_classifier:
enabled: true # 扫描件自动开启
# 版式检测
layout_detection:
module: "docling" # 可选: "mineru", "paddle", "docling"
model_name: "docling-layout-old"
model_dir: "ds4sd/docling-layout-old" # HuggingFace 模型仓库
device: "cpu"
conf: 0.3
# VL 识别(表格、公式)
vl_recognition:
module: "paddle" # 可选: "mineru", "paddle"
backend: "http-client"
server_url: "http://xxx:8110"
table_recognition:
return_cells_coordinate: true
# OCR 识别
ocr_recognition:
module: "mineru"
language: "ch"
# 输出配置
output:
create_subdir: false # 是否创建子目录
save_json: true
save_markdown: true
save_html: true
save_layout_image: false # debug 模式开启
save_ocr_image: false # debug 模式开启
normalize_numbers: true # 金额数字标准化
```
---
## 支持的布局检测器
### 1. Docling Layout (推荐)
基于 HuggingFace transformers 的 RT-DETR 模型。
```yaml
layout_detection:
module: "docling"
model_name: "docling-layout-old"
model_dir: "ds4sd/docling-layout-old"
```
支持的模型:
- `ds4sd/docling-layout-old`
- `ds4sd/docling-layout-heron`
- `ds4sd/docling-layout-egret-medium`
- `ds4sd/docling-layout-egret-large`
### 2. PaddleX RT-DETR (ONNX)
基于 ONNX Runtime 的 PaddleX 布局检测器。
```yaml
layout_detection:
module: "paddle"
model_name: "RT-DETR-H_layout_17cls"
model_dir: "/path/to/RT-DETR-H_layout_17cls.onnx"
```
### 3. MinerU DocLayout-YOLO
MinerU 内置的布局检测模型。
```yaml
layout_detection:
module: "mineru"
model_name: "layout"
```
---
## 类别映射
所有布局检测器的输出都会统一映射到 MinerU/EnhancedDocPipeline 类别体系:
| 类别分类 | 包含类别 |
|---------|---------|
| **文本类** (TEXT) | text, title, header, footer, page_number, ref_text, page_footnote, aside_text, ocr_text |
| **表格类** (TABLE) | table, table_body, table_caption, table_footnote |
| **图片类** (IMAGE) | image, image_body, figure, image_caption, image_footnote |
| **公式类** (EQUATION) | interline_equation, inline_equation, equation |
| **代码类** (CODE) | code, code_body, code_caption, algorithm |
| **丢弃类** (DISCARD) | abandon, discarded |
---
## 核心组件
### 1. EnhancedDocPipeline (`pipeline_manager_v2.py`)
主流水线管理器,实现完整处理流程:
- PDF 分类(扫描件/数字原生)
- 页面方向识别
- Layout 检测与去重
- **整页 OCR + Span-Block 匹配** ⭐
- 元素分类处理
- 阅读顺序排序
- 坐标转换
### 2. SpanMatcher (`layout_utils.py`)
OCR Span 与 Layout Block 匹配器,参考 MinerU 实现:
- `match_spans_to_blocks()` - 将 spans 匹配到对应的 blocks
- `merge_spans_to_text()` - 将多个 spans 合并为文本
- `remove_duplicate_spans()` - 去除重复 spans
- `poly_to_bbox()` - 多边形坐标转 bbox
### 3. ElementProcessors (`element_processors.py`)
元素处理器,处理不同类型的元素:
- `process_text_element()` - 文本处理(支持 pre_matched_spans)
- `process_table_element()` - 表格处理(VLM + OCR 坐标匹配)
- `process_image_element()` - 图片处理
- `process_equation_element()` - 公式处理
- `process_code_element()` - 代码处理
- `process_discard_element()` - 丢弃元素处理(支持 pre_matched_spans)
### 3. OutputFormatterV2 (`output_formatter_v2.py`)
统一输出格式化器:
- MinerU 标准 middle.json 格式
- 每页独立 JSON(含单元格坐标)
- Markdown 输出(完整版 + 按页)
- 表格 HTML(带 data-bbox 属性)
- 可视化图片(Layout/OCR)
- 金额数字标准化
### 4. TableCellMatcher (来自 `merger`)
表格单元格坐标匹配器:
- 使用动态规划进行行内单元格匹配
- 将 OCR 检测框与 VLM 表格结构匹配
- 输出带坐标的增强 HTML
---
## 依赖说明
### MinerU 组件
- `mineru.utils.pdf_image_tools` - PDF 图像处理
- `mineru.utils.pdf_text_tool` - PDF 文本提取
- `mineru.utils.boxbase` - 边界框计算
- `mineru.model.ocr` - OCR 模型
- `mineru.model.ori_cls` - 方向分类模型
### Merger 组件(来自 ocr_verify)
- `merger.table_cell_matcher.TableCellMatcher` - 单元格坐标匹配
- `merger.text_matcher.TextMatcher` - 文本匹配
### 其他依赖
- transformers - Docling 模型加载
- huggingface_hub - 模型下载
- onnxruntime - ONNX 模型推理
- Pillow - 图像处理
- NumPy - 数值计算
- BeautifulSoup4 - HTML 解析
- PyYAML - 配置文件解析
- loguru - 日志
---
## 安装 merger 模块
```bash
# 1. 进入 ocr_verify 目录
cd /Users/zhch158/workspace/repository.git/ocr_verify
# 2. 安装 merger 模块(可编辑模式)
pip uninstall -y merger && pip install -e .
# 3. 验证安装
python3 -c "from merger.table_cell_matcher import TableCellMatcher; print('✅ 安装成功')"
```
完成后,在任何 Python 文件中都可以直接导入:
```python
from merger.table_cell_matcher import TableCellMatcher
from merger.text_matcher import TextMatcher
from merger.bbox_extractor import BBoxExtractor
```
---
## 项目结构
```
/Users/zhch158/workspace/repository.git/
├── ocr_verify/ # 源项目
│ ├── setup.py # 安装配置
│ └── merger/ # 表格匹配模块
│ ├── table_cell_matcher.py # 表格单元格匹配
│ ├── text_matcher.py # 文本匹配
│ └── bbox_extractor.py # 边界框提取
│
└── MinerU/ # 目标项目
└── zhch/
└── universal_doc_parser/ # 金融文档处理框架
├── core/ # 核心处理模块
├── models/adapters/ # 模型适配器
├── utils/ # 输出工具
└── config/ # 配置文件
```