fix(ocr): 引擎对比长度保护——Windows OCR截断丢消息
根因:_pick_ocr_text() 用 score >= score 选引擎,Windows OCR 虽然行数少(8行 vs EasyOCR 19行),但因垃圾字符少、空格惩罚低, 分数可能略高或持平,导致完整 EasyOCR 文本被丢弃。 修复: - 新增长度保护:当一方行数 >=1.5x 且字符数 >=1.3x 另一方时, 分数差 <10 分则强制选更长文本 - 引擎对比日志增加行数/字符数/分数差,方便排查 - 不影响分数差距大时的正常选择逻辑
This commit is contained in:
+29
-3
@@ -1366,20 +1366,46 @@ class MessageMonitor:
|
|||||||
return max(score, 0.0)
|
return max(score, 0.0)
|
||||||
|
|
||||||
def _pick_ocr_text(self, win_text: str, easy_text: str, image: Image.Image) -> tuple:
|
def _pick_ocr_text(self, win_text: str, easy_text: str, image: Image.Image) -> tuple:
|
||||||
"""双引擎对比,选质量更高的结果。日志记录引擎胜负统计。返回 (text, engine_name)。"""
|
"""双引擎对比,选质量更高的结果。日志记录引擎胜负统计。返回 (text, engine_name)。
|
||||||
|
|
||||||
|
⭐ 长度保护:当一引擎识别行数显著多于另一方(>=1.5x)时,
|
||||||
|
即使分数略低也优先选更长文本——避免 Windows OCR 截断丢消息。
|
||||||
|
"""
|
||||||
if not easy_text:
|
if not easy_text:
|
||||||
return (win_text, "windows")
|
return (win_text, "windows")
|
||||||
if not win_text:
|
if not win_text:
|
||||||
return (easy_text, "easyocr")
|
return (easy_text, "easyocr")
|
||||||
win_score = self._score_ocr_text(win_text)
|
win_score = self._score_ocr_text(win_text)
|
||||||
easy_score = self._score_ocr_text(easy_text)
|
easy_score = self._score_ocr_text(easy_text)
|
||||||
|
win_lines = len([l for l in win_text.split('\n') if l.strip()])
|
||||||
|
easy_lines = len([l for l in easy_text.split('\n') if l.strip()])
|
||||||
|
win_len = len(win_text.strip())
|
||||||
|
easy_len = len(easy_text.strip())
|
||||||
|
|
||||||
|
# 长度保护:一方行数 >= 1.5x 另一方 → 倾向更长文本(分数差 < 10 时触发)
|
||||||
chosen = "windows" if win_score >= easy_score else "easyocr"
|
chosen = "windows" if win_score >= easy_score else "easyocr"
|
||||||
|
score_diff = abs(win_score - easy_score)
|
||||||
|
if score_diff < 10:
|
||||||
|
if easy_lines >= win_lines * 1.5 and easy_len > win_len * 1.3:
|
||||||
|
chosen = "easyocr"
|
||||||
|
logger.debug(
|
||||||
|
f"[ocr] 长度保护: easy行数{easy_lines}>=1.5x win行数{win_lines},"
|
||||||
|
f"分数差仅{score_diff:.1f},强制选easyocr"
|
||||||
|
)
|
||||||
|
elif win_lines >= easy_lines * 1.5 and win_len > easy_len * 1.3:
|
||||||
|
chosen = "windows"
|
||||||
|
logger.debug(
|
||||||
|
f"[ocr] 长度保护: win行数{win_lines}>=1.5x easy行数{easy_lines},"
|
||||||
|
f"分数差仅{score_diff:.1f},强制选windows"
|
||||||
|
)
|
||||||
|
|
||||||
self._ocr_engine_wins[chosen] = self._ocr_engine_wins.get(chosen, 0) + 1
|
self._ocr_engine_wins[chosen] = self._ocr_engine_wins.get(chosen, 0) + 1
|
||||||
total = sum(self._ocr_engine_wins.values())
|
total = sum(self._ocr_engine_wins.values())
|
||||||
ratio = self._ocr_engine_wins.get(chosen, 0) / max(total, 1)
|
ratio = self._ocr_engine_wins.get(chosen, 0) / max(total, 1)
|
||||||
logger.debug(
|
logger.debug(
|
||||||
f"[ocr] 引擎对比: win={win_score:.1f} vs easy={easy_score:.1f} → 选{chosen} "
|
f"[ocr] 引擎对比: win={win_score:.1f}(行{win_lines},字符{win_len}) "
|
||||||
f"(胜率{ratio:.0%}, {total}轮)"
|
f"vs easy={easy_score:.1f}(行{easy_lines},字符{easy_len}) "
|
||||||
|
f"→ 选{chosen}(分数差{score_diff:.1f}, 胜率{ratio:.0%}, {total}轮)"
|
||||||
)
|
)
|
||||||
return (win_text, chosen) if chosen == "windows" else (easy_text, chosen)
|
return (win_text, chosen) if chosen == "windows" else (easy_text, chosen)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user