""" OCR 结果后处理(纯逻辑,无 IO)。 对 OCR 返回的原始结果做结构化解析、置信度过滤、阅读顺序修正。 不依赖任何外部资源,可独立测试。 """ from __future__ import annotations from typing import Any def filter_low_confidence( blocks: list[dict[str, Any]], threshold: float = 0.5, ) -> list[dict[str, Any]]: """过滤低置信度结果。 Args: blocks: 原始 OCR 块列表。 threshold: 置信度阈值(默认 0.5)。 Returns: 过滤后的块列表。 """ return [b for b in blocks if b.get("confidence", 0) >= threshold] def merge_adjacent_lines( blocks: list[dict[str, Any]], y_tolerance: float = 10.0, ) -> list[dict[str, Any]]: """合并同一行的相邻块。 Args: blocks: OCR 块列表(需含 bbox 坐标)。 y_tolerance: Y 轴容差(px),同一行最大差异。 Returns: 合并后的块列表。 """ if not blocks: return [] sorted_blocks = sorted(blocks, key=lambda b: (_center_y(b), _center_x(b))) merged: list[dict[str, Any]] = [] current = sorted_blocks[0] for block in sorted_blocks[1:]: if abs(_center_y(block) - _center_y(current)) <= y_tolerance: current["text"] += block["text"] current["confidence"] = max(current["confidence"], block["confidence"]) else: merged.append(current) current = block merged.append(current) return merged def extract_text( blocks: list[dict[str, Any]], separator: str = "", ) -> str: """从 OCR 块中提取纯文本。 Args: blocks: OCR 块列表。 separator: 块之间的分隔符。 Returns: 拼接后的文本。 """ return separator.join(b["text"] for b in blocks) def _center_y(block: dict[str, Any]) -> float: """获取块的中心 Y 坐标。""" pts = block.get("bbox", {}).get("points", block.get("bbox", [])) if pts and isinstance(pts, list) and len(pts) > 0: ys = [p[1] for p in pts if isinstance(p, (list, tuple)) and len(p) >= 2] return sum(ys) / len(ys) if ys else 0.0 return 0.0 def _center_x(block: dict[str, Any]) -> float: """获取块的中心 X 坐标。""" pts = block.get("bbox", {}).get("points", block.get("bbox", [])) if pts and isinstance(pts, list) and len(pts) > 0: xs = [p[0] for p in pts if isinstance(p, (list, tuple)) and len(p) >= 2] return sum(xs) / len(xs) if xs else 0.0 return 0.0