教程
Python OCR 识别游戏数字:用 Tesseract 读取计数器
在 MAS 中用 read_text 给游戏脚本加上 Python OCR 识别数字的能力:在 Asset Lab 中选区域,调整 psm 和颜色转换,解析计数器和计时器。
- Windows
- Mac
- 模拟器
- 云手机
- 手机
- Studio
- Python SDK
本页目录
模板匹配告诉游戏脚本某个按钮是否在屏幕上。Python OCR 识别数字则告诉它计数器写的是什么:体力 8/50、计时器 00:42、一个等级数字。这篇指南把 mas.read_text 从 Asset Lab 中画出的区域,带到一个在体力低于限值时停止的宏。适合任何在模拟器、云设备或手机上用 Python 写 Macro Automation Studio(MAS)宏的人。
开始之前
Tesseract OCR 在游戏脚本中如何工作
read_text 把一张截图,或者截图中某个区域内的部分,送给应用内的 Tesseract OCR。它返回引擎读到的内容。
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 区域
- 把设备切到有计数器的屏幕。
- 在 Code Editor 中打开资源面板,点击打开资源助手。Asset Lab 会带着实时画面打开。
- 围绕文字画一个框。留一点边距,但不要包含图标、边框或旁边的数字。
- 运行实时 OCR 测试。调整框直到文字能干净地读出来;测试用的引擎和你的脚本相同。
- 把四个坐标复制到
Region(x1, y1, x2, y2)。
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 | 任意位置的零散文字,无顺序 | 整屏、结果列表 |
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 之前预处理裁剪区域。
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_GRAY或RGB_TO_GRAY给出普通灰度,在BLACK_WHITE的阈值吃掉细笔画时有帮助。
在 Asset Lab 中对真实屏幕测试每个选项。没有 GRAYSCALE 成员;请用上面的名字之一。
设置超时
timeout_ms 默认 30000。psm=7 的紧凑区域远不到一秒就能返回;繁忙屏幕上的整屏 psm=11 读取要更久。在必须保持响应的循环中调低超时,并把调用包起来,让慢速读取不会结束运行。
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 是一个字符串,有时带空格、逗号、斜杠或多余的字母。用正则表达式解析它,并把”没有数字”当作一种真实结果。
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") 得到 1250;current_and_max("8/50") 得到 (8, 50)。O 和 l 的替换修复两种最常见的数字误读;只对纯数字的区域使用。
使用置信度
confidence 的范围是 0.0 到 1.0,覆盖 Tesseract 找到的所有词。干净的计数器读出来在 0.9 以上。它下降时,在采用这个值之前再读一次,并把两者都记录下来,方便之后看出规律。
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 都会截一帧新图,除非你传入一张。当循环一次要读几个区域时,截一张图传给每个调用;这样各个值就属于同一个瞬间。
shot = mas.take_screenshot()
energy = mas.read_text(region=ENERGY, screenshot=shot)
gold = mas.read_text(region=GOLD, screenshot=shot)用 Python 在安卓模拟器上识别文字:完整示例
这个脚本点击一个按钮,直到体力计数器低于限值或时间预算用完。把区域、图片 ID 和限值换成你的。
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 换成 0、l 换成 1,去掉逗号,并拒绝在两次读取之间剧烈跳变的值。
OCR 很慢
用 psm=11 和 eng_best 读整屏是最慢的情况。读区域,不读整屏;用 psm=7 或 8;把一张 screenshot 传给多个调用。model="eng_fast" 在干净文字上有帮助。如果一次读取仍然要几秒,区域可能太大了;一个计数器最多只需要几百像素宽的框。
没有任何自动化工具是 100% 无风险的,请负责任地使用自动化,并自行斟酌决定。
下一步
相关页面
谢谢。如果有哪里不对,请在 Discord 告诉我们。
有疑问? 在 Discord 提问