如何用OpenCV和Pytesseract实时识别全屏游戏比分与计时器
问题解决:游戏比分/计时器OCR识别错误与代码报错修复
一、先解决代码的TypeError报错
报错出在img = cv2.imread(cap)这一行:cv2.imread()要求传入文件路径字符串,但ImageGrab.grab()返回的是PIL Image对象,直接传入会触发类型错误。
修复方法:把PIL Image转换成OpenCV兼容的格式(PIL默认是RGB通道,OpenCV默认用BGR,需要做通道转换):
# 替换原有的img = cv2.imread(cap) cap = ImageGrab.grab(bbox=(740, 260, 1070,300)) # PIL转OpenCV格式 img = cv2.cvtColor(np.array(cap), cv2.COLOR_RGB2BGR)
二、解决图形干扰导致的OCR识别错误
初始代码识别完整图时输出错误的“45”,核心原因包括:
- 图像中干扰线条破坏了OCR的字符分割逻辑
- PSM模式选择不当(原代码用
--psm 10是识别单个字符,不适合多字符/多区域场景) - 缺少针对性的图像预处理步骤
优化方案
- 针对性图像预处理:通过阈值过滤、放大、降噪消除干扰线条
- 分区域识别:把左比分、计时器、右比分三个区域分开裁剪,单独识别
- 配置正确的OCR参数:使用适配单行文本的PSM模式,加上字符白名单限制识别范围
修正后的完整代码
#!/usr/bin/env python3.8 import cv2 import numpy as np import pytesseract from PIL import ImageGrab # 若环境未自动识别tesseract,手动指定路径(示例为Windows路径) # pytesseract.pytesseract.tesseract_cmd = r'C:\Program Files\Tesseract-OCR\tesseract.exe' while True: # 捕获目标区域 cap = ImageGrab.grab(bbox=(740, 260, 1070, 300)) # PIL转OpenCV格式(RGB转BGR) img = cv2.cvtColor(np.array(cap), cv2.COLOR_RGB2BGR) # 1. 转灰度图 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 2. 二值化:自动计算阈值,过滤干扰线条保留文字 _, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU) # 3. 放大图像:小尺寸文字放大后OCR识别率更高 scale_ = 5 width = int(binary.shape[1] * scale_) height = int(binary.shape[0] * scale_) resized = cv2.resize(binary, (width, height), interpolation=cv2.INTER_CUBIC) # 4. 降噪:消除残留干扰点 filtered = cv2.medianBlur(resized, 5) # 5. 分区域裁剪:左比分、计时器、右比分 h, w = filtered.shape[:2] left_score = filtered[:, :w//3] timer = filtered[:, w//3:2*w//3] right_score = filtered[:, 2*w//3:] # 6. OCR识别:配置适配单行文本的参数+字符白名单 ocr_config = '--psm 7 --oem 3 -c tessedit_char_whitelist=0123456789:' print("左比分:", pytesseract.image_to_string(left_score, lang='eng', config=ocr_config).strip()) print("计时器:", pytesseract.image_to_string(timer, lang='eng', config=ocr_config).strip()) print("右比分:", pytesseract.image_to_string(right_score, lang='eng', config=ocr_config).strip()) print("---") # 可视化处理后的图像(可选) disp = cv2.cvtColor(filtered, cv2.COLOR_GRAY2BGR) cv2.line(disp, (w//3, 0), (w//3, h), (0, 0, 255), 2) cv2.line(disp, (2*w//3, 0), (2*w//3, h), (0, 0, 255), 2) cv2.namedWindow("Processed Image", cv2.WINDOW_NORMAL) cv2.imshow("Processed Image", disp) # 按ESC退出循环 if cv2.waitKey(1) == 27: break cv2.destroyAllWindows()
关键优化点说明
- 自动二值化:用
THRESH_OTSU自动计算阈值,适配不同游戏画面的亮度变化 - PSM模式:
--psm 7将图像视为单行文本,适配每个区域内的数字/计时器格式 - 字符白名单:限制只识别数字和冒号,避免OCR误把干扰线条识别为其他字符
- 分区域裁剪:避免不同区域的文字互相干扰,提升单区域识别准确率
内容的提问来源于stack exchange,提问作者Crazyfrog
相关产品推荐
相关产品推荐

