|
|
@@ -564,90 +564,6 @@ class GridRecovery:
|
|
|
|
|
|
return grid_lines
|
|
|
|
|
|
- @staticmethod
|
|
|
- def _add_implicit_dividers_from_large_cells(
|
|
|
- bboxes: List[List[float]],
|
|
|
- row_dividers: List[float],
|
|
|
- col_dividers: List[float],
|
|
|
- min_gap_ratio: float = 0.1,
|
|
|
- min_span_ratio: float = 2.5,
|
|
|
- tolerance: float = 5.0
|
|
|
- ) -> tuple[List[float], List[float]]:
|
|
|
- """
|
|
|
- 补充分割线(简化版)
|
|
|
-
|
|
|
- 前提:连通域/矢量重构阶段已保证网格结构正确。
|
|
|
- 因此这里不再做“大框推断/出现次数(min_support)推断”,只做两件事:
|
|
|
-
|
|
|
- 1) **补全最外边界线**:确保 top/bottom/left/right 边界线存在
|
|
|
- 2) **近线合并**:若两条线距离 <= tolerance,则合并为一条(取均值)
|
|
|
-
|
|
|
- 说明:
|
|
|
- - 对于 Y 方向(行):强制使用 min(all_tops) / max(all_bottoms) 作为外边界
|
|
|
- (可解决你提到的 1511.0 这种只出现一次但是真实边界没被保留的问题)
|
|
|
- - 对于 X 方向(列):为避免极少数离群 bbox 把 left/right 拉偏导致“多出空白列”,
|
|
|
- 默认使用 5%/95% 分位数作为列外边界;若 min/max 与分位数足够接近(<= tolerance),
|
|
|
- 则退化为 min/max。
|
|
|
-
|
|
|
- Args:
|
|
|
- bboxes: 所有单元格 bbox 列表
|
|
|
- row_dividers: 已有行分割线(已排序)
|
|
|
- col_dividers: 已有列分割线(已排序)
|
|
|
- min_gap_ratio: 最小间距比例(相对于平均行高/列宽)
|
|
|
- min_span_ratio: 最小跨列/行比例(相对于平均宽度/高度)
|
|
|
- tolerance: 坐标容差(像素)
|
|
|
-
|
|
|
- Returns:
|
|
|
- (补充后的行分割线, 补充后的列分割线),已去重并排序
|
|
|
- """
|
|
|
- if not bboxes:
|
|
|
- return row_dividers, col_dividers
|
|
|
-
|
|
|
- def _merge_close_lines(lines: List[float], tol: float) -> List[float]:
|
|
|
- """按容差合并近似重复网格线(替代 set(),避免浮点近似导致多出窄列/窄行)"""
|
|
|
- if not lines:
|
|
|
- return []
|
|
|
- lines_sorted = sorted(float(x) for x in lines)
|
|
|
- merged: List[float] = []
|
|
|
- cluster: List[float] = [lines_sorted[0]]
|
|
|
- for x in lines_sorted[1:]:
|
|
|
- if abs(x - cluster[-1]) <= tol:
|
|
|
- cluster.append(x)
|
|
|
- else:
|
|
|
- merged.append(sum(cluster) / len(cluster))
|
|
|
- cluster = [x]
|
|
|
- merged.append(sum(cluster) / len(cluster))
|
|
|
- return merged
|
|
|
-
|
|
|
- # 统计 bbox 边界
|
|
|
- all_lefts = [b[0] for b in bboxes]
|
|
|
- all_rights = [b[2] for b in bboxes]
|
|
|
- all_tops = [b[1] for b in bboxes]
|
|
|
- all_bottoms = [b[3] for b in bboxes]
|
|
|
-
|
|
|
- hard_top = float(min(all_tops))
|
|
|
- hard_bottom = float(max(all_bottoms))
|
|
|
-
|
|
|
- # 列边界:默认用分位数抵抗离群点(避免多出空白列)
|
|
|
- lefts_sorted = sorted(float(x) for x in all_lefts)
|
|
|
- rights_sorted = sorted(float(x) for x in all_rights)
|
|
|
- q05 = int(round((len(lefts_sorted) - 1) * 0.05))
|
|
|
- q95 = int(round((len(rights_sorted) - 1) * 0.95))
|
|
|
- q05 = max(0, min(q05, len(lefts_sorted) - 1))
|
|
|
- q95 = max(0, min(q95, len(rights_sorted) - 1))
|
|
|
- robust_left = lefts_sorted[q05]
|
|
|
- robust_right = rights_sorted[q95]
|
|
|
- hard_left = float(min(all_lefts))
|
|
|
- hard_right = float(max(all_rights))
|
|
|
- # 如果 min/max 与分位数很接近(<= tolerance),说明不存在明显离群点,则使用 min/max
|
|
|
- col_left = hard_left if abs(hard_left - robust_left) <= tolerance else robust_left
|
|
|
- col_right = hard_right if abs(hard_right - robust_right) <= tolerance else robust_right
|
|
|
-
|
|
|
- # 仅做:补边界 + 合并近线
|
|
|
- new_row_dividers = _merge_close_lines(list(row_dividers) + [hard_top, hard_bottom], tol=tolerance)
|
|
|
- new_col_dividers = _merge_close_lines(list(col_dividers) + [col_left, col_right], tol=tolerance)
|
|
|
-
|
|
|
- return new_row_dividers, new_col_dividers
|
|
|
|
|
|
@staticmethod
|
|
|
def recover_grid_structure(bboxes: List[List[float]]) -> List[Dict]:
|
|
|
@@ -671,22 +587,14 @@ class GridRecovery:
|
|
|
y_coords.append(b[1])
|
|
|
y_coords.append(b[3])
|
|
|
|
|
|
- row_dividers_raw = GridRecovery.find_grid_lines(y_coords, tolerance=5, min_support=2)
|
|
|
+ row_dividers= GridRecovery.find_grid_lines(y_coords, tolerance=5, min_support=1)
|
|
|
|
|
|
# 2. 识别列分割线 (X轴)
|
|
|
x_coords = []
|
|
|
for b in bboxes:
|
|
|
x_coords.append(b[0])
|
|
|
x_coords.append(b[2])
|
|
|
- col_dividers_raw = GridRecovery.find_grid_lines(x_coords, tolerance=5, min_support=2)
|
|
|
-
|
|
|
- # 2.5. 从大框边界补充隐式分割线
|
|
|
- row_dividers, col_dividers = GridRecovery._add_implicit_dividers_from_large_cells(
|
|
|
- bboxes, row_dividers_raw, col_dividers_raw,
|
|
|
- min_gap_ratio=0.1, # 最小间距比例(相对于平均行高/列宽)
|
|
|
- min_span_ratio=2.5, # 跨2.5倍平均宽度/高度以上才考虑
|
|
|
- tolerance=5.0
|
|
|
- )
|
|
|
+ col_dividers= GridRecovery.find_grid_lines(x_coords, tolerance=5, min_support=1)
|
|
|
|
|
|
# 3. 构建网格结构
|
|
|
structured_cells = []
|