参考 MinerU 实现的模型统一框架,针对金融场景设计。
框架采用模块化设计,各处理节点可根据不同场景灵活替换:
通过配置文件(YAML)即可切换不同的模型组合,无需修改代码。
无论使用何种模型组合,输出格式统一,确保下游处理的一致性:
middle.json(MinerU 标准格式)enhanced.json(包含更多元数据)针对不同业务场景(银行流水、财务报表等),提供预配置的配置文件:
bank_statement_*.yaml| 场景类型 | 特点 | 表格形式 |
|---|---|---|
| 银行交易流水 | 单栏列表形式,无合并单元格 | 有线表格 / 无线表格 |
| 财务报表 | 多栏列表形式,有合并单元格,表头复杂 | 有线表格 / 无线表格 |
| 模型类型 | 推荐模型 | 说明 |
|---|---|---|
| 方向分类 | PP-LCNet_x1_0_doc_ori | paddle onnx格式的模型 |
| 版式检测 | Docling Layout / DocLayout-YOLO | Docling 或 MinerU 模型 |
| 文字识别 | PaddleOCR (PyTorch) | 效果好,支持角度校正 |
| 表格分类 | PaddleTableClsModel | 自动区分有线/无线表格 ⭐ 新增 |
| 表格结构识别 | MinerU VLM / PaddleOCR-VL / UNET 有线表格 | VLM 返回 HTML 结构,UNet 返回单元格坐标 |
| 公式识别 | MinerU VLM | 返回 LaTeX |
| 单元格坐标匹配 | TableCellMatcher | OCR 检测框与 VLM 结构匹配 |
主流程采用模块化设计,各处理节点可根据场景配置替换:
graph TB
A[输入 PDF/图片] --> B[文档加载与分类]
B --> C[逐页处理<br/>详见单页处理流程]
C --> D[跨页表格合并]
D --> E[统一输出格式<br/>JSON/Markdown/HTML]
style C fill:#e1f5ff
style E fill:#fff4e1
classDef replaceable fill:#ffe1e1,stroke:#ff0000,stroke-width:2px
class B,C,D replaceable
关键特性:
可替换组件:
统一输出格式:
{doc}_middle.json:MinerU 标准格式(统一内部描述结构){doc}_enhanced.json:增强版格式(包含更多元数据){doc}_page_XXX.json:每页独立 JSON(包含单元格坐标){doc}.md / {doc}_page_XXX.md:Markdown 格式tables/*.html:表格 HTML(带 data-bbox 坐标)graph TB
A[输入:页面图像] --> B{PDF类型?}
B -->|扫描件| C[页面方向识别<br/>PP-LCNet]
B -->|文字PDF| C1[获取PDF页面rotation<br/>转换为rotate_angle并旋转图像]
C --> D[Layout 检测<br/>Docling/MinerU/DiT]
C1 --> D
D --> E[去重重叠框<br/>IoU过滤]
E --> F{大文本块转表格?}
F -->|是| G[面积占比判断<br/>转换为table类型]
F -->|否| H
G --> H
H --> H1{PDF类型?}
H1 -->|扫描件| H2[整页 OCR<br/>获取所有 text spans]
H1 -->|文字PDF| H3[PDF文本提取<br/>extract_all_text_blocks]
H3 --> H4{页面类型检测}
H4 -->|文字页| H5[使用PDF提取结果]
H4 -->|扫描页| H2
H3 -->|提取失败| H2
H2 --> I[Span 去重<br/>IoU过滤]
H5 --> I
I --> J[Span 排序<br/>从上到下、从左到右]
J --> K[Span-Block 匹配<br/>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 H2 fill:#e1f5ff
style H3 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
参考 MinerU 的处理方式,新流程采用 整页文本提取 → Span-Block 匹配 策略:
处理路径:
扫描件/图片:
文字PDF:
extract_all_text_blocks)detect_page_type)
后续处理(统一):
优势:
代码实现:
# 1. 根据PDF类型选择文本提取方式
if pdf_type == 'txt' and pdf_doc is not None:
# 文字PDF:从PDF提取文本块
actual_page_type = PDFUtils.detect_page_type(pdf_doc, page_idx)
if actual_page_type == 'txt':
all_text_spans, rotation = PDFUtils.extract_all_text_blocks(
pdf_doc, page_idx, scale=scale, return_upright_coords=True
)
all_text_spans = self._convert_pdf_blocks_to_spans(
all_text_spans, detection_image.shape
)
else:
# 扫描页,使用OCR
all_text_spans = self.ocr_recognizer.recognize_text(detection_image)
else:
# 扫描件:整页 OCR
all_text_spans = self.ocr_recognizer.recognize_text(detection_image)
# 2. 去除重复 spans
all_text_spans = SpanMatcher.remove_duplicate_spans(all_text_spans)
# 3. 按坐标排序
all_text_spans = self._sort_spans_by_position(all_text_spans)
# 4. 将 spans 匹配到 layout blocks
matched_spans = SpanMatcher.match_spans_to_blocks(
all_text_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)
新增功能:支持自动表格分类,根据表格类型自动选择识别器
graph TB
A[表格区域] --> B[表格 OCR 预处理]
subgraph OCR预处理
B --> B1[裁剪表格区域<br/>padding=10px]
B1 --> B2[表格方向检测<br/>PP-LCNet]
B2 --> B3{有整页OCR spans?}
B3 -->|是| B4[提取重叠spans<br/>转换坐标到裁剪区域]
B3 -->|否| B5[裁剪区域单独OCR<br/>兜底方案]
B4 --> B6[OCR框列表]
B5 --> B6
end
B6 --> C{启用表格分类?}
C -->|是| C1[表格分类器<br/>PaddleTableClsModel]
C1 --> C2{分类结果?}
C2 -->|wired| D[UNet 有线表格路径]
C2 -->|wireless| E[VLM 无线表格路径]
C -->|否| C3{手动配置?}
C3 -->|use_wired_unet=true| D
C3 -->|否| E
subgraph 有线表格路径
D --> D1[UNet 检测表格线<br/>横线 + 竖线]
D1 --> D2{启用倾斜矫正?}
D2 -->|是| D3[基于Mask检测倾斜角度<br/>Hough变换 + 矫正图片和OCR坐标]
D2 -->|否| D4
D3 --> D4[网格恢复<br/>grid_recovery.py]
D4 --> D4a[连通域提取单元格<br/>OCR边缘补偿]
D4a --> D5[边缘过滤<br/>edge_margin=padding×upscale×1.2]
D5 --> D6[文本填充<br/>text_filling.py]
D6 --> D7[二次OCR修正<br/>单元格裁剪OCR]
D7 --> D8[生成HTML<br/>data-bbox属性]
D8 --> D9{识别成功?}
D9 -->|否| E[自动Fallback到VLM]
D9 -->|是| F
end
subgraph 无线表格路径
E --> E1[VLM识别表格结构<br/>返回HTML]
E1 --> E2[TableCellMatcher匹配<br/>OCR框 + HTML结构]
E2 --> E3[生成增强HTML<br/>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
配置项:table_classification.enabled: true
启用后,系统会自动对每个表格进行分类,判断是有线表格还是无线表格:
PaddleTableClsModelwired:有线表格(带边框)→ 使用 UNet 识别wireless:无线表格(无边框)→ 使用 VLM 识别confidence_threshold: 0.5(可配置)优势:
无论使用哪种表格识别方法,都需要先进行OCR预处理:
padding=10px 保护边缘内容关键点:
pdf_type='txt'),会传递 pdf_type 参数,支持PDF字符提取作为OCR补充配置项:table_recognition_wired.use_wired_unet: true
处理步骤:
UNet表格线检测:
倾斜检测与矫正(可选,enable_deskew: true):
correction_angle = -detected_angle(反向旋转)网格恢复(grid_recovery.py):
边缘过滤:过滤padding区域的噪声线条
edge_margin = int(crop_padding × upscale × 1.2) # 例如:10 × 3.333 × 1.2 = 40px
合并距离过近的线条(row_threshold, col_threshold)
生成单元格网格
文本填充(text_filling.py):
ocr_conf_threshold)二次OCR修正(text_filling.py):
pdf_type='txt'),空文本单元格不触发二次OCR,为了解决文字PDF中误合并问题HTML生成:
data-bbox 属性记录单元格坐标坐标逆转换:
自动Fallback:
文字PDF支持:
pdf_type='txt' 参数到有线表格识别器pdf_type='txt'),空文本单元格不触发二次OCR,为了解决文字PDF中误合并问题关键配置:
# 表格分类配置(推荐启用)
table_classification:
enabled: true # 启用自动表格分类
module: "paddle" # 使用 PaddleTableClsModel
confidence_threshold: 0.5 # 分类置信度阈值
# 有线表格识别配置
table_recognition_wired:
use_wired_unet: true # 启用有线表格
upscale_ratio: 3.333 # 固定放大比例
enable_deskew: true # 启用倾斜矫正(基于Mask检测)
row_threshold: 10 # 行合并阈值(像素)
col_threshold: 15 # 列合并阈值(像素)
ocr_conf_threshold: 0.8 # OCR置信度阈值
use_custom_postprocess: true # 使用自定义后处理(支持OCR边缘补偿)
配置项:vl_recognition.module: "paddle" 或 "mineru"
处理步骤:
VLM结构识别:
TableCellMatcher匹配:
生成增强HTML:
data-bbox 属性坐标逆转换:
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<br/>兜底方案] --> M
style C fill:#e1f5ff
style D fill:#e1f5ff
处理优先级:
优先级1:使用预匹配的 spans(整页 OCR 结果)
优先级2:数字PDF字符提取
pdf_type='txt'优先级3:裁剪区域OCR(兜底方案)
代码实现:
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(保留备用) | ✅ |
处理过程中涉及多个坐标系的转换:
坐标转换流程:
原图坐标 → 检测图像坐标 → 裁剪区域坐标 → 放大坐标(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:PDF rotation |
扫描件使用PP-LCNet模型识别 文字PDF从PDF元数据获取rotation并旋转图像 |
| 表格区域 | - | 可选,VLM 有一定容忍度,OCR 自带角度校正 |
| 文本区域 | - | 不需要,OCR 自带校正 |
文字PDF方向处理:
rotation 角度rotate_angle 定义(图像需要逆时针旋转的角度)当Layout检测将大面积的表格区域误识别为文本框时,可以通过后处理自动转换:
判断规则:
配置示例:
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
| PDF 类型 | 文字块处理 | 表格处理 |
|---|---|---|
| 扫描件/图片 | 整页 OCR → Span 匹配 | OCR 检测(坐标) + 表格分类 → UNet/VLM(结构) |
| 数字原生 PDF(文字PDF) | 整页 OCR → Span 匹配 / PDF 字符提取 | OCR 检测(坐标) + 表格分类 → UNet/VLM(结构) + 单元格OCR修正(PDF字符提取优先) |
关键点:
默认参数(已优化,参考PPStructureV3):
det_threshold: 0.6(检测框置信度阈值,提高可减少噪声框)unclip_ratio: 1.5(检测框扩展比例,降低可提高框精确度)enable_merge_det_boxes: False(是否合并检测框,表格场景建议False)配置示例:
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参数,选择合适的配置可以显著提升识别效果:
| 配置文件 | 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 | 有线表格 | 平衡配置,兼顾精度与召回 |
参数选择建议:
det_threshold(检测阈值):
0.6:严格模式,适合高质量扫描件/数字PDF,减少噪声框和误检0.5:平衡模式,适合有线表格场景,兼顾精度和召回0.3:宽松模式,适合低质量扫描件,捕获更多文本但可能产生噪声unclip_ratio(扩展比例):
1.5:精确模式,检测框更贴近文本边界,减少相邻单元格干扰1.8:宽松模式,检测框扩大,避免文本截断但可能重叠enable_merge_det_boxes(合并框):
false:表格场景推荐,保持单元格独立性true:长文本场景,自动合并相邻文本框快速选择:
0.6 / 1.5 / false0.5 / 1.8 / false0.3 / 1.8 / false详细分析请参考:OCR识别差异分析与改进方案.md
universal_doc_parser/
├── __init__.py
├── main_v2.py # 命令行入口 ⭐
│
├── 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/
│ ├── __init__.py
│ ├── base.py # 适配器基类
│ ├── mineru_adapter.py # MinerU 适配器
│ ├── paddle_vl_adapter.py # PaddleOCR-VL 适配器
│ ├── paddle_layout_detector.py # PaddleX RT-DETR 布局检测器
│ ├── paddle_table_classifier.py # Paddle表格分类器 ⭐ 新增
│ ├── 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 # 可视化
│
├── dit_support/ # DiT 布局检测器支持模块 ⭐
│ ├── configs/ # DiT 配置文件
│ │ ├── Base-RCNN-FPN.yaml
│ │ └── cascade/
│ │ └── cascade_dit_large.yaml
│ ├── ditod/ # DiT 模型实现
│ │ ├── __init__.py
│ │ ├── backbone.py
│ │ ├── beit.py
│ │ ├── config.py
│ │ └── deit.py
│ └── README.md
│
├── utils/ # 输出工具模块(已迁移到 ocr_utils)⚠️
│ └── __init__.py # 仅作重新导出接口
│
└── tests/ # 测试模块
├── test_dit_layout_adapter.py # DiT 布局检测器测试
├── test_doclayoutyolo.py # DocLayout-YOLO 测试
├── test_layout_detector.py # 布局检测器测试
├── test_pdf_rotation.py # PDF 旋转测试
├── test_skew_correction.py # 倾斜矫正测试
├── test_table_routing.py # 表格路由测试
└── *.png # 测试图片文件
# 处理单个 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/
from core.pipeline_manager_v2 import EnhancedDocPipeline
from ocr_utils import OutputFormatterV2 # 从 ocr_utils 导入
# 初始化流水线
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, # 金额标准化
})
对于大文档或内存受限场景,使用流式处理模式:
# 命令行添加 --streaming 参数
python main_v2.py -i large_document.pdf -c config.yaml --streaming -o ./output
流式处理特点:
✅ 按页处理:每处理完一页立即保存结果,不累积在内存中 ✅ 内存占用低:适合处理数百页的大文档 ✅ 容错性好:某页处理失败不影响已保存的页面 ✅ 输出一致:与批量模式输出格式完全一致 适用场景:
处理超过50页的大型PDF文档 服务器内存受限(如4GB以下) 需要实时查看处理进度
核心原则:无论使用何种模型组合,输出格式统一,确保下游处理的一致性。
| 输出文件 | 格式说明 | 用途 |
|---|---|---|
{doc}_middle.json |
MinerU 标准格式(统一内部描述结构) | 标准输出,兼容 MinerU 生态 |
{doc}_enhanced.json |
增强版 JSON(包含更多元数据)⭐ | 包含识别方法、置信度等详细信息 |
{doc}_page_001.json |
每页独立 JSON(包含单元格坐标) | 按页输出,包含精确坐标信息 |
{doc}.md |
完整文档 Markdown | 人类可读格式 |
{doc}_page_001.md |
每页独立 Markdown(带坐标注释) | 按页 Markdown,便于检查 |
tables/*.html |
表格 HTML(带 data-bbox 坐标) |
表格结构化输出,包含单元格坐标 |
images/ |
提取的图片元素 | 图片资源 |
| 输出文件 | 说明 | 启用条件 |
|---|---|---|
{doc}_pdf_page_001.png |
PDF转换的页面图片 | output.save_pdf_images: true |
{doc}_page_001_layout.png |
Layout 可视化图片 | output.save_layout_image: true |
{doc}_page_001_ocr.png |
OCR 可视化图片 | output.save_ocr_image: true |
{doc}_page_001_table_001_lines.png |
有线表格线可视化 | table_recognition_wired.debug_options.enabled: true |
{doc}_page_001_table_001_grid.png |
有线表格网格结构 | table_recognition_wired.debug_options.enabled: true |
{doc}_page_001_table_001_text.png |
有线表格文本覆盖 | table_recognition_wired.debug_options.enabled: true |
{doc}_page_001_table_001_components.png |
有线表格连通域 | table_recognition_wired.debug_options.enabled: true |
{doc}_page_001_table_001_paddle_table_lines.png |
表格分类线条检测可视化 | table_classification.debug_options.enabled: true |
有线表格调试输出说明:
table_recognition_wired.debug_options.enabled: true 时,会生成详细的可视化图片表格分类调试输出说明:
table_classification.debug_options.enabled: true 时,会生成表格线检测可视化图片配置文件采用 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"
# 表格分类配置(自动区分有线/无线表格)
table_classification:
enabled: true # 是否启用自动表格分类(默认关闭,使用手动配置)
module: "paddle" # 分类模型:paddle(MinerU PaddleTableClsModel)
confidence_threshold: 0.5 # 分类置信度阈值
batch_size: 16 # 批处理大小
debug_options:
enabled: false # 是否开启调试可视化输出
save_table_lines: true # 保存表格线可视化
# 有线表格识别配置
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置信度阈值
debug_options:
enabled: false # 是否开启调试可视化输出
save_table_lines: true # 保存表格线可视化
save_connected_components: true # 保存连通域提取的单元格图
save_grid_structure: true # 保存逻辑网格结构
save_text_overlay: true # 保存文本填充覆盖图
# 输出配置
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 # 金额数字标准化
框架采用适配器模式,各组件可根据场景灵活替换。通过修改配置文件即可切换,无需修改代码。
支持多种布局检测模型,通过 layout_detection.module 配置切换:
基于 HuggingFace transformers 的 RT-DETR 模型。
layout_detection:
module: "docling"
model_name: "docling-layout-old"
model_dir: "ds4sd/docling-layout-old"
支持的模型:
ds4sd/docling-layout-oldds4sd/docling-layout-heronds4sd/docling-layout-egret-mediumds4sd/docling-layout-egret-large基于 ONNX Runtime 的 PaddleX 布局检测器。
layout_detection:
module: "paddle"
model_name: "RT-DETR-H_layout_17cls"
model_dir: "/path/to/RT-DETR-H_layout_17cls.onnx"
MinerU 内置的布局检测模型。
layout_detection:
module: "mineru"
model_name: "layout"
基于 Detectron2 的 DiT 模型,在 PubLayNet 数据集上训练。
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 架构,适合学术文档和出版物
通过 ocr_recognition.module 配置切换:
module: "mineru"module: "paddle"(需配置模型路径)通过 table_classification.module 配置:
module: "paddle"(自动区分有线/无线表格)通过 table_recognition_wired.use_wired_unet 配置:
use_wired_unet: true(MinerU UNet模型)通过 vl_recognition.module 配置:
module: "mineru"module: "paddle"(需配置服务地址)后端支持:
backend: "http-client":HTTP 客户端backend: "vllm-engine":vLLM 引擎backend: "transformers":Transformers 库通过 vl_recognition.module 配置(与无线表格共享):
module: "mineru"module: "paddle"preprocessor.module: "mineru")配置示例:见 config/bank_statement_*.yaml 文件
所有布局检测器的输出都会统一映射到 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 |
pipeline_manager_v2.py)主流水线管理器,实现完整处理流程:
layout_utils.py)OCR Span 与 Layout Block 匹配器,参考 MinerU 实现:
match_spans_to_blocks() - 将 spans 匹配到对应的 blocksmerge_spans_to_text() - 将多个 spans 合并为文本remove_duplicate_spans() - 去除重复 spanspoly_to_bbox() - 多边形坐标转 bboxelement_processors.py)元素处理器,处理不同类型的元素:
process_text_element() - 文本处理(支持 pre_matched_spans)process_table_element_wired() - 有线表格处理(UNet + OCR 坐标匹配,支持文字PDF)process_table_element_vlm() - 无线表格处理(VLM + OCR 坐标匹配)process_image_element() - 图片处理process_equation_element() - 公式处理process_code_element() - 代码处理process_discard_element() - 丢弃元素处理(支持 pre_matched_spans)paddle_table_classifier.py) ⭐ 新增表格分类器,自动区分有线表格和无线表格:
classify() - 分类单个表格图像batch_classify() - 批量分类表格图像PaddleTableClsModel 进行分类paddle_table_classifier.py) ⭐ 新增表格分类器,自动区分有线表格和无线表格:
classify() - 分类单个表格图像batch_classify() - 批量分类表格图像PaddleTableClsModel 进行分类wired(有线表格)或 wireless(无线表格)ocr_utils)统一输出格式化器,位于 ocr_utils 包中:
导入方式:
from ocr_utils import OutputFormatterV2
merger)表格单元格坐标匹配器:
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_merger)⚠️实际导入路径(注意:不是 ocr_verify):
# 实际使用的导入路径
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:文本相似度匹配工具ocr_utils)⭐定位:统一的OCR工具包,提供文档处理相关的工具函数,支持跨项目复用。
主要模块:
| 模块 | 功能 | 说明 |
|---|---|---|
OutputFormatterV2 |
统一输出格式化器 | 生成 JSON、Markdown、HTML 等格式 |
JSONFormatters |
JSON 格式化工具 | 格式化 MinerU 标准 JSON、增强 JSON 等 |
MarkdownGenerator |
Markdown 生成器 | 生成完整文档和按页 Markdown |
HTMLGenerator |
HTML 生成器 | 生成表格 HTML(带 data-bbox 坐标) |
VisualizationUtils |
可视化工具 | Layout、OCR 可视化图片生成 |
normalize_financial_numbers |
金额标准化 | 金融数字标准化(金额、百分比等) |
PDFUtils |
PDF 处理工具 | PDF 文本提取、坐标转换等 |
BBoxExtractor |
边界框提取器 | 从 HTML 等格式提取边界框 |
file_utils |
文件处理工具 | 文件列表处理、PDF 转图片等 |
image_utils |
图像处理工具 | 图像解码、预处理、坐标转换等 |
html_utils |
HTML 处理工具 | HTML 表格解析、图片处理等 |
number_utils |
数字解析工具 | 数字解析和标准化 |
导入示例:
# 主要输出工具
from ocr_utils import (
OutputFormatterV2, # 统一输出格式化器
JSONFormatters, # JSON格式化
MarkdownGenerator, # Markdown生成
HTMLGenerator, # HTML生成
VisualizationUtils, # 可视化工具
normalize_financial_numbers, # 金额标准化
)
# PDF 工具(延迟导入)
from ocr_utils import PDFUtils, BBoxExtractor
# 文件工具
from ocr_utils import (
get_input_files,
convert_pdf_to_images,
parse_page_range
)
优势:
其他依赖 . transformers - Docling 模型加载 . huggingface_hub - 模型下载 . detectron2 - DiT 模型推理 ⭐ 新增 . onnxruntime - ONNX 模型推理 . Pillow - 图像处理 . NumPy - 数值计算 . OpenCV (cv2) - 图像处理和表格线检测 ⭐ . BeautifulSoup4 - HTML 解析 . PyYAML - 配置文件解析 . loguru - 日志
# 基础依赖
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