|
|
@@ -13,83 +13,117 @@
|
|
|
|
|
|
| 模型类型 | 推荐模型 | 说明 |
|
|
|
|---------|---------|------|
|
|
|
-| **版式检测** | Docling Layout / DocLayout-YOLO | HuggingFace 或 MinerU 模型 |
|
|
|
+| **方向分类** | PP-LCNet_x1_0_doc_ori | paddle onnx格式的模型 |
|
|
|
+| **版式检测** | Docling Layout / DocLayout-YOLO | Docling 或 MinerU 模型 |
|
|
|
| **文字识别** | PaddleOCR (PyTorch) | 效果好,支持角度校正 |
|
|
|
-| **表格结构识别** | MinerU VLM / PaddleOCR-VL | VLM 返回 HTML 结构 |
|
|
|
+| **表格结构识别** | MinerU VLM / PaddleOCR-VL / UNET 有线表格 | VLM 返回 HTML 结构 |
|
|
|
| **公式识别** | MinerU VLM | 返回 LaTeX |
|
|
|
-| **方向识别** | PP-LCNet | 沿用 MinerU 实现 |
|
|
|
| **单元格坐标匹配** | TableCellMatcher | OCR 检测框与 VLM 结构匹配 |
|
|
|
|
|
|
---
|
|
|
|
|
|
## 处理流程
|
|
|
|
|
|
+### 主流程图
|
|
|
+
|
|
|
```mermaid
|
|
|
graph TB
|
|
|
- A[输入 PDF/图片] --> B{PDF 分类}
|
|
|
-
|
|
|
- B -->|扫描件/图片| C1[页面方向识别<br/>PP-LCNet]
|
|
|
- B -->|数字原生PDF| D
|
|
|
- C1 --> D[Layout 检测<br/>去重叠框]
|
|
|
-
|
|
|
- D --> E[整页 OCR<br/>获取所有 text spans]
|
|
|
- E --> F[Span-Block 匹配<br/>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
|
|
|
+ A[输入 PDF/图片] --> B[加载文档并分类]
|
|
|
|
|
|
- subgraph 表格处理
|
|
|
- I --> I1[OCR 检测<br/>获取文本框坐标]
|
|
|
- I --> I2[VLM 结构识别<br/>返回 HTML]
|
|
|
- I1 --> I3[坐标匹配<br/>TableCellMatcher]
|
|
|
- I2 --> I3
|
|
|
- I3 --> I4[带坐标的表格]
|
|
|
- end
|
|
|
+ B --> C{文档类型?}
|
|
|
+ C -->|PDF| D[PDF分类: 扫描件/数字原生]
|
|
|
+ C -->|图片目录| E[加载所有图片]
|
|
|
|
|
|
- subgraph 图片处理
|
|
|
- J --> J1[裁剪保存]
|
|
|
- end
|
|
|
+ D --> F[处理每一页]
|
|
|
+ E --> F
|
|
|
|
|
|
- subgraph 公式处理
|
|
|
- K --> K1[VLM 识别<br/>返回 LaTeX]
|
|
|
- end
|
|
|
+ F --> G[页面方向识别<br/>仅扫描件]
|
|
|
+ G --> H[Layout 检测]
|
|
|
|
|
|
- subgraph 丢弃元素
|
|
|
- L --> L1{有匹配的spans?}
|
|
|
- L1 -->|是| L2[合并 spans 文本]
|
|
|
- L1 -->|否| L3[裁剪区域 OCR]
|
|
|
- L2 --> L4[保留备用]
|
|
|
- L3 --> L4
|
|
|
- end
|
|
|
+ H --> I[去重重叠框]
|
|
|
+ I --> J{大文本块转表格?}
|
|
|
+ J -->|启用| K[后处理转换]
|
|
|
+ J -->|否| L
|
|
|
+ K --> L[整页 OCR<br/>获取所有 text spans]
|
|
|
+
|
|
|
+ L --> M[Span 去重与排序]
|
|
|
+ M --> N[Span-Block 匹配<br/>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类型?}
|
|
|
|
|
|
- H7 --> M[合并所有结果]
|
|
|
- I4 --> M
|
|
|
- J1 --> M
|
|
|
- K1 --> M
|
|
|
- L4 --> M
|
|
|
-
|
|
|
- M --> N[按阅读顺序排序]
|
|
|
- N --> O[坐标转换回原图]
|
|
|
- O --> P[合并跨页表格]
|
|
|
- P --> Q[金额数字标准化]
|
|
|
- Q --> R[多格式输出]
|
|
|
+ B -->|扫描件| C[页面方向识别<br/>PP-LCNet]
|
|
|
+ B -->|数字PDF| D
|
|
|
+ C --> D[Layout 检测<br/>Docling/MinerU/DiT]
|
|
|
+
|
|
|
+ D --> E[去重重叠框<br/>IoU过滤]
|
|
|
+ E --> F{大文本块转表格?}
|
|
|
+
|
|
|
+ F -->|是| G[面积占比判断<br/>转换为table类型]
|
|
|
+ F -->|否| H
|
|
|
+ G --> H[整页 OCR<br/>获取所有 text spans]
|
|
|
+
|
|
|
+ H --> I[Span 去重<br/>IoU过滤]
|
|
|
+ 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 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 匹配
|
|
|
@@ -98,15 +132,297 @@ graph TB
|
|
|
|
|
|
1. **整页 OCR**:先对整个页面进行 OCR,获取所有 text spans(包含坐标和文本)
|
|
|
2. **Span 去重**:移除高 IoU 重叠的 spans,保留置信度高的
|
|
|
-3. **Span-Block 匹配**:将 OCR spans 按重叠比例匹配到对应的 layout blocks
|
|
|
-4. **文本合并**:将匹配到同一 block 的 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[裁剪表格区域<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 -->|是| D[UNet 有线表格路径]
|
|
|
+ C -->|否| E[VLM 无线表格路径]
|
|
|
+
|
|
|
+ subgraph 有线表格路径
|
|
|
+ D --> D1[UNet 检测表格线<br/>横线 + 竖线]
|
|
|
+ D1 --> D2{启用倾斜矫正?}
|
|
|
+ D2 -->|是| D3[Hough变换检测角度<br/>矫正图片和OCR坐标]
|
|
|
+ D2 -->|否| D4
|
|
|
+ D3 --> D4[网格恢复<br/>grid_recovery.py]
|
|
|
+ D4 --> D5[边缘过滤<br/>edge_margin=padding×upscale×1.2]
|
|
|
+ D5 --> D6[文本填充<br/>text_filling.py]
|
|
|
+ D6 --> D7[生成HTML<br/>data-bbox属性]
|
|
|
+ D7 --> D8{识别成功?}
|
|
|
+ D8 -->|否| E[自动Fallback到VLM]
|
|
|
+ D8 -->|是| 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
|
|
|
+```
|
|
|
+
|
|
|
+#### 表格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<br/>兜底方案] --> 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放大
|
|
|
+ ↓ ↓ ↓
|
|
|
+ 逆向转换 逆向转换 逆向转换
|
|
|
+```
|
|
|
+
|
|
|
+所有处理完成后,坐标统一转换回**原图坐标系**,确保输出一致性。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
### 元素分类说明
|
|
|
|
|
|
| 元素类别 | 包含类型 | 处理方式 |
|
|
|
@@ -183,10 +499,36 @@ ocr:
|
|
|
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 参数实际使用对比
|
|
|
+
|
|
|
+不同配置文件针对不同场景优化了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`
|
|
|
|
|
|
@@ -196,39 +538,51 @@ ocr:
|
|
|
|
|
|
```
|
|
|
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 # 模型工厂
|
|
|
+├── 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)⭐ 新增
|
|
|
│
|
|
|
-├── 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 布局检测器 ⭐
|
|
|
+├── 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 # 模型工厂
|
|
|
│
|
|
|
-├── 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 # 本文档
|
|
|
+├── 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 # 本文档
|
|
|
```
|
|
|
|
|
|
---
|
|
|
@@ -274,6 +628,26 @@ with EnhancedDocPipeline("config/bank_statement_yusys_v2.yaml") as pipeline:
|
|
|
})
|
|
|
```
|
|
|
|
|
|
+### 流式处理模式
|
|
|
+
|
|
|
+对于大文档或内存受限场景,使用流式处理模式:
|
|
|
+
|
|
|
+```bash
|
|
|
+# 命令行添加 --streaming 参数
|
|
|
+python main_v2.py -i large_document.pdf -c config.yaml --streaming -o ./output
|
|
|
+```
|
|
|
+流式处理特点:
|
|
|
+
|
|
|
+✅ 按页处理:每处理完一页立即保存结果,不累积在内存中
|
|
|
+✅ 内存占用低:适合处理数百页的大文档
|
|
|
+✅ 容错性好:某页处理失败不影响已保存的页面
|
|
|
+✅ 输出一致:与批量模式输出格式完全一致
|
|
|
+适用场景:
|
|
|
+
|
|
|
+处理超过50页的大型PDF文档
|
|
|
+服务器内存受限(如4GB以下)
|
|
|
+需要实时查看处理进度
|
|
|
+
|
|
|
---
|
|
|
|
|
|
## 输出文件说明
|
|
|
@@ -281,15 +655,26 @@ with EnhancedDocPipeline("config/bank_statement_yusys_v2.yaml") as pipeline:
|
|
|
| 输出文件 | 说明 |
|
|
|
|---------|------|
|
|
|
| `{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)
|
|
|
+
|
|
|
---
|
|
|
|
|
|
## 配置说明
|
|
|
@@ -385,6 +770,31 @@ layout_detection:
|
|
|
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 框架支持
|
|
|
+
|
|
|
---
|
|
|
|
|
|
## 类别映射
|
|
|
@@ -461,61 +871,67 @@ OCR Span 与 Layout Block 匹配器,参考 MinerU 实现:
|
|
|
- `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 模块
|
|
|
+### OCR Tools 组件(来自 ocr_tools.ocr_merger)⚠️
|
|
|
|
|
|
-```bash
|
|
|
-# 1. 进入 ocr_verify 目录
|
|
|
-cd /Users/zhch158/workspace/repository.git/ocr_verify
|
|
|
+实际导入路径(**注意:不是 ocr_verify**):
|
|
|
|
|
|
-# 2. 安装 merger 模块(可编辑模式)
|
|
|
-pip uninstall -y merger && pip install -e .
|
|
|
+```python
|
|
|
+# 实际使用的导入路径
|
|
|
+from ocr_tools.ocr_merger import TableCellMatcher, TextMatcher
|
|
|
|
|
|
-# 3. 验证安装
|
|
|
-python3 -c "from merger.table_cell_matcher import TableCellMatcher; print('✅ 安装成功')"
|
|
|
-```
|
|
|
+# 模块位置:ocr_tools/ocr_merger/
|
|
|
+├── table_cell_matcher.py # 单元格坐标匹配
|
|
|
+├── text_matcher.py # 文本匹配
|
|
|
+└── merger_core.py # 核心匹配算法
|
|
|
+````
|
|
|
+功能说明:
|
|
|
|
|
|
-完成后,在任何 Python 文件中都可以直接导入:
|
|
|
+TableCellMatcher:将 OCR 检测框与 VLM 表格结构匹配,使用动态规划算法
|
|
|
+TextMatcher:文本相似度匹配工具
|
|
|
|
|
|
+o工具模块(已迁移到 ocr_utils)⚠️
|
|
|
+输出工具已统一迁移到 ocr_utils 包,
|
|
|
```python
|
|
|
-from merger.table_cell_matcher import TableCellMatcher
|
|
|
-from merger.text_matcher import TextMatcher
|
|
|
-from merger.bbox_extractor import BBoxExtractor
|
|
|
+# 从 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
|
|
|
|
|
|
-```
|
|
|
-/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/ # 配置文件
|
|
|
-```
|
|
|
+# 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
|
|
|
+```
|