fix: 降低OCR预处理锐化/对比度,增强偏旁碎片检测
This commit is contained in:
+41
-9
@@ -1376,12 +1376,13 @@ class MessageMonitor:
|
|||||||
# 图像预处理:提升 Windows OCR 识别准确率
|
# 图像预处理:提升 Windows OCR 识别准确率
|
||||||
# Windows OCR 对低 DPI/未处理截图识别差——CJK 空格、字符混淆
|
# Windows OCR 对低 DPI/未处理截图识别差——CJK 空格、字符混淆
|
||||||
# 2x LANCZOS 放大 + 锐化 + 对比度增强
|
# 2x LANCZOS 放大 + 锐化 + 对比度增强
|
||||||
|
# ⚠️ 锐化/对比度过高会导致汉字边缘断裂成偏旁部首
|
||||||
im_original = im # 保留原图,bad allocation 时降级
|
im_original = im # 保留原图,bad allocation 时降级
|
||||||
try:
|
try:
|
||||||
im = im.resize((im.width * 2, im.height * 2), Image.LANCZOS)
|
im = im.resize((im.width * 2, im.height * 2), Image.LANCZOS)
|
||||||
im = ImageEnhance.Sharpness(im).enhance(1.8)
|
im = ImageEnhance.Sharpness(im).enhance(1.2) # 降低锐化,防字符断裂
|
||||||
im = ImageEnhance.Contrast(im).enhance(1.4)
|
im = ImageEnhance.Contrast(im).enhance(1.2) # 降低对比度,保持笔画连贯
|
||||||
logger.debug(f"[ocr] 预处理: resize 2x + sharpen(1.8) + contrast(1.4)")
|
logger.debug(f"[ocr] 预处理: resize 2x + sharpen(1.2) + contrast(1.2)")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.debug(f"[ocr] 预处理失败(跳过): {e}")
|
logger.debug(f"[ocr] 预处理失败(跳过): {e}")
|
||||||
|
|
||||||
@@ -1485,11 +1486,12 @@ class MessageMonitor:
|
|||||||
self._ocr_unchanged.pop("wechat", None)
|
self._ocr_unchanged.pop("wechat", None)
|
||||||
|
|
||||||
# 图像预处理(同 QQ)
|
# 图像预处理(同 QQ)
|
||||||
|
# ⚠️ 锐化/对比度过高会导致汉字边缘断裂成偏旁部首
|
||||||
im_original = im # 保留原图,bad allocation 时降级
|
im_original = im # 保留原图,bad allocation 时降级
|
||||||
try:
|
try:
|
||||||
im = im.resize((im.width * 2, im.height * 2), Image.LANCZOS)
|
im = im.resize((im.width * 2, im.height * 2), Image.LANCZOS)
|
||||||
im = ImageEnhance.Sharpness(im).enhance(1.8)
|
im = ImageEnhance.Sharpness(im).enhance(1.2) # 降低锐化,防字符断裂
|
||||||
im = ImageEnhance.Contrast(im).enhance(1.4)
|
im = ImageEnhance.Contrast(im).enhance(1.2) # 降低对比度,保持笔画连贯
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.debug(f"[wechat] OCR 预处理失败(跳过): {e}")
|
logger.debug(f"[wechat] OCR 预处理失败(跳过): {e}")
|
||||||
|
|
||||||
@@ -1976,10 +1978,25 @@ class MessageMonitor:
|
|||||||
# —— OCR 偏旁碎片过滤:氵、亻、讠、扌等 CJK 偏旁不是完整汉字 ——
|
# —— OCR 偏旁碎片过滤:氵、亻、讠、扌等 CJK 偏旁不是完整汉字 ——
|
||||||
# 从 unicode_radicals.md 加载偏旁字符集,统计出现次数
|
# 从 unicode_radicals.md 加载偏旁字符集,统计出现次数
|
||||||
# ≥1 个偏旁字符 → 判定为 OCR 把汉字拆碎了,整段丢弃
|
# ≥1 个偏旁字符 → 判定为 OCR 把汉字拆碎了,整段丢弃
|
||||||
|
# ⚠️ 增强:连续偏旁检测(如"亻乍弊")—— 偏旁数≥2 且文本短(<20字)时更严格
|
||||||
radical_cnt = sum(1 for c in line if c in _RADICAL_CHARS)
|
radical_cnt = sum(1 for c in line if c in _RADICAL_CHARS)
|
||||||
if radical_cnt >= 1:
|
if radical_cnt >= 1:
|
||||||
logger.debug(f"[{platform}] OCR 过滤: 偏旁碎片(radical={radical_cnt}) line={line!r}")
|
# 计算非空格文本长度
|
||||||
continue
|
text_len = len(line.replace(' ', ''))
|
||||||
|
# 短文本(<20字)出现偏旁 → 高概率碎片
|
||||||
|
if text_len < 20:
|
||||||
|
logger.debug(f"[{platform}] OCR 过滤: 偏旁碎片(短文本radical={radical_cnt},len={text_len}) line={line!r}")
|
||||||
|
continue
|
||||||
|
# 长文本但偏旁比例高(>10%)→ 碎片
|
||||||
|
elif text_len > 0 and radical_cnt / text_len > 0.1:
|
||||||
|
logger.debug(f"[{platform}] OCR 过滤: 偏旁碎片(比例{radical_cnt}/{text_len}) line={line!r}")
|
||||||
|
continue
|
||||||
|
# 单个偏旁但文本很长(>50字)→ 可能是正常文本包含偏旁字符(罕见),放行
|
||||||
|
elif radical_cnt == 1 and text_len > 50:
|
||||||
|
pass # 放行
|
||||||
|
else:
|
||||||
|
logger.debug(f"[{platform}] OCR 过滤: 偏旁碎片(radical={radical_cnt}) line={line!r}")
|
||||||
|
continue
|
||||||
# —— 系统配置内容过滤:SMTP/邮件地址/代码片段不是用户消息 ——
|
# —— 系统配置内容过滤:SMTP/邮件地址/代码片段不是用户消息 ——
|
||||||
if re.search(r'@example|smtp|\.py\b|\.bat\b|\.sh\b|//.*\.\w{2,4}\b', line, re.IGNORECASE):
|
if re.search(r'@example|smtp|\.py\b|\.bat\b|\.sh\b|//.*\.\w{2,4}\b', line, re.IGNORECASE):
|
||||||
logger.debug(f"[{platform}] OCR 过滤: 系统配置内容 line={line!r}")
|
logger.debug(f"[{platform}] OCR 过滤: 系统配置内容 line={line!r}")
|
||||||
@@ -3659,10 +3676,25 @@ class MessageMonitor:
|
|||||||
# === 偏旁碎片过滤:氵、亻、讠、扌等 CJK 偏旁不是完整汉字 ===
|
# === 偏旁碎片过滤:氵、亻、讠、扌等 CJK 偏旁不是完整汉字 ===
|
||||||
# 从 unicode_radicals.md 加载偏旁字符集,统计出现次数
|
# 从 unicode_radicals.md 加载偏旁字符集,统计出现次数
|
||||||
# ≥1 个偏旁字符 → 判定为 OCR 把汉字拆碎了,整段丢弃
|
# ≥1 个偏旁字符 → 判定为 OCR 把汉字拆碎了,整段丢弃
|
||||||
|
# ⚠️ 增强:连续偏旁检测(如"亻乍弊")—— 偏旁数≥2 且文本短(<20字)时更严格
|
||||||
radical_cnt = sum(1 for c in ts if c in _RADICAL_CHARS)
|
radical_cnt = sum(1 for c in ts if c in _RADICAL_CHARS)
|
||||||
if radical_cnt >= 1:
|
if radical_cnt >= 1:
|
||||||
logger.debug(f"[{platform}] Poll过滤: 偏旁碎片(radical={radical_cnt}) ts={ts!r}")
|
# 计算非空格文本长度
|
||||||
continue
|
text_len = len(ts.replace(' ', ''))
|
||||||
|
# 短文本(<20字)出现偏旁 → 高概率碎片
|
||||||
|
if text_len < 20:
|
||||||
|
logger.debug(f"[{platform}] Poll过滤: 偏旁碎片(短文本radical={radical_cnt},len={text_len}) ts={ts!r}")
|
||||||
|
continue
|
||||||
|
# 长文本但偏旁比例高(>10%)→ 碎片
|
||||||
|
elif text_len > 0 and radical_cnt / text_len > 0.1:
|
||||||
|
logger.debug(f"[{platform}] Poll过滤: 偏旁碎片(比例{radical_cnt}/{text_len}) ts={ts!r}")
|
||||||
|
continue
|
||||||
|
# 单个偏旁但文本很长(>50字)→ 可能是正常文本包含偏旁字符(罕见),放行
|
||||||
|
elif radical_cnt == 1 and text_len > 50:
|
||||||
|
pass # 放行
|
||||||
|
else:
|
||||||
|
logger.debug(f"[{platform}] Poll过滤: 偏旁碎片(radical={radical_cnt}) ts={ts!r}")
|
||||||
|
continue
|
||||||
# === 系统配置内容过滤:SMTP/邮件地址/代码片段不是用户消息 ===
|
# === 系统配置内容过滤:SMTP/邮件地址/代码片段不是用户消息 ===
|
||||||
if re.search(r'@example|smtp|\.py\b|\.bat\b|\.sh\b|//.*\.\w{2,4}\b', ts, re.IGNORECASE):
|
if re.search(r'@example|smtp|\.py\b|\.bat\b|\.sh\b|//.*\.\w{2,4}\b', ts, re.IGNORECASE):
|
||||||
logger.debug(f"[{platform}] Poll过滤: 系统配置内容 ts={ts!r}")
|
logger.debug(f"[{platform}] Poll过滤: 系统配置内容 ts={ts!r}")
|
||||||
|
|||||||
Reference in New Issue
Block a user