Guias
OCR Python com Tesseract para bot de jogo Android
Dê a um bot de jogo Android o OCR do Tesseract com read_text: escolha uma região no Asset Lab, ajuste psm e conversão de cor, e leia contadores e timers.
- Windows
- Mac
- Emulador
- Dispositivo na nuvem
- Celular
- Studio
- SDK Python
Nesta página
- Antes de começar
- Como o OCR Python com Tesseract funciona em um bot de jogo Android
- Escolha uma região de OCR no Asset Lab
- Escolha o modelo
- Escolha um modo de segmentação de página
- Corrija texto claro sobre fundo escuro
- Defina um tempo limite
- Extraia números do texto
- Use a confiança
- Reaproveite uma captura de tela
- Ler texto em um emulador Android com Python: um exemplo completo
- Solução de problemas
- O OCR retorna uma string vazia
- Dígitos lidos errado
- OCR lento
O template matching diz a um bot de jogo Android se um botão está na tela. O OCR do Tesseract, chamado do Python, diz o que um contador mostra: energia 8 de 50, um timer em 00:42, um número de nível. Este guia leva mas.read_text de uma região desenhada no Asset Lab até uma macro que para quando a energia cai abaixo de um limite. Ele é para quem escreve macros do Macro Automation Studio (MAS) em Python em um emulador, em um dispositivo na nuvem ou em um celular.
Antes de começar
- Um projeto Baseado em código está aberto no Code Editor e um dispositivo está selecionado. Veja Primeiros passos.
- O app ou jogo mostra o texto que você quer ler, na resolução que você vai manter.
- Você leu o guia de reconhecimento de imagem ou sabe o que é uma
Region.
Como o OCR Python com Tesseract funciona em um bot de jogo Android
read_text envia uma captura de tela, ou a parte dela dentro de uma região, ao Tesseract OCR dentro do app. Ele retorna o que o motor leu.
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,
) -> TextRecognitionResultO resultado é um TextRecognitionResult com três campos: text (a string), confidence (0.0 a 1.0) e region (onde ele olhou). Ler a tela inteira funciona, mas uma região justa é mais rápida e muito mais precisa, então o primeiro passo é sempre a região.
Escolha uma região de OCR no Asset Lab
- Leve o dispositivo até a tela com o contador.
- No Code Editor, abra o painel Assets e clique em Abrir o Asset Helper. O Asset Lab abre com a tela ao vivo.
- Desenhe uma caixa em volta do texto. Inclua uma pequena margem, mas nenhum ícone, borda ou número vizinho.
- Rode o teste de OCR ao vivo. Ajuste a caixa até o texto voltar limpo; o teste usa o mesmo motor que o seu script.
- Copie as quatro coordenadas para uma
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)Imprima com repr enquanto ajusta: ele mostra espaços e quebras de linha perdidos que o print esconde. As regiões são coordenadas em pixels na resolução da captura, então mantenha todo dispositivo nessa resolução. Veja Asset Lab.
Escolha o modelo
model seleciona os dados do Tesseract. "eng_best" é o padrão e o mais preciso; "eng_fast" troca precisão por velocidade em texto limpo; "eng" é o conjunto padrão de inglês. Comece pelo padrão e só troque quando um loop ler dezenas de vezes por minuto.
Escolha um modo de segmentação de página
psm diz ao Tesseract que forma de texto esperar. O modo errado é a causa mais comum de resultados vazios ou embaralhados.
| psm | Espera | Use para |
|---|---|---|
| 7 | Uma única linha de texto (padrão) | Contadores, timers, rótulos de uma linha |
| 8 | Uma única palavra | Um número sozinho ou um selo curto |
| 6 | Um bloco uniforme de texto | Um parágrafo em um diálogo |
| 11 | Texto esparso em qualquer lugar, sem ordem | Uma tela inteira, uma lista de resultados |
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)Os valores vão de 0 a 13, mas esses quatro cobrem quase toda macro. Quando uma região de uma linha não retorna nada, tente 8 primeiro, depois 6.
Corrija texto claro sobre fundo escuro
O Tesseract espera texto escuro sobre fundo claro. Os contadores de jogos costumam ser o oposto, dígitos brancos sobre uma barra escura, muitas vezes com um contorno colorido. color_conversion pré-processa o recorte antes do OCR.
from mas import ColorConversion
energy = mas.read_text(
region=ENERGY,
psm=7,
color_conversion=ColorConversion.BLACK_WHITE,
)ColorConversion.NONE(padrão) envia os pixels como estão.ColorConversion.BLACK_WHITEconverte para escala de cinza e aplica um limiar automático, dando preto e branco puros. É a melhor primeira tentativa para texto de alto contraste sobre fundos ruidosos ou coloridos.ColorConversion.BGR_TO_GRAYouRGB_TO_GRAYdá escala de cinza simples, o que ajuda quando o limiar deBLACK_WHITEcome traços finos.
Teste cada opção no Asset Lab na tela real. Não existe um membro GRAYSCALE; use um dos nomes acima.
Defina um tempo limite
timeout_ms tem 30000 como padrão. Uma região justa com psm=7 retorna bem abaixo de um segundo; uma leitura de tela inteira com psm=11 em uma tela cheia demora mais. Reduza o tempo limite em um loop que precisa continuar responsivo, e envolva a chamada para que uma leitura lenta não encerre a execução.
try:
result = mas.read_text(region=ENERGY, timeout_ms=5000)
except mas.RPCError as e:
mas.log(f"OCR failed: {e}", level="warning")
result = NoneExtraia números do texto
result.text é uma string, às vezes com espaços, vírgulas, uma barra ou uma letra perdida. Interprete-a com uma expressão regular e trate “nenhum número” como um resultado real.
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") dá 1250; current_and_max("8/50") dá (8, 50). As trocas de O e l corrigem as duas leituras erradas de dígito mais comuns; aplique-as só a regiões que contêm apenas dígitos.
Use a confiança
confidence vai de 0.0 a 1.0 sobre as palavras que o Tesseract encontrou. Um contador limpo lê a 0.9 ou mais. Quando ela cair, leia de novo antes de agir sobre o valor, e registre os dois para ver o padrão depois.
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")Reaproveite uma captura de tela
Todo read_text captura um quadro novo, a menos que você passe um. Quando um loop lê várias regiões de uma vez, tire uma captura e passe-a a cada chamada; os valores então pertencem ao mesmo instante.
shot = mas.take_screenshot()
energy = mas.read_text(region=ENERGY, screenshot=shot)
gold = mas.read_text(region=GOLD, screenshot=shot)Ler texto em um emulador Android com Python: um exemplo completo
O script toca em um botão até o contador de energia cair abaixo de um limite ou o limite de tempo passar. Troque a região, o ID da imagem e o limite pelos seus.
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()Ler antes de cada toque mantém a macro honesta: ela nunca gasta energia que não consegue ver. O contador unreadable transforma uma região quebrada em uma execução com falha, que um webhook em macro.failed pode informar. Veja Loops e agendamento. Se preferir descrever a tarefa, o MAS Agent mede a região e escreve esse código para você.
Solução de problemas
O OCR retorna uma string vazia
A região não pega o texto, o modo está errado, ou o texto é claro sobre escuro. Confira a região no Asset Lab, troque psm para 8 para um único número ou 6 para um bloco, e adicione color_conversion=ColorConversion.BLACK_WHITE. Texto muito pequeno também é lido como nada. Se os dígitos têm só alguns pixels de altura, aumente a resolução do emulador nas configurações de tela e capture todas as regiões de novo.
Dígitos lidos errado
Zero lido como a letra O, um como l, oito como B, ou uma vírgula que some. Primeiro aperte a região para nenhum ícone tocar nos dígitos. Depois tente BLACK_WHITE e, se os traços quebrarem, BGR_TO_GRAY em vez disso. Por fim, normalize no código: troque O por 0 e l por 1 em regiões só de dígitos, remova as vírgulas e rejeite valores que saltam demais entre leituras.
OCR lento
Leituras de tela inteira com psm=11 e eng_best são o caso lento. Leia uma região, não a tela; use psm=7 ou 8; e passe uma única screenshot a várias chamadas. model="eng_fast" ajuda em texto limpo. Se uma leitura ainda leva segundos, a região provavelmente é grande; um contador precisa de uma caixa de no máximo algumas centenas de pixels de largura.
Nenhuma ferramenta de automação é 100% livre de riscos, por isso automatize com responsabilidade e a seu próprio critério.
Próximos passos
Páginas relacionadas
Obrigado. Se algo estiver errado, conte para a gente no Discord.
Dúvidas? Pergunte no Discord