Explorar o código

添加“全局动态规划与行级动态规划详解”

zhch158_admin hai 2 días
pai
achega
6d9159d719
Modificáronse 1 ficheiros con 97 adicións e 0 borrados
  1. 97 0
      merger/Tablecells匹配-动态规划.md

+ 97 - 0
merger/Tablecells匹配-动态规划.md

@@ -331,3 +331,100 @@ DP 找的是“主干路径”,可能会漏掉一些没能进入最优路径
 3.  **天然处理合并**:
     *   DP 的内层循环 `candidate_boxes = row_boxes[prev_j:j]` 天然支持将多个 Box 合并给一个 Cell,不需要单独写 `merged_bboxes` 逻辑。
 
+# 全局动态规划与行级动态规划详解
+
+结合 `ocr_verify/merger/table_cell_matcher.py` 代码与提供的流水分析数据,为您讲解这两种动态规划在表格匹配中的应用。
+
+## 核心背景
+
+表格匹配的任务是将 **HTML 表格结构**(来自 PP-Structure)与 **OCR 文字框**(来自 PaddleOCR)进行对齐。由于 OCR 结果可能存在漏检、误检、多行被识别为单行或单行被切分为多行的情况,简单的顺序匹配容易出错。因此,代码采用了**两级动态规划(DP)**策略。
+
+---
+
+## 1. 全局动态规划 (Global DP):行级匹配
+
+**目标**:将 HTML 的 `<tr>` 行与 OCR 的“行组”(Grouped Boxes)进行对齐。
+
+### 代码位置
+`TableCellMatcher._match_html_rows_to_paddle_groups` (Line 548)
+
+### 算法原理
+*   **状态定义**:`dp[i][j]` 表示 HTML 前 `i` 行与 OCR 前 `j` 个行组匹配的最大得分。
+*   **核心挑战**:HTML 行数与 OCR 行组数往往不一致(例如 OCR 将一行文字拆成了两行,或者漏掉了某一行)。
+*   **转移方程**:
+    1.  **匹配 (Match)**:HTML 第 `i` 行与 OCR 第 `j` 组(或合并 `j` 到 `j+k` 组)匹配。
+        *   `score = similarity(html_text, ocr_text) - penalty`
+    2.  **跳过 HTML (Skip HTML)**:HTML 第 `i` 行在 OCR 中没找到对应(可能是 OCR 漏检)。
+        *   `dp[i][j] = dp[i-1][j] - SKIP_HTML_PENALTY`
+    3.  **跳过 OCR (Skip Paddle)**:OCR 第 `j` 组是噪音,不匹配任何 HTML 行(通过 `gap` 参数实现)。
+
+### 实例演示
+**数据来源**:`A用户_单元格扫描流水_page_007.json`
+
+假设 HTML 结构如下(简化):
+*   **HTML Row 0**: `1000107... 2024-07-21...` (交易记录1)
+*   **HTML Row 1**: `1000107... 2024-07-21...` (交易记录2)
+
+OCR 分组结果(按 Y 坐标聚类):
+*   **OCR Group 0**: `1000107... 2024-07-21...` (对应 HTML Row 0)
+*   **OCR Group 1**: `1000107... 2024-07-21...` (对应 HTML Row 1)
+*   **OCR Group 2**: `(噪音/水印)`
+
+**DP 过程**:
+1.  `dp[0][0]` 计算 HTML Row 0 与 OCR Group 0 的相似度,得分高。
+2.  `dp[1][1]` 基于 `dp[0][0]`,计算 HTML Row 1 与 OCR Group 1 的相似度,得分高。
+3.  如果 OCR Group 2 是噪音,算法会发现 HTML Row 2 与 OCR Group 2 匹配度极低,可能会选择跳过 OCR Group 2,或者如果 HTML 结束了,OCR Group 2 就成为“未匹配组”。
+
+---
+
+## 2. 行级动态规划 (Row-level DP):单元格匹配
+
+**目标**:在已对齐的某一行内,将 HTML 的 `<td>` 单元格与该行的 OCR Boxes 进行对齐。
+
+### 代码位置
+`TableCellMatcher._match_cells_in_row_dp` (Line 171)
+
+### 算法原理
+*   **状态定义**:`dp[i][j]` 表示该行前 `i` 个 HTML 单元格消耗了前 `j` 个 OCR Boxes 的最大得分。
+*   **核心挑战**:一个单元格可能对应多个 OCR Box(例如长文本被切断),或者某个单元格内容 OCR 漏检。
+*   **转移方程**:
+    1.  **匹配 (Match)**:HTML 单元格 `i` 匹配 OCR Boxes `prev_j` 到 `j` 的合并内容。
+        *   `score = similarity(cell_text, merged_box_text)`
+        *   这里允许合并最多 `MAX_MERGE` (5) 个 Box。
+    2.  **单元格缺失 (Cell Missing)**:当前 HTML 单元格为空或 OCR 没识别到。
+        *   `dp[i][j] = dp[i-1][j]` (继承上一个状态,相当于当前单元格不消耗 Box)
+
+### 实例演示
+**数据来源**:`A用户_单元格扫描流水_page_007.json` (HTML Row 0)
+
+**HTML 单元格**:
+1.  Cell 0: `100010710124072100059119291975743003` (长数字)
+2.  Cell 1: `2024-07-2107:50:38` (时间)
+3.  Cell 2: `扫二维码付款`
+
+**OCR Boxes (按 X 排序)**:
+1.  Box 0: `100010710124072100059119291975743003`
+2.  Box 1: `2024-07-21`
+3.  Box 2: `07:50:38` (假设时间被切分为两个 Box)
+4.  Box 3: `扫二维码付款`
+
+**DP 过程**:
+1.  **i=1 (Cell 0)**:
+    *   尝试匹配 Box 0: 相似度 100%,得分高。
+    *   `dp[1][1]` 更新为高分。
+2.  **i=2 (Cell 1)**:
+    *   尝试匹配 Box 1: `2024-07-21` vs `2024-07-2107:50:38` -> 相似度一般。
+    *   尝试匹配 Box 1+2: `2024-07-21 07:50:38` vs `2024-07-2107:50:38` -> 相似度极高。
+    *   算法选择合并 Box 1 和 Box 2 赋给 Cell 1。
+    *   `dp[2][3]` 更新为 `dp[1][1] + score`。
+3.  **i=3 (Cell 2)**:
+    *   尝试匹配 Box 3: 相似度 100%。
+    *   `dp[3][4]` 更新。
+
+最终回溯路径:Cell 0 <- [Box 0], Cell 1 <- [Box 1, Box 2], Cell 2 <- [Box 3]。
+
+## 总结
+
+*   **全局 DP** 解决了“行对齐”问题,处理行层面的漏检和错位。
+*   **行级 DP** 解决了“单元格对齐”问题,处理单元格内的碎片化识别和内容匹配。
+*   两者结合,实现了从整页到细节的高精度表格还原。