搜索

教程

Python OCR 识别游戏数字:用 Tesseract 读取计数器

在 MAS 中用 read_text 给游戏脚本加上 Python OCR 识别数字的能力:在 Asset Lab 中选区域,调整 psm 和颜色转换,解析计数器和计时器。

  • Windows
  • Mac
  • 模拟器
  • 云手机
  • 手机
  • Studio
  • Python SDK
进阶 更新于 阅读约 6 分钟
本页目录
  1. 开始之前
  2. Tesseract OCR 在游戏脚本中如何工作
  3. 在 Asset Lab 中选一个 OCR 区域
  4. 选择模型
  5. 选择页面分割模式
  6. 修复深色背景上的浅色文字
  7. 设置超时
  8. 从文字中解析数字
  9. 使用置信度
  10. 复用一张截图
  11. 用 Python 在安卓模拟器上识别文字:完整示例
  12. 故障排查
  13. OCR 返回空字符串
  14. 数字读错
  15. OCR 很慢

模板匹配告诉游戏脚本某个按钮是否在屏幕上。Python OCR 识别数字则告诉它计数器写的是什么:体力 8/50、计时器 00:42、一个等级数字。这篇指南把 mas.read_text 从 Asset Lab 中画出的区域,带到一个在体力低于限值时停止的宏。适合任何在模拟器、云设备或手机上用 Python 写 Macro Automation Studio(MAS)宏的人。

开始之前

  • Code Editor 中打开了一个代码型项目,并选择了一台设备。参见快速开始
  • 应用或游戏正显示你要读的文字,且分辨率是你会一直保持的那个。
  • 你已读过图像识别指南,或者知道 Region 是什么。

Tesseract OCR 在游戏脚本中如何工作

read_text 把一张截图,或者截图中某个区域内的部分,送给应用内的 Tesseract OCR。它返回引擎读到的内容。

python
def read_text(
    region: Region | None = None,
    screenshot: Screenshot | None = None,
    model: str = "eng_best",
    psm: int = 7,
    color_conversion: ColorConversion = ColorConversion.NONE,
    timeout_ms: int = 30000,
) -> TextRecognitionResult

结果是一个 TextRecognitionResult,有三个字段:text(字符串)、confidence(0.0 到 1.0)和 region(它看的位置)。读整屏也能用,但紧凑的区域更快、准确得多,所以第一步永远是区域。

在 Asset Lab 中选一个 OCR 区域

  1. 把设备切到有计数器的屏幕。
  2. 在 Code Editor 中打开资源面板,点击打开资源助手。Asset Lab 会带着实时画面打开。
  3. 围绕文字画一个框。留一点边距,但不要包含图标、边框或旁边的数字。
  4. 运行实时 OCR 测试。调整框直到文字能干净地读出来;测试用的引擎和你的脚本相同。
  5. 把四个坐标复制到 Region(x1, y1, x2, y2)
python
import mas
from mas import Region

ENERGY = Region(x1=380, y1=20, x2=520, y2=60)

result = mas.read_text(region=ENERGY)
print(repr(result.text), result.confidence)

调试时用 repr 打印:它会显示 print 隐藏的多余空格和换行。区域是截取分辨率下的像素坐标,所以让每台设备都保持那个分辨率。参见 Asset Lab

选择模型

model 选择 Tesseract 数据。"eng_best" 是默认值,也最准确;"eng_fast" 在干净文字上用准确度换速度;"eng" 是标准英文集。从默认开始,只在循环每分钟读几十次时才切换。

选择页面分割模式

psm 告诉 Tesseract 预期什么形状的文字。模式选错是结果为空或乱码最常见的原因。

psm预期适用于
7单行文字(默认)计数器、计时器、单行标签
8单个词孤立的数字或短角标
6一个统一的文字块对话框中的一段文字
11任意位置的零散文字,无顺序整屏、结果列表
python
level = mas.read_text(region=Region(x1=20, y1=20, x2=90, y2=60), psm=8)
dialog = mas.read_text(region=Region(x1=60, y1=300, x2=480, y2=600), psm=6)

取值范围是 0 到 13,但这四个几乎覆盖所有宏。单行区域什么都读不到时,先试 8,再试 6。

修复深色背景上的浅色文字

Tesseract 预期浅色背景上的深色文字。游戏计数器通常相反:深色条上的白色数字,常常还带彩色描边。color_conversion 在 OCR 之前预处理裁剪区域。

python
from mas import ColorConversion

energy = mas.read_text(
    region=ENERGY,
    psm=7,
    color_conversion=ColorConversion.BLACK_WHITE,
)
  • ColorConversion.NONE(默认)按原样发送像素。
  • ColorConversion.BLACK_WHITE 转为灰度并应用自动阈值,得到纯黑白。对嘈杂或彩色背景上的高对比度文字,这是最好的第一选择。
  • ColorConversion.BGR_TO_GRAYRGB_TO_GRAY 给出普通灰度,在 BLACK_WHITE 的阈值吃掉细笔画时有帮助。

在 Asset Lab 中对真实屏幕测试每个选项。没有 GRAYSCALE 成员;请用上面的名字之一。

设置超时

timeout_ms 默认 30000。psm=7 的紧凑区域远不到一秒就能返回;繁忙屏幕上的整屏 psm=11 读取要更久。在必须保持响应的循环中调低超时,并把调用包起来,让慢速读取不会结束运行。

