ガイド
Tesseract OCR をゲーム bot で使う: 数値の読み取り
MAS の read_text で Android ゲーム bot に Tesseract OCR を組み込む: Asset Lab で領域を選び、psm と色変換を調整し、カウンターやタイマーの数値を取り出します。
- Windows
- Mac
- エミュレータ
- クラウド端末
- スマホ
- Studio
- Python SDK
このページの内容
テンプレートマッチングは、Android ゲーム bot にボタンが画面にあるかどうかを教えます。Tesseract OCR はカウンターが何を示しているかを教えます: エネルギー 8 / 50、00:42 のタイマー、レベルの数字。このガイドでは、Asset Lab で描いた領域から、エネルギーが上限を下回ったら止まるマクロまで、mas.read_text を Python で使います。エミュレータ、クラウドデバイス、スマホで Macro Automation Studio (MAS) のマクロを Python で書くすべての方向けです。
始める前に
- コードベースのプロジェクトが Code Editor で開いていて、デバイスが選ばれていること。はじめに を参照してください。
- アプリかゲームが、今後も変えない解像度で、読みたい文字を表示していること。
- 画像認識ガイド を読んだか、
Regionが何かを知っていること。
Android ゲーム bot での 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結果は 3 つのフィールドを持つ TextRecognitionResult です: text (文字列)、confidence (0.0 から 1.0)、region (見た場所)。画面全体を読むこともできますが、狭い領域の方が速く、はるかに正確なので、最初の一歩は常に領域です。
Asset Lab で OCR 領域を選ぶ
- デバイスをカウンターのある画面にします。
- Code Editor で アセット パネルを開き、Asset Helper を開く をクリックします。Asset Lab がライブ画面で開きます。
- 文字の周りに枠を描きます。少し余白を含めますが、アイコン、枠線、隣の数字は含めません。
- ライブの OCR テストを実行します。文字がきれいに読めるまで枠を調整します。テストはスクリプトと同じエンジンを使います。
- 4 つの座標を
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" は標準の英語セットです。既定から始め、ループが 1 分間に何十回も読むときだけ切り替えてください。
ページセグメンテーションモードを選ぶ
psm は Tesseract にどんな形の文字を期待するかを伝えます。間違ったモードは、空や文字化けした結果の最も多い原因です。
| psm | 期待するもの | 用途 |
|---|---|---|
| 7 | 1 行の文字 (既定) | カウンター、タイマー、1 行のラベル |
| 8 | 1 語 | 単独の数字や短いバッジ |
| 6 | 均一な 1 ブロックの文字 | ダイアログ内の段落 |
| 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 までありますが、この 4 つでほぼすべてのマクロをカバーします。1 行の領域が何も返さないときは、まず 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 の狭い領域は 1 秒よりずっと速く返ります。混み合った画面での全画面 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 の置き換えは、最もよくある 2 つの数字の誤読を直します。数字しか含まない領域にだけ適用してください。
信頼度を使う
confidence は Tesseract が見つけた単語全体で 0.0 から 1.0 です。きれいなカウンターは 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")1 枚のスクリーンショットを再利用する
read_text は渡さない限り、毎回新しいフレームを取得します。ループが複数の領域を同時に読むときは、スクリーンショットを 1 枚撮って各呼び出しに渡します。値は同じ瞬間のものになります。
shot = mas.take_screenshot()
energy = mas.read_text(region=ENERGY, screenshot=shot)
gold = mas.read_text(region=GOLD, screenshot=shot)Python で Android エミュレータの文字を読む: 完全な例
このスクリプトは、エネルギーのカウンターが上限を下回るか、時間の予算を過ぎるまでボタンをタップします。領域、画像 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、1 が l、8 が B と読まれる、またはカンマが消えます。まず、アイコンが数字に触れないよう領域を詰めます。次に BLACK_WHITE を試し、線が途切れるなら代わりに BGR_TO_GRAY を試します。最後にコードで正規化します: 数字だけの領域では O を 0 に、l を 1 に置き換え、カンマを取り除き、読み取りの間で大きく跳ぶ値を捨てます。
OCR が遅い
psm=11 と eng_best での全画面の読み取りが遅いケースです。画面ではなく領域を読み、psm=7 か 8 を使い、1 枚の screenshot を複数の呼び出しに渡してください。きれいな文字では model="eng_fast" が役立ちます。それでも読み取りに数秒かかるなら、領域がおそらく大きすぎます。カウンターに必要な枠は、幅がせいぜい数百ピクセルです。
100%リスクのない自動化ツールは存在しないため、自動化は責任を持って、ご自身の判断で行ってください。
次のステップ
関連ページ
ありがとうございます。誤りがあればDiscordでお知らせください。
質問がありますか? Discordで質問する