|
|
пре 1 недеља | |
|---|---|---|
| .. | ||
| DP算法多路径探索说明.md | пре 1 недеља | |
| README.md | пре 1 недеља | |
| Tablecells匹配-动态规划.md | пре 1 недеља | |
| 坐标系变换.md | пре 1 недеља | |
| 表格行匹配算法可视化图示.md | пре 1 недеља | |
| 表格行匹配算法详解.md | пре 1 недеља | |
本工具包用于合并不同 OCR 工具的识别结果,主要功能是将结构化识别结果(如 MinerU、PaddleOCR_VL、DotsOCR)与精确文字框坐标(PaddleOCR)进行合并,生成包含完整 bbox 信息的增强版 Markdown 和 JSON 文件。
位置:ocr_platform/ocr_tools/ocr_merger/
注意:
BBoxExtractor 已迁移到 ocr_utils/bbox_utils.py,供多个模块共享使用from ocr_utils import BBoxExtractorocr_tools/ocr_merger/
├── __init__.py # 包初始化文件
├── merger_core.py # MinerU 合并器核心类
├── paddleocr_vl_merger.py # PaddleOCR_VL 合并器核心类
├── dotsocr_merger.py # DotsOCR 合并器核心类
├── merge_mineru_paddle_ocr.py # MinerU + PaddleOCR 主程序
├── merge_paddleocr_vl_paddleocr.py # PaddleOCR_VL + PaddleOCR 主程序
├── merge_dotsocr_paddleocr.py # DotsOCR + PaddleOCR 主程序
├── text_matcher.py # 文本匹配模块(共用)
├── data_processor.py # 数据处理模块(共用)
├── markdown_generator.py # Markdown 生成模块(共用)
├── unified_output_converter.py # 统一输出转换器
├── table_cell_matcher.py # 表格单元格匹配器
└── README.md # 本说明文档
注意:
- `BBoxExtractor` 已迁移到 `ocr_utils/bbox_utils.py`,供多个模块共享使用
- 导入时使用:`from ocr_utils import BBoxExtractor`
MinerUPaddleOCRMerger (merger_core.py)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)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"""
DotsOCRMerger (dotsocr_merger.py)class DotsOCRMerger:
"""DotsOCR 和 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, dotsocr_json_path: str,
paddle_json_path: str,
data_format: str = 'mineru') -> List[Dict]:
"""合并 DotsOCR 和 PaddleOCR 的结果"""
def generate_enhanced_markdown(self, merged_data: List[Dict],
output_path: str = None,
source_file: str = None,
data_format: str = None) -> str:
"""生成增强的 Markdown"""
TextMatcher (text_matcher.py)负责文本匹配,找到 MinerU/PaddleOCR_VL/DotsOCR 文本在 PaddleOCR 结果中的对应位置。
核心方法:
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)
"""
匹配策略:
start_index 开始顺序查找[last_match_index - look_ahead_window, last_match_index + look_ahead_window] 范围内查找fuzzywuzzy 计算文本相似度BBoxExtractor (ocr_utils/bbox_utils.py)负责从 PaddleOCR 结果中提取文字框信息,并提供坐标转换功能。
注意:BBoxExtractor 已迁移到 ocr_utils/bbox_utils.py,供多个模块共享使用。
导入方式:
from ocr_utils import BBoxExtractor
核心方法:
def extract_paddle_text_boxes(self, paddle_data: Dict) -> Tuple[List[Dict], float, Tuple[int, int]]:
"""
提取 PaddleOCR 的文字框信息
Returns:
(文字框列表, 旋转角度, 原始图像尺寸)
文字框格式:
[
{
'text': '文本内容',
'bbox': [x1, y1, x2, y2],
'poly': [[x1,y1], [x2,y2], [x3,y3], [x4,y4]],
'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],
'row': 1,
'col': 2,
'score': 0.99,
'paddle_index': 10
},
...
]
"""
def inverse_rotate_box_coordinates(self, bbox: List[float], angle: float, orig_image_size: tuple) -> List[float]:
"""
反向旋转 bbox 坐标(将旋转后的坐标转换回原始图像坐标)
"""
def rotate_box_coordinates(self, bbox: List[float], angle: float, orig_image_size: tuple) -> List[float]:
"""
旋转 bbox 坐标(与图像旋转保持一致)
"""
def calculate_skew_angle(self, paddle_boxes: List[Dict], sample_ratio: float = 0.5, outlier_threshold: float = 0.3) -> float:
"""
计算文档倾斜角度(基于文本行分析)
"""
def correct_boxes_skew(self, paddle_boxes: List[Dict], correction_angle: float, image_size: Tuple[int, int]) -> List[Dict]:
"""
校正文本框的倾斜
"""
DataProcessor (data_processor.py)负责处理 MinerU/PaddleOCR_VL/DotsOCR 数据,添加 bbox 信息。
核心方法:
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],
rotation_angle: float = 0.0,
orig_image_size: tuple = (0,0)) -> List[Dict]:
"""
处理 PaddleOCR_VL 数据,添加 bbox 信息
处理类型:
- paragraph_title: 段落标题
- figure_title: 图片标题
- text: 文本
- table: 表格
- figure: 图片
- equation: 公式
- reference: 参考文献
"""
def process_dotsocr_data(self, dotsocr_data: Dict,
paddle_text_boxes: List[Dict],
rotation_angle: float = 0.0,
orig_image_size: tuple = (0,0)) -> List[Dict]:
"""
处理 DotsOCR 数据,添加 bbox 信息
处理类型:
- text: 文本
- table: 表格
- image: 图片
- equation: 公式
"""
表格处理逻辑:
<td> 添加 data-bbox、data-paddle-index、data-score 属性MarkdownGenerator (markdown_generator.py)负责将合并后的数据生成 Markdown 文件。
核心特性:
<!-- bbox: [x1, y1, x2, y2] --> 注释核心方法:
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 则自动检测
"""
格式化方法:
_format_mineru_*() 系列方法_format_paddleocr_vl_*() 系列方法_format_equation(), _format_metadata() 等# 单文件处理
python ocr_tools/ocr_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 \
--output-type both
# 批量处理
python ocr_tools/ocr_merger/merge_mineru_paddle_ocr.py \
--mineru-dir /path/to/mineru_results \
--paddle-dir /path/to/paddle_results \
--output-dir /path/to/output \
--output-type both \
--window 15 \
--threshold 85
| 参数 | 说明 | 默认值 |
|---|---|---|
--mineru-file |
MinerU JSON 文件路径(单文件模式) | - |
--paddle-file |
PaddleOCR JSON 文件路径(单文件模式) | - |
--mineru-dir |
MinerU 结果目录(批量模式) | - |
--paddle-dir |
PaddleOCR 结果目录(批量模式) | - |
-o, --output-dir |
输出目录(必需) | - |
-f, --output-type |
输出格式:json/markdown/both | both |
-w, --window |
向前查找窗口大小 | 15 |
-t, --threshold |
文本相似度阈值(0-100) | 80 |
# 单文件处理
python ocr_tools/ocr_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 \
--output-type both
# 批量处理
python ocr_tools/ocr_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 \
--output-type 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, --output-type |
输出格式:json/markdown/both | both |
-w, --window |
向前查找窗口大小 | 15 |
-t, --threshold |
文本相似度阈值(0-100) | 80 |
# 单文件处理
python ocr_tools/ocr_merger/merge_dotsocr_paddleocr.py \
--dotsocr-file /path/to/dotsocr_page_001.json \
--paddle-file /path/to/paddle_page_001.json \
--output-dir /path/to/output \
--output-type both
# 批量处理
python ocr_tools/ocr_merger/merge_dotsocr_paddleocr.py \
--dotsocr-dir /path/to/dotsocr_results \
--paddle-dir /path/to/paddle_results \
--output-dir /path/to/output \
--output-type both \
--window 15 \
--threshold 85
| 参数 | 说明 | 默认值 |
|---|---|---|
--dotsocr-file |
DotsOCR JSON 文件路径(单文件模式) | - |
--paddle-file |
PaddleOCR JSON 文件路径(单文件模式) | - |
--dotsocr-dir |
DotsOCR 结果目录(批量模式) | - |
--paddle-dir |
PaddleOCR 结果目录(批量模式) | - |
-o, --output-dir |
输出目录(必需) | - |
-f, --output-type |
输出格式:json/markdown/both | both |
-w, --window |
向前查找窗口大小 | 15 |
-t, --threshold |
文本相似度阈值(0-100) | 80 |
<!-- 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>
[
{
"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
}
]
[
{
"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
}
]
目标:在 PaddleOCR 的文字框列表中找到与 MinerU/PaddleOCR_VL 文本最匹配的 bbox。
策略:
start_index 开始顺序查找fuzzywuzzy.partial_ratio 计算相似度,阈值默认 80%start_index:下次搜索的起始位置last_match_index:上一次匹配的位置(用于窗口回溯)伪代码:
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
目标:为表格中的每个单元格找到对应的 PaddleOCR 文字框。
步骤:
<table> 结构逐行逐列处理:
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']
处理合并单元格:
colspan 和 rowspan 属性指针更新:每次匹配成功后更新 paddle_pointer,避免重复匹配
look_ahead_window (向前查找窗口)作用:当顺序匹配失败时,在上一次匹配位置附近的窗口内查找。
推荐值:
10-1515-255-10调优方法:
# 如果发现匹配错位,可以适当增大窗口
merger = MinerUPaddleOCRMerger(look_ahead_window=20)
# 如果发现误匹配,可以适当减小窗口
merger = MinerUPaddleOCRMerger(look_ahead_window=8)
similarity_threshold (相似度阈值)作用:控制文本匹配的严格程度。
推荐值:
85-9075-8570-80调优方法:
# 如果发现漏匹配,可以降低阈值
merger = MinerUPaddleOCRMerger(similarity_threshold=75)
# 如果发现误匹配,可以提高阈值
merger = MinerUPaddleOCRMerger(similarity_threshold=90)
创建新的合并器类:
# ocr_tools/ocr_merger/my_custom_merger.py
import sys
from pathlib import Path
# 添加 ocr_platform 根目录到 Python 路径
ocr_platform_root = Path(__file__).parents[3]
if str(ocr_platform_root) not in sys.path:
sys.path.insert(0, str(ocr_platform_root))
from ocr_tools.ocr_merger.text_matcher import TextMatcher
from ocr_tools.ocr_merger.data_processor import DataProcessor
from ocr_utils import BBoxExtractor # 从 ocr_utils 导入
class MyCustomMerger:
def __init__(self):
self.text_matcher = TextMatcher()
self.bbox_extractor = BBoxExtractor() # 从 ocr_utils 导入
self.data_processor = DataProcessor(self.text_matcher, look_ahead_window=10)
def merge_data(self, custom_json, paddle_json):
# 实现自定义合并逻辑
pass
在 DataProcessor 中添加处理方法:
# ocr_tools/ocr_merger/data_processor.py
def process_my_custom_data(self, custom_data, paddle_text_boxes, rotation_angle=0.0, orig_image_size=(0,0)):
# 处理自定义格式数据
pass
在 MarkdownGenerator 中添加格式化方法:
# ocr_tools/ocr_merger/markdown_generator.py
@staticmethod
def _format_my_custom_element(item: Dict) -> List[str]:
# 格式化自定义元素
pass
# tests/test_merger.py
import sys
from pathlib import Path
# 添加 ocr_platform 根目录到 Python 路径
ocr_platform_root = Path(__file__).parents[2] # 根据实际层级调整
if str(ocr_platform_root) not in sys.path:
sys.path.insert(0, str(ocr_platform_root))
import pytest
from ocr_tools.ocr_merger import MinerUPaddleOCRMerger
def test_text_matching():
merger = MinerUPaddleOCRMerger()
# 测试文本匹配逻辑
def test_table_processing():
merger = MinerUPaddleOCRMerger()
# 测试表格处理逻辑
import sys
from pathlib import Path
# 添加 ocr_platform 根目录到 Python 路径
ocr_platform_root = Path(__file__).parents[3] # 根据实际层级调整
if str(ocr_platform_root) not in sys.path:
sys.path.insert(0, str(ocr_platform_root))
# 导入 merger 组件
from ocr_tools.ocr_merger import (
MinerUPaddleOCRMerger,
PaddleOCRVLMerger,
DotsOCRMerger,
TableCellMatcher,
TextMatcher
)
# 导入 BBoxExtractor(已迁移到 ocr_utils)
from ocr_utils import BBoxExtractor
# 相对导入(在同一包内)
from .text_matcher import TextMatcher
from .data_processor import DataProcessor
# 从 ocr_utils 导入 BBoxExtractor
from ocr_utils import BBoxExtractor
ocr_platform/ocr_tools/ocr_mergerBBoxExtractor 提取到 ocr_utils/bbox_utils.py,供多个模块共享cd /Users/zhch158/workspace/repository.git/ocr_platform
echo "A用户_单元格扫描流水"
python ocr_tools/ocr_merger/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" \
--output-type "both"
echo "B用户_扫描流水"
python ocr_tools/ocr_merger/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" \
--output-type "both"
echo "德_内蒙古银行照"
python ocr_tools/ocr_merger/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" \
--output-type "both"
echo "对公_招商银行图"
python ocr_tools/ocr_merger/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" \
--output-type "both"
echo "至远彩色印刷工业有限公司"
python ocr_tools/ocr_merger/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" \
--output-type "both"
cd /Users/zhch158/workspace/repository.git/ocr_platform
echo "A用户_单元格扫描流水"
python ocr_tools/ocr_merger/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" \
--output-type "both"
echo "B用户_扫描流水"
python ocr_tools/ocr_merger/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" \
--output-type "both"
echo "德_内蒙古银行照"
python ocr_tools/ocr_merger/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" \
--output-type "both"
echo "对公_招商银行图"
python ocr_tools/ocr_merger/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" \
--output-type "both"
echo "至远彩色印刷工业有限公司"
python ocr_tools/ocr_merger/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" \
--output-type "both"