python
try:
    result = mas.read_text(region=ENERGY, timeout_ms=5000)
except mas.RPCError as e:
    mas.log(f"OCR failed: {e}", level="warning")
    result = None

从文字中解析数字

result.text 是一个字符串,有时带空格、逗号、斜杠或多余的字母。用正则表达式解析它,并把”没有数字”当作一种真实结果。

python
import re

def first_int(text: str) -> int | None:
    cleaned = text.replace(",", "").replace("O", "0").replace("l", "1")
    m = re.search(r"\d+", cleaned)
    return int(m.group()) if m else None

def current_and_max(text: str) -> tuple[int | None, int | None]:
    m = re.search(r"(\d+)\s*/\s*(\d+)", text.replace(",", ""))
    return (int(m.group(1)), int(m.group(2))) if m else (None, None)

first_int("Energy 1,250") 得到 1250current_and_max("8/50") 得到 (8, 50)Ol 的替换修复两种最常见的数字误读;只对纯数字的区域使用。

使用置信度

confidence 的范围是 0.0 到 1.0,覆盖 Tesseract 找到的所有词。干净的计数器读出来在 0.9 以上。它下降时,在采用这个值之前再读一次,并把两者都记录下来,方便之后看出规律。

python
for attempt in range(3):
    result = mas.read_text(region=ENERGY, psm=7)
    value = first_int(result.text)
    if value is not None and result.confidence >= 0.8:
        break
    mas.log(f"Low confidence {result.confidence:.2f} for {result.text!r}", level="warning")

复用一张截图

每次 read_text 都会截一帧新图,除非你传入一张。当循环一次要读几个区域时,截一张图传给每个调用;这样各个值就属于同一个瞬间。

python
shot = mas.take_screenshot()
energy = mas.read_text(region=ENERGY, screenshot=shot)
gold = mas.read_text(region=GOLD, screenshot=shot)

用 Python 在安卓模拟器上识别文字:完整示例

这个脚本点击一个按钮,直到体力计数器低于限值或时间预算用完。把区域、图片 ID 和限值换成你的。

python
import random
import re
import sys
import time

import mas
from mas import ColorConversion, Region

images = mas.images({"attack_button": 101})

ENERGY = Region(x1=380, y1=20, x2=520, y2=60)
MIN_ENERGY = 10
TIME_BUDGET_S = 15 * 60


def read_energy() -> int | None:
    for _ in range(3):
        result = mas.read_text(
            region=ENERGY,
            psm=7,
            color_conversion=ColorConversion.BLACK_WHITE,
            timeout_ms=5000,
        )
        m = re.search(r"\d+", result.text.replace(",", "").replace("O", "0"))
        if m and result.confidence >= 0.7:
            return int(m.group())
        mas.log(f"Unclear energy {result.text!r} ({result.confidence:.2f})", level="warning")
        time.sleep(1)
    return None


def main():
    started = time.monotonic()
    unreadable = 0

    while time.monotonic() - started < TIME_BUDGET_S:
        energy = read_energy()
        if energy is None:
            unreadable += 1
            if unreadable >= 5:
                mas.log("Energy unreadable five times, stopping", level="error")
                sys.exit(2)
            continue
        unreadable = 0
        if energy < MIN_ENERGY:
            mas.log(f"Energy {energy} is below {MIN_ENERGY}, done")
            break

        button = mas.find_object_retry(images.attack_button, total_tries=3, time_sleep=2.0)
        if button is None:
            mas.log("Attack button not found", level="warning")
            continue
        mas.click(button.x, button.y, delay_ms=1000)
        time.sleep(random.uniform(0.8, 2.0))

    mas.log("Finished")


if __name__ == "__main__":
    main()

每次点击前都读一次,宏就不会作弊:它从不花掉它看不见的体力。unreadable 计数器把损坏的区域变成一次失败的运行,订阅 macro.failed 的 Webhook 可以报告它。参见循环与定时。如果你更愿意描述任务,MAS Agent 会替你测量区域并写出这段代码。

故障排查

OCR 返回空字符串

区域没框住文字、模式不对,或者文字是深色背景上的浅色。在 Asset Lab 中检查区域,单个数字把 psm 切到 8,文字块切到 6,并加上 color_conversion=ColorConversion.BLACK_WHITE。非常小的文字也会读成空。如果数字只有几个像素高,在模拟器显示设置中提高分辨率,并重新截取每个区域。

数字读错

零读成字母 O,一读成 l,八读成 B,或者逗号消失。首先收紧区域,让图标不碰到数字。然后试 BLACK_WHITE,笔画断裂时改用 BGR_TO_GRAY。最后在代码中归一化:在纯数字区域把 O 换成 0l 换成 1,去掉逗号,并拒绝在两次读取之间剧烈跳变的值。

OCR 很慢

psm=11eng_best 读整屏是最慢的情况。读区域,不读整屏;用 psm=78;把一张 screenshot 传给多个调用。model="eng_fast" 在干净文字上有帮助。如果一次读取仍然要几秒,区域可能太大了;一个计数器最多只需要几百像素宽的框。

没有任何自动化工具是 100% 无风险的,请负责任地使用自动化,并自行斟酌决定。

下一步

相关页面

这个页面有帮助吗?

有疑问? 在 Discord 提问