|
@@ -0,0 +1,278 @@
|
|
|
|
|
+# Layout后处理:大面积文本块转表格
|
|
|
|
|
+
|
|
|
|
|
+## 📋 功能说明
|
|
|
|
|
+
|
|
|
|
|
+当Layout检测将大面积的表格区域误识别为文本框时,可以通过后处理自动将其转换为表格类型。
|
|
|
|
|
+
|
|
|
|
|
+## 🎯 使用场景
|
|
|
|
|
+
|
|
|
|
|
+### 典型问题
|
|
|
|
|
+
|
|
|
|
|
+从 `page_022.json` 可以看到:
|
|
|
|
|
+- 一个很大的文本框(bbox: [226, 288, 1495, 1685])
|
|
|
|
|
+- 包含了多个表格的内容(账龄分析、主要单位往来、存货等)
|
|
|
|
|
+- 但被识别为 `type: "text"`,而不是 `type: "table"`
|
|
|
|
|
+
|
|
|
|
|
+### 解决方案
|
|
|
|
|
+
|
|
|
|
|
+通过后处理规则,自动将满足条件的大文本块转换为表格:
|
|
|
|
|
+- ✅ 面积占比超过阈值(默认25%)
|
|
|
|
|
+- ✅ 宽度和高度都超过一定比例(避免细长条)
|
|
|
|
|
+- ✅ 页面中没有其他表格(避免误判)
|
|
|
|
|
+
|
|
|
|
|
+## ⚙️ 配置选项
|
|
|
|
|
+
|
|
|
|
|
+### 配置文件示例
|
|
|
|
|
+
|
|
|
|
|
+```yaml
|
|
|
|
|
+# 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%)
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 参数说明
|
|
|
|
|
+
|
|
|
|
|
+| 参数 | 类型 | 默认值 | 说明 |
|
|
|
|
|
+|-----|------|--------|------|
|
|
|
|
|
+| `convert_large_text_to_table` | bool | `true` | 是否启用文本转表格功能 |
|
|
|
|
|
+| `min_text_area_ratio` | float | `0.25` | 最小面积占比(0-1),文本块面积需占页面25%以上 |
|
|
|
|
|
+| `min_text_width_ratio` | float | `0.4` | 最小宽度占比(0-1),文本块宽度需占页面40%以上 |
|
|
|
|
|
+| `min_text_height_ratio` | float | `0.3` | 最小高度占比(0-1),文本块高度需占页面30%以上 |
|
|
|
|
|
+
|
|
|
|
|
+## 🔍 判断规则
|
|
|
|
|
+
|
|
|
|
|
+### 1. 面积占比判断
|
|
|
|
|
+
|
|
|
|
|
+```python
|
|
|
|
|
+area_ratio = text_block_area / page_area
|
|
|
|
|
+if area_ratio >= min_text_area_ratio: # 默认 >= 0.25
|
|
|
|
|
+ # 满足面积条件
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**示例**:
|
|
|
|
|
+- 页面尺寸:2338 × 1654 = 3,867,052 像素²
|
|
|
|
|
+- 文本块:1207 × 1397 = 1,686,179 像素²
|
|
|
|
|
+- 面积占比:1,686,179 / 3,867,052 = **43.6%** ✅ 满足条件
|
|
|
|
|
+
|
|
|
|
|
+### 2. 尺寸比例判断
|
|
|
|
|
+
|
|
|
|
|
+```python
|
|
|
|
|
+width_ratio = text_block_width / page_width
|
|
|
|
|
+height_ratio = text_block_height / page_height
|
|
|
|
|
+
|
|
|
|
|
+if (width_ratio >= min_text_width_ratio and
|
|
|
|
|
+ height_ratio >= min_text_height_ratio):
|
|
|
|
|
+ # 满足尺寸条件
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**示例**:
|
|
|
|
|
+- 页面宽度:1654px,文本块宽度:1269px → 宽度占比:**76.7%** ✅
|
|
|
|
|
+- 页面高度:2338px,文本块高度:1397px → 高度占比:**59.8%** ✅
|
|
|
|
|
+
|
|
|
|
|
+### 3. 表格冲突检查
|
|
|
|
|
+
|
|
|
|
|
+```python
|
|
|
|
|
+has_table = any(
|
|
|
|
|
+ item.get('category', '').lower() in ['table', 'table_body']
|
|
|
|
|
+ for item in layout_results
|
|
|
|
|
+)
|
|
|
|
|
+
|
|
|
|
|
+if has_table:
|
|
|
|
|
+ # 页面已有表格,不进行转换(避免误判)
|
|
|
|
|
+ return layout_results
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**逻辑**:
|
|
|
|
|
+- 如果页面中已经有表格元素,说明Layout检测正常工作
|
|
|
|
|
+- 此时不进行转换,避免将普通文本误判为表格
|
|
|
|
|
+
|
|
|
|
|
+## 📊 转换效果
|
|
|
|
|
+
|
|
|
|
|
+### 转换前
|
|
|
|
|
+
|
|
|
|
|
+```json
|
|
|
|
|
+{
|
|
|
|
|
+ "bbox": [226, 288, 1495, 1685],
|
|
|
|
|
+ "category": "text",
|
|
|
|
|
+ "text": "1、账龄分析\n账龄 期末余额\n1年以内 178,051,695.35\n..."
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 转换后
|
|
|
|
|
+
|
|
|
|
|
+```json
|
|
|
|
|
+{
|
|
|
|
|
+ "bbox": [226, 288, 1495, 1685],
|
|
|
|
|
+ "category": "table",
|
|
|
|
|
+ "original_category": "text", // 保留原始类别
|
|
|
|
|
+ "text": "1、账龄分析\n账龄 期末余额\n1年以内 178,051,695.35\n..."
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+## 🎯 调优建议
|
|
|
|
|
+
|
|
|
|
|
+### 场景1:财务报表(多表格)
|
|
|
|
|
+
|
|
|
|
|
+```yaml
|
|
|
|
|
+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%高度
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 场景2:密集表格(小表格多)
|
|
|
|
|
+
|
|
|
|
|
+```yaml
|
|
|
|
|
+layout:
|
|
|
|
|
+ convert_large_text_to_table: true
|
|
|
|
|
+ min_text_area_ratio: 0.15 # 降低到15%(更敏感)
|
|
|
|
|
+ min_text_width_ratio: 0.3 # 降低到30%
|
|
|
|
|
+ min_text_height_ratio: 0.2 # 降低到20%
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 场景3:宽松检测(避免误判)
|
|
|
|
|
+
|
|
|
|
|
+```yaml
|
|
|
|
|
+layout:
|
|
|
|
|
+ convert_large_text_to_table: true
|
|
|
|
|
+ min_text_area_ratio: 0.35 # 提高到35%(更严格)
|
|
|
|
|
+ min_text_width_ratio: 0.5 # 提高到50%
|
|
|
|
|
+ min_text_height_ratio: 0.4 # 提高到40%
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 场景4:关闭功能
|
|
|
|
|
+
|
|
|
|
|
+```yaml
|
|
|
|
|
+layout:
|
|
|
|
|
+ convert_large_text_to_table: false # 完全关闭
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+## ⚠️ 注意事项
|
|
|
|
|
+
|
|
|
|
|
+### 1. **误判风险**
|
|
|
|
|
+
|
|
|
|
|
+- **风险**:可能将大段普通文本误判为表格
|
|
|
|
|
+- **缓解**:通过面积和尺寸比例阈值控制
|
|
|
|
|
+- **建议**:根据实际文档类型调整阈值
|
|
|
|
|
+
|
|
|
|
|
+### 2. **已有表格检查**
|
|
|
|
|
+
|
|
|
|
|
+- **逻辑**:如果页面已有表格,不进行转换
|
|
|
|
|
+- **原因**:说明Layout检测正常工作,不需要后处理
|
|
|
|
|
+- **例外**:如果Layout检测完全失败,可能无法检测到表格
|
|
|
|
|
+
|
|
|
|
|
+### 3. **转换时机**
|
|
|
|
|
+
|
|
|
|
|
+- **位置**:在Layout检测之后,元素分类之前
|
|
|
|
|
+- **顺序**:
|
|
|
|
|
+ 1. Layout检测
|
|
|
|
|
+ 2. 重叠框去重
|
|
|
|
|
+ 3. **文本转表格(后处理)** ← 这里
|
|
|
|
|
+ 4. 元素分类
|
|
|
|
|
+ 5. 元素处理
|
|
|
|
|
+
|
|
|
|
|
+### 4. **保留原始信息**
|
|
|
|
|
+
|
|
|
|
|
+- 转换后的元素会保留 `original_category` 字段
|
|
|
|
|
+- 便于调试和追溯转换历史
|
|
|
|
|
+
|
|
|
|
|
+## 🔧 代码实现
|
|
|
|
|
+
|
|
|
|
|
+### 核心函数
|
|
|
|
|
+
|
|
|
|
|
+```python
|
|
|
|
|
+@staticmethod
|
|
|
|
|
+def convert_large_text_to_table(
|
|
|
|
|
+ layout_results: List[Dict[str, Any]],
|
|
|
|
|
+ image_shape: Tuple[int, int],
|
|
|
|
|
+ min_area_ratio: float = 0.25,
|
|
|
|
|
+ min_width_ratio: float = 0.4,
|
|
|
|
|
+ min_height_ratio: float = 0.3
|
|
|
|
|
+) -> List[Dict[str, Any]]:
|
|
|
|
|
+ """
|
|
|
|
|
+ 将大面积的文本块转换为表格
|
|
|
|
|
+
|
|
|
|
|
+ 判断规则:
|
|
|
|
|
+ 1. 面积占比:占页面面积超过 min_area_ratio(默认25%)
|
|
|
|
|
+ 2. 尺寸比例:宽度和高度都超过一定比例(避免细长条)
|
|
|
|
|
+ 3. 不与其他表格重叠:如果已有表格,不转换
|
|
|
|
|
+ """
|
|
|
|
|
+ # 实现逻辑...
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 调用位置
|
|
|
|
|
+
|
|
|
|
|
+```python
|
|
|
|
|
+# 在 pipeline_manager_v2.py 中
|
|
|
|
|
+# 2.6 将大面积文本块转换为表格(后处理)
|
|
|
|
|
+if layout_results:
|
|
|
|
|
+ convert_large_text = self.config.get('layout', {}).get('convert_large_text_to_table', True)
|
|
|
|
|
+ if convert_large_text:
|
|
|
|
|
+ image_shape = (detection_image.shape[0], detection_image.shape[1])
|
|
|
|
|
+ layout_results = LayoutUtils.convert_large_text_to_table(
|
|
|
|
|
+ layout_results,
|
|
|
|
|
+ image_shape,
|
|
|
|
|
+ min_area_ratio=self.config.get('layout', {}).get('min_text_area_ratio', 0.25),
|
|
|
|
|
+ min_width_ratio=self.config.get('layout', {}).get('min_text_width_ratio', 0.4),
|
|
|
|
|
+ min_height_ratio=self.config.get('layout', {}).get('min_text_height_ratio', 0.3)
|
|
|
|
|
+ )
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+## 📈 效果评估
|
|
|
|
|
+
|
|
|
|
|
+### 转换前的问题
|
|
|
|
|
+
|
|
|
|
|
+- ❌ 大表格被识别为文本
|
|
|
|
|
+- ❌ 无法使用VLM进行表格结构识别
|
|
|
|
|
+- ❌ 表格内容无法正确提取
|
|
|
|
|
+
|
|
|
|
|
+### 转换后的改进
|
|
|
|
|
+
|
|
|
|
|
+- ✅ 大表格被正确识别为表格类型
|
|
|
|
|
+- ✅ 可以使用VLM进行表格结构识别
|
|
|
|
|
+- ✅ 表格内容可以正确提取和处理
|
|
|
|
|
+
|
|
|
|
|
+## 🎯 最佳实践
|
|
|
|
|
+
|
|
|
|
|
+1. **默认启用**:对于财务报表等包含大表格的文档,建议启用
|
|
|
|
|
+2. **阈值调优**:根据实际文档类型调整阈值
|
|
|
|
|
+3. **监控日志**:查看转换日志,确认转换效果
|
|
|
|
|
+4. **验证结果**:检查转换后的表格是否正确处理
|
|
|
|
|
+
|
|
|
|
|
+## 📝 日志输出
|
|
|
|
|
+
|
|
|
|
|
+转换时会输出详细日志:
|
|
|
|
|
+
|
|
|
|
|
+```
|
|
|
|
|
+🔄 Converted large text block to table: area=43.6%, size=76.7%×59.8%, bbox=[226, 288, 1495, 1685]
|
|
|
|
|
+✅ Converted 1 large text block(s) to table(s)
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+## 🔄 与其他功能的关系
|
|
|
|
|
+
|
|
|
|
|
+### 与VLM表格识别
|
|
|
|
|
+
|
|
|
|
|
+- 转换后的表格会进入VLM处理流程
|
|
|
|
|
+- VLM会识别表格结构(HTML格式)
|
|
|
|
|
+- OCR会提取单元格文本和坐标
|
|
|
|
|
+
|
|
|
|
|
+### 与跨页表格合并
|
|
|
|
|
+
|
|
|
|
|
+- 转换后的表格可以参与跨页合并
|
|
|
|
|
+- 需要确保转换后的表格类型正确
|
|
|
|
|
+
|
|
|
|
|
+### 与元素分类
|
|
|
|
|
+
|
|
|
|
|
+- 转换在元素分类之前进行
|
|
|
|
|
+- 转换后的表格会被正确分类到 `TABLE_BODY_CATEGORIES`
|
|
|
|
|
+
|
|
|
|
|
+## 📚 相关文档
|
|
|
|
|
+
|
|
|
|
|
+- [模型统一框架.md](./模型统一框架.md) - 整体架构说明
|
|
|
|
|
+- [OCR识别差异分析与改进方案.md](./OCR识别差异分析与改进方案.md) - OCR优化说明
|
|
|
|
|
+
|