# 金融文档处理统一框架
参考 MinerU 实现的模型统一框架,针对金融场景设计。
## 支持场景
| 场景类型 | 特点 | 表格形式 |
|---------|------|---------|
| **银行交易流水** | 单栏列表形式,无合并单元格 | 有线表格 / 无线表格 |
| **财务报表** | 多栏列表形式,有合并单元格,表头复杂 | 有线表格 / 无线表格 |
## 模型选择
| 模型类型 | 推荐模型 | 说明 |
|---------|---------|------|
| **方向分类** | PP-LCNet_x1_0_doc_ori | paddle onnx格式的模型 |
| **版式检测** | Docling Layout / DocLayout-YOLO | Docling 或 MinerU 模型 |
| **文字识别** | PaddleOCR (PyTorch) | 效果好,支持角度校正 |
| **表格结构识别** | MinerU VLM / PaddleOCR-VL / UNET 有线表格 | VLM 返回 HTML 结构 |
| **公式识别** | MinerU VLM | 返回 LaTeX |
| **单元格坐标匹配** | TableCellMatcher | OCR 检测框与 VLM 结构匹配 |
---
## 处理流程
### 主流程图
```mermaid
graph TB
A[输入 PDF/图片] --> B[加载文档并分类]
B --> C{文档类型?}
C -->|PDF| D[PDF分类: 扫描件/数字原生]
C -->|图片目录| E[加载所有图片]
D --> F[处理每一页]
E --> F
F --> G[页面方向识别
仅扫描件]
G --> H[Layout 检测]
H --> I[去重重叠框]
I --> J{大文本块转表格?}
J -->|启用| K[后处理转换]
J -->|否| L
K --> L[整页 OCR
获取所有 text spans]
L --> M[Span 去重与排序]
M --> N[Span-Block 匹配
SpanMatcher]
N --> O[元素分类]
O --> P[处理各类元素]
P --> Q[按阅读顺序排序]
Q --> R[坐标转换回原图]
R --> S{所有页处理完?}
S -->|否| F
S -->|是| T[跨页表格合并]
T --> U[输出结果]
style L fill:#e1f5ff
style N fill:#e1f5ff
style P fill:#fff4e1
```
---
### 单页处理详细流程
```mermaid
graph TB
A[输入:页面图像] --> B{PDF类型?}
B -->|扫描件| C[页面方向识别
PP-LCNet]
B -->|数字PDF| D
C --> D[Layout 检测
Docling/MinerU/DiT]
D --> E[去重重叠框
IoU过滤]
E --> F{大文本块转表格?}
F -->|是| G[面积占比判断
转换为table类型]
F -->|否| H
G --> H[整页 OCR
获取所有 text spans]
H --> I[Span 去重
IoU过滤]
I --> J[Span 排序
从上到下、从左到右]
J --> K[Span-Block 匹配
overlap_threshold=0.5]
K --> L[元素分类]
L --> L1[文本类]
L --> L2[表格类]
L --> L3[图片类]
L --> L4[公式类]
L --> L5[代码类]
L --> L6[丢弃类]
L1 --> M[处理文本元素]
L2 --> N[处理表格元素]
L3 --> O[处理图片元素]
L4 --> P[处理公式元素]
L5 --> Q[处理代码元素]
L6 --> R[处理丢弃元素]
M --> S[合并所有结果]
N --> S
O --> S
P --> S
Q --> S
R --> S
S --> T[按阅读顺序排序]
T --> U[坐标转换回原图]
style H fill:#e1f5ff
style K fill:#e1f5ff
style L fill:#fff4e1
style L1 fill:#fff4e1
style L2 fill:#fff4e1
style L3 fill:#fff4e1
style L4 fill:#fff4e1
style L5 fill:#fff4e1
style L6 fill:#fff4e1
```
### 关键改进:整页 OCR + Span 匹配
参考 MinerU 的处理方式,新流程采用 **整页 OCR → Span-Block 匹配** 策略:
1. **整页 OCR**:先对整个页面进行 OCR,获取所有 text spans(包含坐标和文本)
2. **Span 去重**:移除高 IoU 重叠的 spans,保留置信度高的
3. **Span 排序**:按坐标排序(从上到下,从左到右),方便人工检查缺失字符
4. **Span-Block 匹配**:将 OCR spans 按重叠比例(默认0.5)匹配到对应的 layout blocks
5. **文本合并**:将匹配到同一 block 的 spans 按阅读顺序合并
**优势**:
- ✅ 避免裁剪小图 OCR 失败的问题
- ✅ OCR 可以利用更多上下文信息
- ✅ 坐标更精确(整页坐标系)
- ✅ 减少重复 OCR 调用,提高效率
- ✅ 与 MinerU 处理方式一致
**代码实现**:
```python
# 1. 整页 OCR
all_ocr_spans = self.ocr_recognizer.recognize_text(detection_image)
# 2. 去除重复 spans
all_ocr_spans = SpanMatcher.remove_duplicate_spans(all_ocr_spans)
# 3. 按坐标排序
all_ocr_spans = self._sort_spans_by_position(all_ocr_spans)
# 4. 将 OCR spans 匹配到 layout blocks
matched_spans = SpanMatcher.match_spans_to_blocks(
all_ocr_spans, layout_results, overlap_threshold=0.5
)
# 5. 在元素处理时使用预匹配的 spans
element = self.element_processors.process_text_element(
detection_image, item, pdf_type, pdf_doc, page_idx, scale,
pre_matched_spans=matched_spans.get(block_idx, [])
)
```
---
### 表格处理流程
表格处理支持两种路径:**有线表格(UNET)** 和 **无线表格(VLM)**
```mermaid
graph TB
A[表格区域] --> B[表格 OCR 预处理]
subgraph OCR预处理
B --> B1[裁剪表格区域
padding=10px]
B1 --> B2[表格方向检测
PP-LCNet]
B2 --> B3{有整页OCR spans?}
B3 -->|是| B4[提取重叠spans
转换坐标到裁剪区域]
B3 -->|否| B5[裁剪区域单独OCR
兜底方案]
B4 --> B6[OCR框列表]
B5 --> B6
end
B6 --> C{使用有线表格?}
C -->|是| D[UNet 有线表格路径]
C -->|否| E[VLM 无线表格路径]
subgraph 有线表格路径
D --> D1[UNet 检测表格线
横线 + 竖线]
D1 --> D2{启用倾斜矫正?}
D2 -->|是| D3[Hough变换检测角度
矫正图片和OCR坐标]
D2 -->|否| D4
D3 --> D4[网格恢复
grid_recovery.py]
D4 --> D5[边缘过滤
edge_margin=padding×upscale×1.2]
D5 --> D6[文本填充
text_filling.py]
D6 --> D7[生成HTML
data-bbox属性]
D7 --> D8{识别成功?}
D8 -->|否| E[自动Fallback到VLM]
D8 -->|是| F
end
subgraph 无线表格路径
E --> E1[VLM识别表格结构
返回HTML]
E1 --> E2[TableCellMatcher匹配
OCR框 + HTML结构]
E2 --> E3[生成增强HTML
data-bbox属性]
E3 --> F
end
F[坐标逆转换] --> G[回到原图坐标系]
G --> H[返回表格元素]
style D fill:#e1f5ff
style D3 fill:#e1f5ff
style D5 fill:#ffe1e1
style E1 fill:#fff4e1
```
#### 表格OCR预处理(共享逻辑)
无论使用哪种表格识别方法,都需要先进行OCR预处理:
1. **裁剪表格区域**:添加 `padding=10px` 保护边缘内容
2. **表格方向检测**:使用 PP-LCNet 检测并矫正表格方向
3. **收集OCR框**:
- **优先**:使用整页OCR结果中与表格区域重叠的spans
- **兜底**:对裁剪后的表格区域单独OCR
4. **坐标转换**:将坐标从原图转换到裁剪后的表格图像坐标系
**关键点**:
- padding=10px 在原图坐标系中
- 表格图像的 (0,0) 对应原图的 (bbox[0]-padding, bbox[1]-padding)
- UNet处理时会放大 upscale_ratio≈3.333 倍
#### 有线表格识别流程(UNET)
配置项:`table_recognition_wired.use_wired_unet: true`
**处理步骤**:
1. **UNet表格线检测**:
- 检测横线(rows)和竖线(cols)坐标
- 坐标在放大后的图像坐标系(upscale≈3.333倍)
2. **倾斜检测与矫正**(可选,`enable_deskew: true`):
- 使用 Hough 变换检测表格线倾斜角度
- 坐标系:Y轴向下,逆时针旋转为正角度
- 矫正逻辑:`correction_angle = -detected_angle`(反向旋转)
- 同步更新表格图像和OCR框坐标
3. **网格恢复**(`grid_recovery.py`):
- 提取唯一的行线和列线坐标
- **边缘过滤**:过滤padding区域的噪声线条
```python
edge_margin = int(crop_padding × upscale × 1.2) # 例如:10 × 3.333 × 1.2 = 40px
```
- 合并距离过近的线条(`row_threshold`, `col_threshold`)
- 生成单元格网格
4. **文本填充**(`text_filling.py`):
- 计算OCR框与单元格的IoU
- 匹配OCR文本到对应单元格
- 支持置信度过滤(`ocr_conf_threshold`)
5. **HTML生成**:
- 生成标准表格HTML
- 添加 `data-bbox` 属性记录单元格坐标
6. **坐标逆转换**:
- 将所有坐标从裁剪+放大坐标系转换回原图坐标系
7. **自动Fallback**:
- 如果有线识别失败(返回空HTML),自动切换到VLM识别
- 无需手动干预,确保识别鲁棒性
**关键配置**:
```yaml
table_recognition_wired:
use_wired_unet: true # 启用有线表格
upscale_ratio: 3.333 # 固定放大比例
enable_deskew: true # 启用倾斜矫正
row_threshold: 10 # 行合并阈值(像素)
col_threshold: 15 # 列合并阈值(像素)
ocr_conf_threshold: 0.8 # OCR置信度阈值
```
#### 无线表格识别流程(VLM)
配置项:`vl_recognition.module: "paddle"` 或 `"mineru"`
**处理步骤**:
1. **VLM结构识别**:
- 输入:表格图像
- 输出:表格HTML结构(无坐标信息)
2. **TableCellMatcher匹配**:
- 解析VLM返回的HTML结构
- 使用动态规划算法匹配OCR框到表格单元格
- 考虑合并单元格(rowspan/colspan)
3. **生成增强HTML**:
- 在原HTML基础上添加 `data-bbox` 属性
- 记录每个单元格的精确坐标
4. **坐标逆转换**:
- 将坐标从裁剪坐标系转换回原图坐标系
### 文本处理流程
```mermaid
graph TB
A[文本区域] --> B{有预匹配spans?}
B -->|是| C[使用整页OCR spans]
C --> D[SpanMatcher合并文本]
D --> E{文本非空?}
B -->|否| F
E -->|是| M[返回文本结果]
E -->|否| F
F{PDF类型?} -->|数字PDF| G[尝试PDF字符提取]
F -->|扫描件| H
G --> I{提取成功?}
I -->|是| M
I -->|否| H
H[裁剪区域OCR
兜底方案] --> M
style C fill:#e1f5ff
style D fill:#e1f5ff
```
**处理优先级**:
1. **优先级1**:使用预匹配的 spans(整页 OCR 结果)
- 效率最高,避免重复OCR
- 坐标精确(整页坐标系)
2. **优先级2**:数字PDF字符提取
- 仅适用于 `pdf_type='txt'`
- 提取PDF内嵌的文本和坐标
3. **优先级3**:裁剪区域OCR(兜底方案)
- 适用于spans匹配失败或扫描件
- 单独OCR该区域,坐标需转换
**代码实现**:
```python
def process_text_element(
self,
image: np.ndarray,
layout_item: Dict[str, Any],
pdf_type: str,
pdf_doc: Optional[Any],
page_idx: int,
scale: float,
pre_matched_spans: Optional[List[Dict[str, Any]]] = None
) -> Dict[str, Any]:
bbox = layout_item.get('bbox', [0, 0, 0, 0])
# 优先级1:使用预匹配的 spans
if pre_matched_spans and len(pre_matched_spans) > 0:
text_content, sorted_spans = SpanMatcher.merge_spans_to_text(
pre_matched_spans, bbox
)
if text_content.strip():
return {..., 'extraction_method': 'whole_page_ocr_spans'}
# 优先级2:PDF字符提取
if pdf_type == 'txt' and pdf_doc is not None:
extracted_text = PDFUtils.extract_text_from_region(...)
if extracted_text.strip():
return {..., 'extraction_method': 'pdf_extraction'}
# 优先级3:裁剪区域OCR
cropped_region = CoordinateUtils.crop_region(image, bbox)
ocr_result = self.ocr_recognizer.recognize_text(cropped_region)
return {..., 'extraction_method': 'cropped_region_ocr'}
```
---
### 元素分类说明
| 元素类别 | 包含类型 | 处理方式 | 是否使用pre_matched_spans |
|---------|---------|---------|-------------------------|
| **文本类** | text, title, header, footer, ref_text, table_caption, image_caption 等 | 优先spans → PDF提取 → 裁剪OCR | ✅ |
| **表格类** | table, table_body | OCR预处理 + (UNET/VLM) | ✅(仅OCR预处理) |
| **图片类** | image, image_body, figure | 裁剪保存 | ❌ |
| **公式类** | interline_equation, equation | VLM识别 → LaTeX | ❌ |
| **代码类** | code, code_body, code_caption, algorithm | 优先spans → PDF提取 → 裁剪OCR | ✅ |
| **丢弃类** | abandon, discarded | 优先spans → 裁剪OCR(保留备用) | ✅ |
---
### 坐标转换说明
处理过程中涉及多个坐标系的转换:
1. **原图坐标系**:PDF/图片的原始坐标
2. **检测图像坐标系**:可能经过旋转(方向矫正)
3. **裁剪区域坐标系**:表格/文本区域裁剪后的坐标(可能有padding)
4. **放大坐标系**:UNet处理时的放大坐标(upscale≈3.333)
**坐标转换流程**:
```
原图坐标 → 检测图像坐标 → 裁剪区域坐标 → 放大坐标(UNET)
↓ ↓ ↓
方向矫正 添加padding upscale放大
↓ ↓ ↓
逆向转换 逆向转换 逆向转换
```
所有处理完成后,坐标统一转换回**原图坐标系**,确保输出一致性。
---
### 元素分类说明
| 元素类别 | 包含类型 | 处理方式 |
|---------|---------|---------|
| **文本类** | 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等)
```
### OCR 参数实际使用对比
不同配置文件针对不同场景优化了OCR参数,选择合适的配置可以显著提升识别效果:
| 配置文件 | det_threshold | unclip_ratio | enable_merge | 适用场景 | 说明 |
|---------|--------------|--------------|--------------|---------|------|
| bank_statement_yusys_v2.yaml | 0.6 | 1.5 | false | 银行流水(标准质量) | **推荐配置**,减少噪声框 |
| bank_statement_mineru_v2.yaml | 0.6 | 1.5 | false | 财务报表(标准质量) | **推荐配置**,高精度 |
| bank_statement_paddle_vl.yaml | 0.3 | 1.8 | false | 扫描质量差 | 宽松配置,增强召回 |
| bank_statement_wired_unet.yaml | 0.5 | 1.8 | false | 有线表格 | 平衡配置,兼顾精度与召回 |
**参数选择建议**:
1. **det_threshold(检测阈值)**:
- `0.6`:严格模式,适合高质量扫描件/数字PDF,**减少噪声框和误检**
- `0.5`:平衡模式,适合有线表格场景,兼顾精度和召回
- `0.3`:宽松模式,适合低质量扫描件,**捕获更多文本但可能产生噪声**
2. **unclip_ratio(扩展比例)**:
- `1.5`:精确模式,检测框更贴近文本边界,**减少相邻单元格干扰**
- `1.8`:宽松模式,检测框扩大,**避免文本截断但可能重叠**
3. **enable_merge_det_boxes(合并框)**:
- `false`:表格场景推荐,**保持单元格独立性**
- `true`:长文本场景,自动合并相邻文本框
**快速选择**:
- ✅ **银行流水/财务报表**(高质量)→ `0.6 / 1.5 / false`
- ✅ **有线表格**(需要精确坐标)→ `0.5 / 1.8 / false`
- ✅ **扫描质量差**(老旧文档)→ `0.3 / 1.8 / false`
详细分析请参考:`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)
│ └── bank_statement_wired_unet.yaml # 有线表格配置(Docling + UNET)⭐ 新增
│
├── core/ # 核心处理模块
│ ├── pipeline_manager_v2.py # 主流水线管理器 ⭐
│ ├── pipeline_manager_v2_streaming.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 布局检测器 ⭐
│ ├── dit_layout_adapter.py # DiT 布局检测器 ⭐ 新增
│ ├── mineru_wired_table.py # MinerU 有线表格识别器 ⭐ 新增
│ └── wired_table/ # 有线表格子模块 ⭐ 新增
│ ├── init.py
│ ├── debug_utils.py # 调试工具
│ ├── ocr_formatter.py # OCR 格式转换
│ ├── skew_detection.py # 倾斜检测与矫正
│ ├── grid_recovery.py # 网格恢复
│ ├── text_filling.py # 文本填充
│ ├── html_generator.py # HTML 生成
│ └── visualization.py # 可视化
│
├── utils/ # 输出工具模块(已迁移到 ocr_utils)⚠️
│ └── init.py # 仅作重新导出接口
│
├── tests/ # 测试模块
│ ├── test_skew_correction.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, # 金额标准化
})
```
### 流式处理模式
对于大文档或内存受限场景,使用流式处理模式:
```bash
# 命令行添加 --streaming 参数
python main_v2.py -i large_document.pdf -c config.yaml --streaming -o ./output
```
流式处理特点:
✅ 按页处理:每处理完一页立即保存结果,不累积在内存中
✅ 内存占用低:适合处理数百页的大文档
✅ 容错性好:某页处理失败不影响已保存的页面
✅ 输出一致:与批量模式输出格式完全一致
适用场景:
处理超过50页的大型PDF文档
服务器内存受限(如4GB以下)
需要实时查看处理进度
---
## 输出文件说明
| 输出文件 | 说明 |
|---------|------|
| `{doc}_middle.json` | MinerU 标准格式 JSON |
| `{doc}_enhanced.json` | 增强版 JSON(包含更多元数据)⭐ 新增 |
| `{doc}_page_001.json` | 每页独立 JSON(包含单元格坐标) |
| `{doc}_pdf_page_001.png` | PDF转换的页面图片 ⭐ 新增 |
| `{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 模式) |
| `{doc}_page_001_table_001_lines.png` | 有线表格线可视化 ⭐ 新增(wired debug) |
| `{doc}_page_001_table_001_grid.png` | 有线表格网格结构 ⭐ 新增(wired debug) |
| `{doc}_page_001_table_001_text.png` | 有线表格文本覆盖 ⭐ 新增(wired debug) |
| `{doc}_page_001_table_001_components.png` | 有线表格连通域 ⭐ 新增(wired debug) |
| `*_original.*` | 标准化前的原始文件(如有修改) |
**有线表格调试输出说明**:
- 当配置 `table_recognition_wired.debug_options.enabled: true` 时,会生成详细的可视化图片
- 这些图片帮助理解表格识别的各个处理阶段(表格线提取、网格恢复、文本填充等)
- 详细说明请参考:[有线表格识别技术文档.md](有线表格识别技术文档.md)
---
## 配置说明
配置文件采用 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"
```
### 4. DiT Layout (Document Image Transformer)
基于 Detectron2 的 DiT 模型,在 PubLayNet 数据集上训练。
```yaml
layout_detection:
module: "dit"
config_file: "dit_support/configs/cascade/cascade_dit_large.yaml"
model_weights: "path/to/model.pth"
device: "cpu"
conf: 0.3
```
支持类别:
text:正文文本
title:标题
list:列表
table:表格
figure:图片/图表
特点:
基于 Vision Transformer 架构
适合学术文档和出版物
需要 Detectron2 框架支持
---
## 类别映射
所有布局检测器的输出都会统一映射到 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` - 方向分类模型
### OCR Tools 组件(来自 ocr_tools.ocr_merger)⚠️
实际导入路径(**注意:不是 ocr_verify**):
```python
# 实际使用的导入路径
from ocr_tools.ocr_merger import TableCellMatcher, TextMatcher
# 模块位置:ocr_tools/ocr_merger/
├── table_cell_matcher.py # 单元格坐标匹配
├── text_matcher.py # 文本匹配
└── merger_core.py # 核心匹配算法
````
功能说明:
TableCellMatcher:将 OCR 检测框与 VLM 表格结构匹配,使用动态规划算法
TextMatcher:文本相似度匹配工具
o工具模块(已迁移到 ocr_utils)⚠️
输出工具已统一迁移到 ocr_utils 包,
```python
# 从 ocr_utils 重新导出
from ocr_utils import (
OutputFormatterV2, # 统一输出格式化器
JSONFormatters, # JSON格式化
MarkdownGenerator, # Markdown生成
HTMLGenerator, # HTML生成
VisualizationUtils, # 可视化工具
normalize_financial_numbers, # 金额标准化
)
```
优势:
. 统一管理所有输出工具
. 跨项目复用代码
. 更好的版本控制
其他依赖
. transformers - Docling 模型加载
. huggingface_hub - 模型下载
. detectron2 - DiT 模型推理 ⭐ 新增
. onnxruntime - ONNX 模型推理
. Pillow - 图像处理
. NumPy - 数值计算
. OpenCV (cv2) - 图像处理和表格线检测 ⭐
. BeautifulSoup4 - HTML 解析
. PyYAML - 配置文件解析
. loguru - 日志
---
### 安装依赖
```bash
# 基础依赖
pip install transformers huggingface_hub onnxruntime pillow numpy opencv-python beautifulsoup4 pyyaml loguru
# MinerU(必需)
pip install magic-pdf[full]
# OCR Merger(必需)
cd /path/to/ocr_tools && pip install -e .
# DiT支持(可选,如果使用DiT布局检测器)
pip install detectron2 -f https://dl.fbaipublicfiles.com/detectron2/wheels/cpu/torch2.0/index.html
```