94 lines
2.5 KiB
Python
94 lines
2.5 KiB
Python
"""
|
|
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
|