Procházet zdrojové kódy

feat: Add documentation for grid recovery scenarios in UNet, detailing causes of empty rows/columns and how `compress_grid` addresses them.

zhch158_admin před 2 dny
rodič
revize
26b500f344

+ 79 - 0
docs/ocr_tools/universal_doc_parser/unet表格识别-grid_recovery.md

@@ -0,0 +1,79 @@
+
+## 产生空行/空列的情况
+```@ocr_platform/ocr_tools/universal_doc_parser/models/adapters/wired_table/grid_recovery.py:466 recover_grid_structure什么情况会产生空行或空列?
+```
+
+### 1. 网格线检测产生的额外分割线
+```352:380:ocr_platform/ocr_tools/universal_doc_parser/models/adapters/wired_table/grid_recovery.py
+    def recover_grid_structure(bboxes: List[List[float]]) -> List[Dict]:
+        # ...
+        # 1. 识别行分割线 (Y轴)
+        y_coords = []
+        for b in bboxes:
+            y_coords.append(b[1])  # top
+            y_coords.append(b[3])  # bottom
+        
+        row_dividers = GridRecovery.find_grid_lines(y_coords, tolerance=5, min_support=2)
+```
+
+- 问题:`find_grid_lines` 收集所有单元格的 top/bottom(或 left/right)坐标,聚类后生成网格线。
+- 如果某些位置有 ≥2 个坐标对齐(满足 `min_support=2`),就会产生一条网格线。
+- 结果:可能产生比实际行/列更多的网格线,从而产生空的行区间或列区间。
+
+### 2. 单元格匹配时未覆盖某些行/列区间
+```411:428:ocr_platform/ocr_tools/universal_doc_parser/models/adapters/wired_table/grid_recovery.py
+            # 匹配行
+            matched_rows = []
+            for r in row_intervals:
+                inter_top = max(b_top, r["top"])
+                inter_bottom = min(b_bottom, r["bottom"])
+                inter_h = max(0, inter_bottom - inter_top)
+                
+                if r["height"] > 0 and (inter_h / r["height"] > 0.5 or inter_h / b_h > 0.5):
+                    matched_rows.append(r["index"])
+```
+
+- 问题:匹配条件为 `inter_h / r["height"] > 0.5` 或 `inter_h / b_h > 0.5`。
+- 如果某个行/列区间很小,且没有单元格满足该条件,该区间就不会被匹配。
+- 结果:该行/列区间没有单元格的起始位置,成为空行/空列。
+
+### 3. rowspan/colspan 跨越的间隙行/列
+```500:504:ocr_platform/ocr_tools/universal_doc_parser/models/adapters/wired_table/grid_recovery.py
+        for cell in cells:
+            if cell["row"] < max_row:
+                row_occupied[cell["row"]] = True  # 只标记起始行
+            if cell["col"] < max_col:
+                col_occupied[cell["col"]] = True  # 只标记起始列
+```
+
+- 问题:`compress_grid` 只标记单元格的起始行/列(`cell["row"]` 和 `cell["col"]`)。
+- 如果一个单元格跨越多个行/列(rowspan/colspan > 1),中间的行/列如果没有其他单元格起始,就不会被标记为占用。
+- 结果:这些中间行/列成为空行/空列。
+
+### 4. 表格边缘的额外网格线
+- 如果表格边缘的单元格边界对齐形成网格线,但该行/列区间内没有单元格,也会产生空行/空列。
+
+## 示例场景
+
+假设有以下单元格:
+- Cell A: row=0, rowspan=3(跨越行 0, 1, 2)
+- Cell B: row=3, rowspan=1(只在行 3)
+
+如果网格线检测产生了行 0, 1, 2, 3, 4 的分割线:
+- 行 0: 被 Cell A 占用(起始)
+- 行 1: 被 Cell A 跨越,但没有单元格起始 → 空行
+- 行 2: 被 Cell A 跨越,但没有单元格起始 → 空行
+- 行 3: 被 Cell B 占用(起始)
+- 行 4: 没有单元格 → 空行
+
+`compress_grid` 会移除这些空行,最终得到紧凑的网格。
+
+## 总结
+
+空行/空列主要来自:
+1. 网格线检测产生的额外分割线
+2. 单元格匹配条件未覆盖某些区间
+3. rowspan/colspan 跨越的中间行/列
+4. 表格边缘的额外网格线
+
+`compress_grid` 会移除这些空行/空列,确保最终网格紧凑。