|
|
@@ -0,0 +1,650 @@
|
|
|
+# OCR 结果合并工具说明
|
|
|
+
|
|
|
+## 概述
|
|
|
+
|
|
|
+本工具包用于合并不同 OCR 工具的识别结果,主要功能是将结构化识别结果(如 MinerU、PaddleOCR_VL)与精确文字框坐标(PaddleOCR)进行合并,生成包含完整 bbox 信息的增强版 Markdown 和 JSON 文件。
|
|
|
+
|
|
|
+## 支持的合并方式
|
|
|
+
|
|
|
+### 1. MinerU + PaddleOCR
|
|
|
+- **输入**:
|
|
|
+ - MinerU 的 JSON 文件(包含表格结构、段落等)
|
|
|
+ - PaddleOCR 的 JSON 文件(包含精确的文字框坐标)
|
|
|
+- **输出**:
|
|
|
+ - 增强的 Markdown(包含 bbox 注释)
|
|
|
+ - 合并的 JSON(MinerU 格式 + bbox 信息)
|
|
|
+
|
|
|
+### 2. PaddleOCR_VL + PaddleOCR
|
|
|
+- **输入**:
|
|
|
+ - PaddleOCR_VL 的 JSON 文件(包含版面分析、表格识别等)
|
|
|
+ - PaddleOCR 的 JSON 文件(包含精确的文字框坐标)
|
|
|
+- **输出**:
|
|
|
+ - 增强的 Markdown(包含 bbox 注释)
|
|
|
+ - 合并的 JSON(转换为 MinerU 格式 + bbox 信息)
|
|
|
+
|
|
|
+## 目录结构
|
|
|
+
|
|
|
+```
|
|
|
+merger/
|
|
|
+├── __init__.py # 包初始化文件
|
|
|
+├── merger_core.py # MinerU 合并器核心类
|
|
|
+├── paddleocr_vl_merger.py # PaddleOCR_VL 合并器核心类
|
|
|
+├── merge_mineru_paddle_ocr.py # MinerU + PaddleOCR 主程序
|
|
|
+├── merge_paddleocr_vl_paddleocr.py # PaddleOCR_VL + PaddleOCR 主程序
|
|
|
+├── text_matcher.py # 文本匹配模块(共用)
|
|
|
+├── bbox_extractor.py # Bbox 提取模块(共用)
|
|
|
+├── data_processor.py # 数据处理模块(共用)
|
|
|
+├── markdown_generator.py # Markdown 生成模块(共用)
|
|
|
+└── README.md # 本说明文档
|
|
|
+```
|
|
|
+
|
|
|
+## 核心模块说明
|
|
|
+
|
|
|
+### 1. 合并器类
|
|
|
+
|
|
|
+#### `MinerUPaddleOCRMerger` (merger_core.py)
|
|
|
+```python
|
|
|
+class MinerUPaddleOCRMerger:
|
|
|
+ """MinerU 和 PaddleOCR 结果合并器"""
|
|
|
+
|
|
|
+ def __init__(self, look_ahead_window: int = 10,
|
|
|
+ similarity_threshold: int = 90):
|
|
|
+ """
|
|
|
+ Args:
|
|
|
+ look_ahead_window: 向前查找的窗口大小
|
|
|
+ similarity_threshold: 文本相似度阈值(0-100)
|
|
|
+ """
|
|
|
+
|
|
|
+ def merge_table_with_bbox(self, mineru_json_path: str,
|
|
|
+ paddle_json_path: str) -> List[Dict]:
|
|
|
+ """合并 MinerU 和 PaddleOCR 的结果"""
|
|
|
+
|
|
|
+ def generate_enhanced_markdown(self, merged_data: List[Dict],
|
|
|
+ output_path: str = None) -> str:
|
|
|
+ """生成增强的 Markdown"""
|
|
|
+```
|
|
|
+
|
|
|
+#### `PaddleOCRVLMerger` (paddleocr_vl_merger.py)
|
|
|
+```python
|
|
|
+class PaddleOCRVLMerger:
|
|
|
+ """PaddleOCR_VL 和 PaddleOCR 结果合并器"""
|
|
|
+
|
|
|
+ def __init__(self, look_ahead_window: int = 10,
|
|
|
+ similarity_threshold: int = 90):
|
|
|
+ """
|
|
|
+ Args:
|
|
|
+ look_ahead_window: 向前查找的窗口大小
|
|
|
+ similarity_threshold: 文本相似度阈值(0-100)
|
|
|
+ """
|
|
|
+
|
|
|
+ def merge_table_with_bbox(self, paddleocr_vl_json_path: str,
|
|
|
+ paddle_json_path: str) -> List[Dict]:
|
|
|
+ """合并 PaddleOCR_VL 和 PaddleOCR 的结果"""
|
|
|
+
|
|
|
+ def generate_enhanced_markdown(self, merged_data: List[Dict],
|
|
|
+ output_path: str = None,
|
|
|
+ data_format: str = None) -> str:
|
|
|
+ """生成增强的 Markdown"""
|
|
|
+```
|
|
|
+
|
|
|
+### 2. 共用模块
|
|
|
+
|
|
|
+#### `TextMatcher` (text_matcher.py)
|
|
|
+负责文本匹配,找到 MinerU/PaddleOCR_VL 文本在 PaddleOCR 结果中的对应位置。
|
|
|
+
|
|
|
+**核心方法**:
|
|
|
+```python
|
|
|
+def find_matching_bbox(self, target_text: str,
|
|
|
+ text_boxes: List[Dict],
|
|
|
+ start_index: int = 0,
|
|
|
+ last_match_index: int = 0,
|
|
|
+ look_ahead_window: int = 10) -> Tuple[Optional[Dict], int, int]:
|
|
|
+ """
|
|
|
+ 查找匹配的 bbox
|
|
|
+
|
|
|
+ Args:
|
|
|
+ target_text: 目标文本
|
|
|
+ text_boxes: PaddleOCR 文字框列表
|
|
|
+ start_index: 开始搜索的位置
|
|
|
+ last_match_index: 上一次匹配的索引
|
|
|
+ look_ahead_window: 向前查找窗口大小
|
|
|
+
|
|
|
+ Returns:
|
|
|
+ (匹配的文字框, 新的开始位置, 新的last_match_index)
|
|
|
+ """
|
|
|
+```
|
|
|
+
|
|
|
+**匹配策略**:
|
|
|
+1. **顺序匹配**:优先从 `start_index` 开始顺序查找
|
|
|
+2. **窗口回溯**:在 `[last_match_index - look_ahead_window, last_match_index + look_ahead_window]` 范围内查找
|
|
|
+3. **相似度计算**:使用 `fuzzywuzzy` 计算文本相似度
|
|
|
+4. **指针更新**:匹配成功后更新指针,避免重复匹配
|
|
|
+
|
|
|
+#### `BBoxExtractor` (bbox_extractor.py)
|
|
|
+负责从 PaddleOCR 结果中提取文字框信息。
|
|
|
+
|
|
|
+**核心方法**:
|
|
|
+```python
|
|
|
+def extract_paddle_text_boxes(self, paddle_data: Dict) -> List[Dict]:
|
|
|
+ """
|
|
|
+ 提取 PaddleOCR 的文字框信息
|
|
|
+
|
|
|
+ Returns:
|
|
|
+ [
|
|
|
+ {
|
|
|
+ 'text': '文本内容',
|
|
|
+ 'bbox': [x1, y1, x2, y2],
|
|
|
+ 'score': 0.99,
|
|
|
+ 'used': False
|
|
|
+ },
|
|
|
+ ...
|
|
|
+ ]
|
|
|
+ """
|
|
|
+
|
|
|
+def extract_table_cells_with_bbox(self, merged_data: List[Dict]) -> List[Dict]:
|
|
|
+ """
|
|
|
+ 提取所有表格单元格及其 bbox 信息
|
|
|
+
|
|
|
+ Returns:
|
|
|
+ [
|
|
|
+ {
|
|
|
+ 'text': '单元格文本',
|
|
|
+ 'bbox': [x1, y1, x2, y2],
|
|
|
+ 'table_index': 0,
|
|
|
+ 'row': 1,
|
|
|
+ 'col': 2
|
|
|
+ },
|
|
|
+ ...
|
|
|
+ ]
|
|
|
+ """
|
|
|
+```
|
|
|
+
|
|
|
+#### `DataProcessor` (data_processor.py)
|
|
|
+负责处理 MinerU/PaddleOCR_VL 数据,添加 bbox 信息。
|
|
|
+
|
|
|
+**核心方法**:
|
|
|
+```python
|
|
|
+def process_mineru_data(self, mineru_data: List[Dict],
|
|
|
+ paddle_text_boxes: List[Dict]) -> List[Dict]:
|
|
|
+ """
|
|
|
+ 处理 MinerU 数据,添加 bbox 信息
|
|
|
+
|
|
|
+ 处理类型:
|
|
|
+ - text: 普通文本
|
|
|
+ - title: 标题
|
|
|
+ - table: 表格
|
|
|
+ - list: 列表
|
|
|
+ - image: 图片
|
|
|
+ - equation: 公式
|
|
|
+ """
|
|
|
+
|
|
|
+def process_paddleocr_vl_data(self, paddleocr_vl_data: Dict,
|
|
|
+ paddle_text_boxes: List[Dict]) -> List[Dict]:
|
|
|
+ """
|
|
|
+ 处理 PaddleOCR_VL 数据,添加 bbox 信息
|
|
|
+
|
|
|
+ 处理类型:
|
|
|
+ - paragraph_title: 段落标题
|
|
|
+ - figure_title: 图片标题
|
|
|
+ - text: 文本
|
|
|
+ - table: 表格
|
|
|
+ - figure: 图片
|
|
|
+ - equation: 公式
|
|
|
+ - reference: 参考文献
|
|
|
+ """
|
|
|
+```
|
|
|
+
|
|
|
+**表格处理逻辑**:
|
|
|
+1. 解析 HTML 表格结构
|
|
|
+2. 逐个单元格匹配 PaddleOCR 文字框
|
|
|
+3. 为每个 `<td>` 添加 `data-bbox`、`data-paddle-index`、`data-score` 属性
|
|
|
+4. 处理合并单元格(colspan、rowspan)
|
|
|
+
|
|
|
+#### `MarkdownGenerator` (markdown_generator.py)
|
|
|
+负责将合并后的数据生成 Markdown 文件。
|
|
|
+
|
|
|
+**核心特性**:
|
|
|
+- **自动格式检测**:自动识别 MinerU 或 PaddleOCR_VL 格式
|
|
|
+- **bbox 注释**:为每个元素添加 `<!-- bbox: [x1, y1, x2, y2] -->` 注释
|
|
|
+- **表格增强**:保留表格中的 bbox 属性
|
|
|
+- **图片处理**:自动复制图片文件
|
|
|
+
|
|
|
+**核心方法**:
|
|
|
+```python
|
|
|
+def detect_data_format(merged_data: List[Dict]) -> str:
|
|
|
+ """
|
|
|
+ 检测数据格式
|
|
|
+
|
|
|
+ Returns:
|
|
|
+ 'mineru' 或 'paddleocr_vl'
|
|
|
+ """
|
|
|
+
|
|
|
+def generate_enhanced_markdown(merged_data: List[Dict],
|
|
|
+ output_path: Optional[str] = None,
|
|
|
+ source_file: Optional[str] = None,
|
|
|
+ data_format: Optional[str] = None) -> str:
|
|
|
+ """
|
|
|
+ 生成增强的 Markdown
|
|
|
+
|
|
|
+ Args:
|
|
|
+ merged_data: 合并后的数据
|
|
|
+ output_path: 输出路径
|
|
|
+ source_file: 源文件路径(用于复制图片)
|
|
|
+ data_format: 数据格式,None 则自动检测
|
|
|
+ """
|
|
|
+```
|
|
|
+
|
|
|
+**格式化方法**:
|
|
|
+- **MinerU 格式**:`_format_mineru_*()` 系列方法
|
|
|
+- **PaddleOCR_VL 格式**:`_format_paddleocr_vl_*()` 系列方法
|
|
|
+- **通用方法**:`_format_equation()`, `_format_metadata()` 等
|
|
|
+
|
|
|
+## 使用方法
|
|
|
+
|
|
|
+### 1. MinerU + PaddleOCR 合并
|
|
|
+
|
|
|
+#### 命令行使用
|
|
|
+
|
|
|
+```bash
|
|
|
+# 单文件处理
|
|
|
+python merger/merge_mineru_paddle_ocr.py \
|
|
|
+ --mineru-file /path/to/mineru_page_001.json \
|
|
|
+ --paddle-file /path/to/paddle_page_001.json \
|
|
|
+ --output-dir /path/to/output \
|
|
|
+ --format both
|
|
|
+
|
|
|
+# 批量处理
|
|
|
+python merger/merge_mineru_paddle_ocr.py \
|
|
|
+ --mineru-dir /path/to/mineru_results \
|
|
|
+ --paddle-dir /path/to/paddle_results \
|
|
|
+ --output-dir /path/to/output \
|
|
|
+ --format both \
|
|
|
+ --window 15 \
|
|
|
+ --threshold 85
|
|
|
+```
|
|
|
+
|
|
|
+#### 参数说明
|
|
|
+
|
|
|
+| 参数 | 说明 | 默认值 |
|
|
|
+|------|------|--------|
|
|
|
+| `--mineru-file` | MinerU JSON 文件路径(单文件模式) | - |
|
|
|
+| `--paddle-file` | PaddleOCR JSON 文件路径(单文件模式) | - |
|
|
|
+| `--mineru-dir` | MinerU 结果目录(批量模式) | - |
|
|
|
+| `--paddle-dir` | PaddleOCR 结果目录(批量模式) | - |
|
|
|
+| `-o, --output-dir` | 输出目录(必需) | - |
|
|
|
+| `-f, --format` | 输出格式:json/markdown/both | both |
|
|
|
+| `-w, --window` | 向前查找窗口大小 | 15 |
|
|
|
+| `-t, --threshold` | 文本相似度阈值(0-100) | 80 |
|
|
|
+
|
|
|
+
|
|
|
+### 2. PaddleOCR_VL + PaddleOCR 合并
|
|
|
+
|
|
|
+#### 命令行使用
|
|
|
+
|
|
|
+```bash
|
|
|
+# 单文件处理
|
|
|
+python merger/merge_paddleocr_vl_paddleocr.py \
|
|
|
+ --paddleocr-vl-file /path/to/paddleocr_vl_page_001.json \
|
|
|
+ --paddle-file /path/to/paddle_page_001.json \
|
|
|
+ --output-dir /path/to/output \
|
|
|
+ --format both
|
|
|
+
|
|
|
+# 批量处理
|
|
|
+python merger/merge_paddleocr_vl_paddleocr.py \
|
|
|
+ --paddleocr-vl-dir /path/to/paddleocr_vl_results \
|
|
|
+ --paddle-dir /path/to/paddle_results \
|
|
|
+ --output-dir /path/to/output \
|
|
|
+ --format both \
|
|
|
+ --window 15 \
|
|
|
+ --threshold 85
|
|
|
+```
|
|
|
+
|
|
|
+#### 参数说明
|
|
|
+
|
|
|
+| 参数 | 说明 | 默认值 |
|
|
|
+|------|------|--------|
|
|
|
+| `--paddleocr-vl-file` | PaddleOCR_VL JSON 文件路径(单文件模式) | - |
|
|
|
+| `--paddle-file` | PaddleOCR JSON 文件路径(单文件模式) | - |
|
|
|
+| `--paddleocr-vl-dir` | PaddleOCR_VL 结果目录(批量模式) | - |
|
|
|
+| `--paddle-dir` | PaddleOCR 结果目录(批量模式) | - |
|
|
|
+| `-o, --output-dir` | 输出目录(必需) | - |
|
|
|
+| `-f, --format` | 输出格式:json/markdown/both | both |
|
|
|
+| `-w, --window` | 向前查找窗口大小 | 15 |
|
|
|
+| `-t, --threshold` | 文本相似度阈值(0-100) | 80 |
|
|
|
+
|
|
|
+## 输出格式
|
|
|
+
|
|
|
+### 1. 增强的 Markdown
|
|
|
+
|
|
|
+```markdown
|
|
|
+<!-- bbox: [717, 191, 917, 229] -->
|
|
|
+# 账务明细清单
|
|
|
+
|
|
|
+<!-- bbox: [721, 233, 921, 254] -->
|
|
|
+# Statement Of Account
|
|
|
+
|
|
|
+<!-- bbox: [181, 257, 517, 283] -->
|
|
|
+开户银行:呼和浩特成吉思汗大街
|
|
|
+
|
|
|
+<!-- bbox: [176, 406, 1468, 1920] -->
|
|
|
+<table>
|
|
|
+ <tr>
|
|
|
+ <td data-bbox="[183,413,293,438]" data-paddle-index="10" data-score="0.9995">日期Date</td>
|
|
|
+ <td data-bbox="[296,413,486,438]" data-paddle-index="11" data-score="0.9988">业务类型Business Type</td>
|
|
|
+ <td data-bbox="[489,413,642,438]" data-paddle-index="12" data-score="0.9994">票据号Bill No.</td>
|
|
|
+ </tr>
|
|
|
+ ...
|
|
|
+</table>
|
|
|
+```
|
|
|
+
|
|
|
+### 2. 合并的 JSON
|
|
|
+
|
|
|
+#### MinerU 格式
|
|
|
+```json
|
|
|
+[
|
|
|
+ {
|
|
|
+ "type": "text",
|
|
|
+ "text": "账务明细清单",
|
|
|
+ "text_level": 1,
|
|
|
+ "bbox": [717, 191, 917, 229],
|
|
|
+ "page_idx": 0
|
|
|
+ },
|
|
|
+ {
|
|
|
+ "type": "table",
|
|
|
+ "table_body": "<table>...</table>",
|
|
|
+ "table_body_with_bbox": "<table>...</table>",
|
|
|
+ "bbox": [176, 406, 1468, 1920],
|
|
|
+ "bbox_mapping": "merged_from_paddle_ocr",
|
|
|
+ "table_cells": [
|
|
|
+ {
|
|
|
+ "text": "日期Date",
|
|
|
+ "bbox": [183, 413, 293, 438],
|
|
|
+ "paddle_index": 10,
|
|
|
+ "score": 0.9995,
|
|
|
+ "row": 0,
|
|
|
+ "col": 0
|
|
|
+ }
|
|
|
+ ],
|
|
|
+ "page_idx": 0
|
|
|
+ }
|
|
|
+]
|
|
|
+```
|
|
|
+
|
|
|
+#### PaddleOCR_VL 格式(转换为 MinerU 格式)
|
|
|
+```json
|
|
|
+[
|
|
|
+ {
|
|
|
+ "type": "text",
|
|
|
+ "text": "账务明细清单",
|
|
|
+ "text_level": 1,
|
|
|
+ "bbox": [719, 194, 924, 264],
|
|
|
+ "page_idx": 0
|
|
|
+ },
|
|
|
+ {
|
|
|
+ "type": "table",
|
|
|
+ "table_body": "<table>...</table>",
|
|
|
+ "table_body_with_bbox": "<table>...</table>",
|
|
|
+ "bbox": [177, 256, 1464, 393],
|
|
|
+ "bbox_mapping": "merged_from_paddle_ocr",
|
|
|
+ "table_cells": [...],
|
|
|
+ "page_idx": 0
|
|
|
+ }
|
|
|
+]
|
|
|
+```
|
|
|
+
|
|
|
+## 核心算法
|
|
|
+
|
|
|
+### 1. 文本匹配算法
|
|
|
+
|
|
|
+**目标**:在 PaddleOCR 的文字框列表中找到与 MinerU/PaddleOCR_VL 文本最匹配的 bbox。
|
|
|
+
|
|
|
+**策略**:
|
|
|
+1. **顺序匹配优先**:从 `start_index` 开始顺序查找
|
|
|
+2. **窗口回溯**:如果顺序匹配失败,在上一次匹配位置附近的窗口内查找
|
|
|
+3. **相似度筛选**:使用 `fuzzywuzzy.partial_ratio` 计算相似度,阈值默认 80%
|
|
|
+4. **指针管理**:维护两个指针
|
|
|
+ - `start_index`:下次搜索的起始位置
|
|
|
+ - `last_match_index`:上一次匹配的位置(用于窗口回溯)
|
|
|
+
|
|
|
+**伪代码**:
|
|
|
+```python
|
|
|
+def find_matching_bbox(target_text, text_boxes, start_index, last_match_index, window):
|
|
|
+ # 第一阶段:顺序查找
|
|
|
+ for i in range(start_index, len(text_boxes)):
|
|
|
+ if similarity(target_text, text_boxes[i].text) >= threshold:
|
|
|
+ return text_boxes[i], i + 1, i
|
|
|
+
|
|
|
+ # 第二阶段:窗口回溯
|
|
|
+ window_start = max(0, last_match_index - window)
|
|
|
+ window_end = min(len(text_boxes), last_match_index + window)
|
|
|
+
|
|
|
+ best_match = None
|
|
|
+ best_score = 0
|
|
|
+ best_index = -1
|
|
|
+
|
|
|
+ for i in range(window_start, window_end):
|
|
|
+ score = similarity(target_text, text_boxes[i].text)
|
|
|
+ if score > best_score and score >= threshold:
|
|
|
+ best_match = text_boxes[i]
|
|
|
+ best_score = score
|
|
|
+ best_index = i
|
|
|
+
|
|
|
+ if best_match:
|
|
|
+ return best_match, start_index, best_index
|
|
|
+
|
|
|
+ return None, start_index, last_match_index
|
|
|
+```
|
|
|
+
|
|
|
+### 2. 表格单元格匹配算法
|
|
|
+
|
|
|
+**目标**:为表格中的每个单元格找到对应的 PaddleOCR 文字框。
|
|
|
+
|
|
|
+**步骤**:
|
|
|
+1. **解析表格 HTML**:使用 BeautifulSoup 解析 `<table>` 结构
|
|
|
+2. **逐行逐列处理**:
|
|
|
+ ```python
|
|
|
+ for row in table.find_all('tr'):
|
|
|
+ for cell in row.find_all(['td', 'th']):
|
|
|
+ cell_text = cell.get_text()
|
|
|
+ matched_bbox = find_matching_bbox(cell_text, ...)
|
|
|
+
|
|
|
+ # 添加属性
|
|
|
+ cell['data-bbox'] = str(matched_bbox['bbox'])
|
|
|
+ cell['data-paddle-index'] = matched_bbox['index']
|
|
|
+ cell['data-score'] = matched_bbox['score']
|
|
|
+ ```
|
|
|
+3. **处理合并单元格**:
|
|
|
+ - 检测 `colspan` 和 `rowspan` 属性
|
|
|
+ - 为每个展开的单元格使用相同的 bbox
|
|
|
+4. **指针更新**:每次匹配成功后更新 `paddle_pointer`,避免重复匹配
|
|
|
+
|
|
|
+## 参数调优建议
|
|
|
+
|
|
|
+### 1. `look_ahead_window` (向前查找窗口)
|
|
|
+
|
|
|
+**作用**:当顺序匹配失败时,在上一次匹配位置附近的窗口内查找。
|
|
|
+
|
|
|
+**推荐值**:
|
|
|
+- **顺序文档**(如流水记录):`10-15`
|
|
|
+- **复杂版面**(如多列排版):`15-25`
|
|
|
+- **表格密集型**:`5-10`
|
|
|
+
|
|
|
+**调优方法**:
|
|
|
+```python
|
|
|
+# 如果发现匹配错位,可以适当增大窗口
|
|
|
+merger = MinerUPaddleOCRMerger(look_ahead_window=20)
|
|
|
+
|
|
|
+# 如果发现误匹配,可以适当减小窗口
|
|
|
+merger = MinerUPaddleOCRMerger(look_ahead_window=8)
|
|
|
+```
|
|
|
+
|
|
|
+### 2. `similarity_threshold` (相似度阈值)
|
|
|
+
|
|
|
+**作用**:控制文本匹配的严格程度。
|
|
|
+
|
|
|
+**推荐值**:
|
|
|
+- **高质量 OCR**(如扫描件):`85-90`
|
|
|
+- **一般质量**(如拍照):`75-85`
|
|
|
+- **低质量**(如模糊图片):`70-80`
|
|
|
+
|
|
|
+**调优方法**:
|
|
|
+```python
|
|
|
+# 如果发现漏匹配,可以降低阈值
|
|
|
+merger = MinerUPaddleOCRMerger(similarity_threshold=75)
|
|
|
+
|
|
|
+# 如果发现误匹配,可以提高阈值
|
|
|
+merger = MinerUPaddleOCRMerger(similarity_threshold=90)
|
|
|
+```
|
|
|
+
|
|
|
+## 开发指南
|
|
|
+
|
|
|
+### 扩展新的合并器
|
|
|
+
|
|
|
+1. **创建新的合并器类**:
|
|
|
+```python
|
|
|
+# merger/my_custom_merger.py
|
|
|
+from .text_matcher import TextMatcher
|
|
|
+from .data_processor import DataProcessor
|
|
|
+
|
|
|
+class MyCustomMerger:
|
|
|
+ def __init__(self):
|
|
|
+ self.text_matcher = TextMatcher()
|
|
|
+ self.data_processor = DataProcessor(self.text_matcher)
|
|
|
+
|
|
|
+ def merge_data(self, custom_json, paddle_json):
|
|
|
+ # 实现自定义合并逻辑
|
|
|
+ pass
|
|
|
+```
|
|
|
+
|
|
|
+2. **在 DataProcessor 中添加处理方法**:
|
|
|
+```python
|
|
|
+# merger/data_processor.py
|
|
|
+def process_my_custom_data(self, custom_data, paddle_text_boxes):
|
|
|
+ # 处理自定义格式数据
|
|
|
+ pass
|
|
|
+```
|
|
|
+
|
|
|
+3. **在 MarkdownGenerator 中添加格式化方法**:
|
|
|
+```python
|
|
|
+# merger/markdown_generator.py
|
|
|
+@staticmethod
|
|
|
+def _format_my_custom_element(item: Dict) -> List[str]:
|
|
|
+ # 格式化自定义元素
|
|
|
+ pass
|
|
|
+```
|
|
|
+
|
|
|
+### 单元测试
|
|
|
+
|
|
|
+```python
|
|
|
+# tests/test_merger.py
|
|
|
+import pytest
|
|
|
+from merger import MinerUPaddleOCRMerger
|
|
|
+
|
|
|
+def test_text_matching():
|
|
|
+ merger = MinerUPaddleOCRMerger()
|
|
|
+ # 测试文本匹配逻辑
|
|
|
+
|
|
|
+def test_table_processing():
|
|
|
+ merger = MinerUPaddleOCRMerger()
|
|
|
+ # 测试表格处理逻辑
|
|
|
+```
|
|
|
+
|
|
|
+## 版本历史
|
|
|
+
|
|
|
+### v1.2.0 (当前版本)
|
|
|
+- ✅ 新增 PaddleOCR_VL 合并支持
|
|
|
+- ✅ 重构为模块化架构,提高代码复用率
|
|
|
+- ✅ 新增自动格式检测功能
|
|
|
+- ✅ 优化文本匹配算法
|
|
|
+- ✅ 改进表格单元格 bbox 匹配
|
|
|
+
|
|
|
+### v1.1.0
|
|
|
+- ✅ 优化表格合并单元格处理
|
|
|
+- ✅ 新增批量处理模式
|
|
|
+- ✅ 改进窗口回溯算法
|
|
|
+
|
|
|
+### v1.0.0
|
|
|
+- ✅ 初始版本
|
|
|
+- ✅ 支持 MinerU + PaddleOCR 合并
|
|
|
+- ✅ 基本的文本匹配功能
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### 运行试验数据
|
|
|
+1. mineru-vlm-2.5.3
|
|
|
+```bash
|
|
|
+echo "A用户_单元格扫描流水"
|
|
|
+python merge_mineru_paddle_ocr.py \
|
|
|
+ --mineru-dir "/Users/zhch158/workspace/data/流水分析/A用户_单元格扫描流水/mineru-vlm-2.5.3_Results" \
|
|
|
+ --paddle-dir "/Users/zhch158/workspace/data/流水分析/A用户_单元格扫描流水/data_PPStructureV3_Results" \
|
|
|
+ --output-dir "/Users/zhch158/workspace/data/流水分析/A用户_单元格扫描流水/merged_results" \
|
|
|
+ --format "both"
|
|
|
+
|
|
|
+echo "B用户_扫描流水"
|
|
|
+python merge_mineru_paddle_ocr.py \
|
|
|
+ --mineru-dir "/Users/zhch158/workspace/data/流水分析/B用户_扫描流水/mineru-vlm-2.5.3_Results" \
|
|
|
+ --paddle-dir "/Users/zhch158/workspace/data/流水分析/B用户_扫描流水/data_PPStructureV3_Results" \
|
|
|
+ --output-dir "/Users/zhch158/workspace/data/流水分析/B用户_扫描流水/merged_results" \
|
|
|
+ --format "both"
|
|
|
+
|
|
|
+echo "德_内蒙古银行照"
|
|
|
+python merge_mineru_paddle_ocr.py \
|
|
|
+ --mineru-dir "/Users/zhch158/workspace/data/流水分析/德_内蒙古银行照/mineru-vlm-2.5.3_Results" \
|
|
|
+ --paddle-dir "/Users/zhch158/workspace/data/流水分析/德_内蒙古银行照/data_PPStructureV3_Results" \
|
|
|
+ --output-dir "/Users/zhch158/workspace/data/流水分析/德_内蒙古银行照/merged_results" \
|
|
|
+ --format "both"
|
|
|
+
|
|
|
+echo "对公_招商银行图"
|
|
|
+python merge_mineru_paddle_ocr.py \
|
|
|
+ --mineru-dir "/Users/zhch158/workspace/data/流水分析/对公_招商银行图/mineru-vlm-2.5.3_Results" \
|
|
|
+ --paddle-dir "/Users/zhch158/workspace/data/流水分析/对公_招商银行图/data_PPStructureV3_Results" \
|
|
|
+ --output-dir "/Users/zhch158/workspace/data/流水分析/对公_招商银行图/merged_results" \
|
|
|
+ --format "both"
|
|
|
+
|
|
|
+echo "至远彩色印刷工业有限公司"
|
|
|
+python merge_mineru_paddle_ocr.py \
|
|
|
+ --mineru-dir "/Users/zhch158/workspace/data/至远彩色印刷工业有限公司/mineru-vlm-2.5.3_Results" \
|
|
|
+ --paddle-dir "/Users/zhch158/workspace/data/至远彩色印刷工业有限公司/data_PPStructureV3_Results" \
|
|
|
+ --output-dir "/Users/zhch158/workspace/data/至远彩色印刷工业有限公司/merged_results" \
|
|
|
+ --format "both"
|
|
|
+
|
|
|
+```
|
|
|
+
|
|
|
+2. PaddleOCR_VL_Results
|
|
|
+```bash
|
|
|
+echo "A用户_单元格扫描流水"
|
|
|
+python merge_paddleocr_vl_paddleocr.py \
|
|
|
+ --paddleocr-vl-dir "/Users/zhch158/workspace/data/流水分析/A用户_单元格扫描流水/PaddleOCR_VL_Results" \
|
|
|
+ --paddle-dir "/Users/zhch158/workspace/data/流水分析/A用户_单元格扫描流水/data_PPStructureV3_Results" \
|
|
|
+ --output-dir "/Users/zhch158/workspace/data/流水分析/A用户_单元格扫描流水/PaddleOCR_VL_Results_cell_bbox" \
|
|
|
+ --format "both"
|
|
|
+
|
|
|
+echo "B用户_扫描流水"
|
|
|
+python merge_paddleocr_vl_paddleocr.py \
|
|
|
+ --paddleocr-vl-dir "/Users/zhch158/workspace/data/流水分析/B用户_扫描流水/PaddleOCR_VL_Results" \
|
|
|
+ --paddle-dir "/Users/zhch158/workspace/data/流水分析/B用户_扫描流水/data_PPStructureV3_Results" \
|
|
|
+ --output-dir "/Users/zhch158/workspace/data/流水分析/B用户_扫描流水/PaddleOCR_VL_Results_cell_bbox" \
|
|
|
+ --format "both"
|
|
|
+
|
|
|
+echo "德_内蒙古银行照"
|
|
|
+python merge_paddleocr_vl_paddleocr.py \
|
|
|
+ --paddleocr-vl-dir "/Users/zhch158/workspace/data/流水分析/德_内蒙古银行照/PaddleOCR_VL_Results" \
|
|
|
+ --paddle-dir "/Users/zhch158/workspace/data/流水分析/德_内蒙古银行照/data_PPStructureV3_Results" \
|
|
|
+ --output-dir "/Users/zhch158/workspace/data/流水分析/德_内蒙古银行照/PaddleOCR_VL_Results_cell_bbox" \
|
|
|
+ --format "both"
|
|
|
+
|
|
|
+echo "对公_招商银行图"
|
|
|
+python merge_paddleocr_vl_paddleocr.py \
|
|
|
+ --paddleocr-vl-dir "/Users/zhch158/workspace/data/流水分析/对公_招商银行图/PaddleOCR_VL_Results" \
|
|
|
+ --paddle-dir "/Users/zhch158/workspace/data/流水分析/对公_招商银行图/data_PPStructureV3_Results" \
|
|
|
+ --output-dir "/Users/zhch158/workspace/data/流水分析/对公_招商银行图/PaddleOCR_VL_Results_cell_bbox" \
|
|
|
+ --format "both"
|
|
|
+
|
|
|
+echo "至远彩色印刷工业有限公司"
|
|
|
+python merge_paddleocr_vl_paddleocr.py \
|
|
|
+ --paddleocr-vl-dir "/Users/zhch158/workspace/data/至远彩色印刷工业有限公司/PaddleOCR_VL_Results" \
|
|
|
+ --paddle-dir "/Users/zhch158/workspace/data/至远彩色印刷工业有限公司/data_PPStructureV3_Results" \
|
|
|
+ --output-dir "/Users/zhch158/workspace/data/至远彩色印刷工业有限公司/PaddleOCR_VL_Results_cell_bbox" \
|
|
|
+ --format "both"
|
|
|
+
|
|
|
+```
|