検索

ガイド

Tesseract OCR をゲーム bot で使う: 数値の読み取り

MAS の read_text で Android ゲーム bot に Tesseract OCR を組み込む: Asset Lab で領域を選び、psm と色変換を調整し、カウンターやタイマーの数値を取り出します。

  • Windows
  • Mac
  • エミュレータ
  • クラウド端末
  • スマホ
  • Studio
  • Python SDK
中級 更新日 約8分で読めます
このページの内容
  1. 始める前に
  2. Android ゲーム bot での Tesseract OCR の使い方
  3. Asset Lab で OCR 領域を選ぶ
  4. モデルを選ぶ
  5. ページセグメンテーションモードを選ぶ
  6. 暗い背景の明るい文字を直す
  7. タイムアウトを設定する
  8. 文字から数値を取り出す
  9. 信頼度を使う
  10. 1 枚のスクリーンショットを再利用する
  11. Python で Android エミュレータの文字を読む: 完全な例
  12. トラブルシューティング
  13. OCR が空の文字列を返す
  14. 数字を誤読する
  15. OCR が遅い

テンプレートマッチングは、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 に送ります。エンジンが読んだものを返します。

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

結果は 3 つのフィールドを持つ TextRecognitionResult です: text (文字列)、confidence (0.0 から 1.0)、region (見た場所)。画面全体を読むこともできますが、狭い領域の方が速く、はるかに正確なので、最初の一歩は常に領域です。

Asset Lab で OCR 領域を選ぶ

  1. デバイスをカウンターのある画面にします。
  2. Code Editor で アセット パネルを開き、Asset Helper を開く をクリックします。Asset Lab がライブ画面で開きます。
  3. 文字の周りに枠を描きます。少し余白を含めますが、アイコン、枠線、隣の数字は含めません。
  4. ライブの OCR テストを実行します。文字がきれいに読めるまで枠を調整します。テストはスクリプトと同じエンジンを使います。
  5. 4 つの座標を 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" は標準の英語セットです。既定から始め、ループが 1 分間に何十回も読むときだけ切り替えてください。

ページセグメンテーションモードを選ぶ

psm は Tesseract にどんな形の文字を期待するかを伝えます。間違ったモードは、空や文字化けした結果の最も多い原因です。

psm期待するもの用途
71 行の文字 (既定)カウンター、タイマー、1 行のラベル
81 語単独の数字や短いバッジ
6均一な 1 ブロックの文字ダイアログ内の段落
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 までありますが、この 4 つでほぼすべてのマクロをカバーします。1 行の領域が何も返さないときは、まず 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 の狭い領域は 1 秒よりずっと速く返ります。混み合った画面での全画面 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")1250 を、current_and_max("8/50")(8, 50) を返します。Ol の置き換えは、最もよくある 2 つの数字の誤読を直します。数字しか含まない領域にだけ適用してください。

信頼度を使う

confidence は Tesseract が見つけた単語全体で 0.0 から 1.0 です。きれいなカウンターは 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")

1 枚のスクリーンショットを再利用する

read_text は渡さない限り、毎回新しいフレームを取得します。ループが複数の領域を同時に読むときは、スクリーンショットを 1 枚撮って各呼び出しに渡します。値は同じ瞬間のものになります。

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

Python で Android エミュレータの文字を読む: 完全な例

このスクリプトは、エネルギーのカウンターが上限を下回るか、時間の予算を過ぎるまでボタンをタップします。領域、画像 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、1 が l、8 が B と読まれる、またはカンマが消えます。まず、アイコンが数字に触れないよう領域を詰めます。次に BLACK_WHITE を試し、線が途切れるなら代わりに BGR_TO_GRAY を試します。最後にコードで正規化します: 数字だけの領域では O0 に、l1 に置き換え、カンマを取り除き、読み取りの間で大きく跳ぶ値を捨てます。

OCR が遅い

psm=11eng_best での全画面の読み取りが遅いケースです。画面ではなく領域を読み、psm=78 を使い、1 枚の screenshot を複数の呼び出しに渡してください。きれいな文字では model="eng_fast" が役立ちます。それでも読み取りに数秒かかるなら、領域がおそらく大きすぎます。カウンターに必要な枠は、幅がせいぜい数百ピクセルです。

100%リスクのない自動化ツールは存在しないため、自動化は責任を持って、ご自身の判断で行ってください。

次のステップ

関連ページ

このページは役に立ちましたか?

質問がありますか? Discordで質問する