# OCR识别差异分析与改进方案 ## 📊 问题描述 对比两个OCR识别结果: - **PPStructureV3**:准确率高,文本识别完整 - **统一OCR框架(MinerU封装)**:很多文本未识别,部分文本块检测错误 ### 典型错误示例 从 `bank_statement_yusys_v2/2023年度报告母公司_page_003.json` 中发现的错误: | 正确文本 | 识别结果 | 匹配分数 | 问题 | |---------|---------|---------|------| | 合同资产 | 货资产 | 80.0% | 检测框不完整 | | 其他应付款 | 税款 | 66.67% | 检测框错误 | | 长期待摊费用 | 效用 | 66.67% | 检测框错误 | | 其他非流动资产 | 非其非产动产 | 61.54% | 检测框合并错误 | | 资本公积 | 资公存股 | 66.67% | 检测框合并错误 | ## 🔍 根本原因分析 ### 1. **检测参数差异** | 参数 | PPStructureV3 | MinerU默认 | 影响 | |-----|--------------|-----------|------| | `box_thresh` | **0.6** | **0.3** | 阈值过低导致检测到大量噪声框 | | `unclip_ratio` | **1.5** | **1.8** | 扩展比例过高,框不够精确 | | `thresh` | 0.3 | 0.3 | 相同 | **问题**: - `box_thresh=0.3` 太低,会检测到很多低置信度的噪声框 - 这些噪声框可能被错误地合并到正确的文本框中 - 导致最终识别结果不准确 ### 2. **检测框合并策略** | 特性 | PPStructureV3 | MinerU | 影响 | |-----|--------------|--------|------| | 框合并 | 无(或更保守) | `enable_merge_det_boxes=True` | 可能错误合并相邻文本块 | **问题**: - `enable_merge_det_boxes=True` 会合并相邻的检测框 - 对于表格等密集文本,可能将不同单元格的文本错误合并 - 例如:"其他非流动资产" 被合并成 "非其非产动产" ### 3. **识别置信度过滤** | 参数 | PPStructureV3 | MinerU | 影响 | |-----|--------------|--------|------| | `score_thresh` | **0.0** | **0.5** | 丢弃低置信度结果 | **问题**: - `drop_score=0.5` 会丢弃置信度 < 0.5 的识别结果 - 某些正确但置信度较低的文本可能被丢弃 - PPStructureV3 使用 `score_thresh=0.0`,保留所有结果 ### 4. **文本行方向识别** | 特性 | PPStructureV3 | MinerU | 影响 | |-----|--------------|--------|------| | 文本行方向识别 | ✅ `use_textline_orientation: True` | ❌ 无 | 倾斜文本识别错误 | **问题**: - PPStructureV3 有专门的文本行方向识别模块 - 可以处理倾斜的文本行,提高识别准确率 - MinerU 缺少此功能 ### 5. **模型版本差异** | 组件 | PPStructureV3 | MinerU | 影响 | |-----|--------------|--------|------| | 检测模型 | PP-OCRv5_server_det | ch/ch_lite | 可能使用较旧版本 | | 识别模型 | PP-OCRv5_server_rec | ch/ch_lite | 可能使用较旧版本 | **问题**: - PP-OCRv5_server 是较新的模型,准确率更高 - MinerU 可能使用较旧版本的模型 ## 💡 改进方案 ### 方案0:单元格二次 OCR(已实施,效果最佳)⭐ **核心思路**:不仅依赖一次整页 OCR 的参数调优,而是在有线表格场景对**每个单元格单独裁剪、预处理、再 OCR**。这是从"提升整页 OCR 质量"到"对关键区域精准重试"的策略升级。 #### 为什么二次 OCR 比调整参数更有效 | 问题 | 仅调参数 | 二次 OCR(单元格裁剪) | |------|---------|----------------------| | **检测框不完整**("合同资产"→"货资产") | 调高 box_thresh 可能直接丢失该行 | 单格裁剪后文字占比更高,det 盒完整 | | **检测框合并错误**("其他非流动资产"→"非其非产动产") | 关闭 merge_det_boxes 可能引入其他问题 | 单元格天然隔离,不存在跨格合并 | | **水印干扰**("有限公司"被误识别) | 无法处理 | 斜框角度过滤(`_is_bbox_slanted`)+ 格级去水印 | | **弱信号遗漏**(空格、低分碎片) | 降低 drop_score 引入噪声 | 精确判定列空性(`_column_empty_ratio`),按需触发 | | **纵向不全**(只识别到"支行") | 无法检测 | `_is_ocr_vertically_incomplete` 纵向偏移+空白不对称检测 | #### 处理流程 详见 [有线表格识别技术文档 — 六、单元格 OCR](./有线表格识别技术文档.md),核心要点: ```mermaid graph TB A[整页 OCR] --> B[一验:中心点匹配
fill_text_by_center_point] B --> C{触发二次 OCR?
_should_second_pass_cell} C --> D[Pass1:格级预处理
去水印+upscale+OCR] C --> E[跳过,保持一验结果] D --> F{Pass1 分数达标?} F -->|否| G[Pass2:enhance_retry
更强预处理+再OCR] F -->|是| H[采纳结果] G --> H style B fill:#e1f5ff style D fill:#fff4e1 style G fill:#fff4e1 ``` #### 关键能力 | 能力 | 方法 | 对应问题 | |------|------|---------| | **斜框过滤** | `_is_bbox_slanted`(多边形角度 > 10° → 丢弃) | 水印误识别(如"有限公司"被当成单元格文字) | | **纵向完整性** | `_is_ocr_vertically_incomplete`(y_center 偏移 + 空白不对称) | 检测框截断(如只识别到"支行"而非完整户名) | | **列空判断** | `_column_empty_ratio`(基于 `matched_boxes_list` 判空) | 区分"OCR 遗漏"和"列本来就空",仅前者触发重试 | | **Pass2 独立配置** | `enhance_retry` 可与 `cell_preprocess` 解耦(`upscale_min_side` 等) | 低分难例二次增强,不牺牲ปกติ格的处理效率 | #### 与方案1-4的关系 方案1-4 的整页 OCR 参数调整 **仍然有价值**,是与二次 OCR **互补**而非替代: - **整页 OCR 参数**(方案1-3):降低噪声框基数,减少二次 OCR 的触发频率 - **二次 OCR**(方案0):对整页 OCR 无法解决的问题做精准修正 - 推荐组合:整页 OCR 平衡参数 + `bank_statement` 模式二次 OCR --- ### 方案1:调整OCR参数(推荐,快速改进) 修改 `MinerUOCRRecognizer` 的初始化参数,使其更接近 PPStructureV3: ```python # 在 mineru_adapter.py 中修改 self.ocr_model = self.atom_model_manager.get_atom_model( atom_model_name=AtomicModel.OCR, det_db_box_thresh=0.6, # 从 0.3 提高到 0.6 lang=self.config.get('language', 'ch'), det_db_unclip_ratio=1.5, # 从 1.8 降低到 1.5 enable_merge_det_boxes=False, # 从 True 改为 False(表格场景) ) ``` **优点**: - ✅ 快速实施,无需修改核心代码 - ✅ 可以显著提高检测准确率 - ✅ 减少错误合并 **缺点**: - ⚠️ 可能漏检一些低置信度的文本(但通常这些是噪声) - ⚠️ 对于非表格场景,可能需要 `enable_merge_det_boxes=True` ### 方案2:降低识别置信度阈值 修改 `drop_score` 参数,保留更多识别结果: ```python # 需要修改 PytorchPaddleOCR 的初始化 kwargs['drop_score'] = 0.3 # 从默认 0.5 降低到 0.3 ``` **优点**: - ✅ 保留更多识别结果 - ✅ 减少误丢弃 **缺点**: - ⚠️ 可能引入更多噪声结果 - ⚠️ 需要修改 MinerU 核心代码 ### 方案3:根据场景动态调整参数(最佳方案) 根据文档类型(表格/文本)和PDF类型(扫描件/数字PDF)动态调整参数: ```python def get_ocr_config(pdf_type: str, has_tables: bool) -> Dict[str, Any]: """根据场景返回OCR配置""" if has_tables: # 表格场景:更严格的检测,不合并框 return { 'det_db_box_thresh': 0.6, 'det_db_unclip_ratio': 1.5, 'enable_merge_det_boxes': False, 'drop_score': 0.3, } elif pdf_type == 'txt': # 数字PDF:可以合并框,提高检测阈值 return { 'det_db_box_thresh': 0.5, 'det_db_unclip_ratio': 1.6, 'enable_merge_det_boxes': True, 'drop_score': 0.3, } else: # 扫描件:平衡检测和合并 return { 'det_db_box_thresh': 0.4, 'det_db_unclip_ratio': 1.6, 'enable_merge_det_boxes': True, 'drop_score': 0.3, } ``` **优点**: - ✅ 针对不同场景优化 - ✅ 兼顾准确率和召回率 **缺点**: - ⚠️ 实现复杂度较高 - ⚠️ 需要场景判断逻辑 ### 方案4:集成文本行方向识别(长期改进) 参考 PPStructureV3,添加文本行方向识别模块: 1. 在 OCR 识别前,先进行文本行方向识别 2. 根据识别结果旋转文本行 3. 再进行 OCR 识别 **优点**: - ✅ 显著提高倾斜文本识别准确率 - ✅ 与 PPStructureV3 能力对齐 **缺点**: - ⚠️ 需要额外的模型和计算资源 - ⚠️ 实现复杂度高 ## 🎯 推荐实施步骤 ### 阶段0:单元格二次 OCR(✅ 已完成) 1. **有线表格二次 OCR**: - 整页 OCR 匹配后,对需要重处理的单元格裁剪再 OCR - `_is_bbox_slanted`:过滤斜向水印 - `_is_ocr_vertically_incomplete`:检测纵向不完全文本 - `_column_empty_ratio`:基于 matched_boxes_list 智能判空 - Pass1 格级预处理 + Pass2 enhance_retry 独立配置 > 详见:[有线表格识别技术文档 — 六、单元格 OCR](./有线表格识别技术文档.md) ### 阶段1:快速改进(整页OCR参数调优) 1. **调整检测参数**: - `det_db_box_thresh`: 0.3 → **0.6** - `det_db_unclip_ratio`: 1.8 → **1.5** - `enable_merge_det_boxes`: True → **False**(表格场景) 2. **降低识别阈值**: - `drop_score`: 0.5 → **0.3** ### 阶段2:场景优化(短期) 3. **实现动态参数调整**: - 根据文档类型和PDF类型选择参数 - 表格场景:严格检测,不合并 - 文本场景:平衡检测和合并 ### 阶段3:能力增强(长期) 4. **集成文本行方向识别**: - 添加文本行方向识别模块 - 提高倾斜文本识别准确率 ## 📝 配置建议 ### 表格场景(当前问题场景) ```yaml ocr: det_db_box_thresh: 0.6 # 提高检测阈值 det_db_unclip_ratio: 1.5 # 降低扩展比例 enable_merge_det_boxes: false # 不合并框 drop_score: 0.3 # 降低识别阈值 ``` ### 文本场景 ```yaml ocr: det_db_box_thresh: 0.4 # 中等检测阈值 det_db_unclip_ratio: 1.6 # 中等扩展比例 enable_merge_det_boxes: true # 允许合并 drop_score: 0.3 # 降低识别阈值 ``` ## 🔧 代码修改位置 1. **`models/adapters/mineru_adapter.py`**: - `MinerUOCRRecognizer.__init__()` - 修改初始化参数 - 添加场景判断逻辑 2. **`core/pipeline_manager_v2.py`**: - `_process_single_page()` - 检测是否有表格 - 传递场景信息给 OCR 识别器 3. **配置文件**: - 添加 OCR 参数配置选项 ## 📈 预期效果 实施阶段0(✅ 已完成)+ 阶段1改进后: - ✅ 检测准确率提升:减少噪声框和错误合并 - ✅ 识别完整度提升:单元格二次 OCR 修复整页漏检、截断误识别 - ✅ 水印豁免:`_is_bbox_slanted` 过滤斜向水印,减少误匹配 - ✅ 智能空列判断:`_column_empty_ratio` 区分"OCR遗漏"与"真空白",减少无效重试 - ✅ 表格识别准确率:预计从 60-70% 提升到 85-90% ## ⚠️ 注意事项 1. **参数调优**: - 不同文档可能需要不同的参数 - 建议通过测试集验证最优参数 2. **性能影响**: - 提高 `box_thresh` 可能略微降低召回率 - 需要平衡准确率和召回率 3. **向后兼容**: - 保持默认参数不变,通过配置覆盖 - 确保现有功能不受影响