Guías
OCR Tesseract en Python para un bot de juego Android
OCR Tesseract en Python para tu bot de juego Android con read_text en MAS: elige una región en Asset Lab, ajusta psm y el color, y lee contadores.
- Windows
- Mac
- Emulador
- Dispositivo en la nube
- Teléfono
- Studio
- SDK de Python
En esta página
- Antes de empezar
- Cómo funciona el OCR Tesseract en Python dentro de un bot de juego
- Elegir una región OCR en Asset Lab
- Elegir el modelo
- Elegir un modo de segmentación de página
- Arreglar texto claro sobre fondo oscuro
- Fijar un tiempo límite
- Extraer números del texto
- Usar la confianza
- Reutilizar una captura
- Leer texto en un emulador Android con Python: ejemplo completo
- Solución de problemas
- El OCR devuelve una cadena vacía
- Dígitos mal leídos
- OCR lento
La coincidencia de plantillas le dice a un bot de juego Android si un botón está en pantalla. El OCR Tesseract en Python le dice qué marca un contador: energía 8 de 50, un temporizador en 00:42, un número de nivel. Esta guía lleva mas.read_text desde una región dibujada en Asset Lab hasta una macro que se detiene cuando la energía baja de un límite. Está pensada para quien escribe macros de Macro Automation Studio (MAS) en Python en un emulador, un dispositivo en la nube o un móvil.
Antes de empezar
- Un proyecto basado en código está abierto en el Code Editor y hay un dispositivo seleccionado. Consulta Primeros pasos.
- La app o el juego muestra el texto que quieres leer, a la resolución que vas a mantener.
- Has leído la guía de reconocimiento de imagen o sabes qué es una
Region.
Cómo funciona el OCR Tesseract en Python dentro de un bot de juego
read_text envía una captura, o la parte de ella dentro de una región, al Tesseract OCR que va dentro de la app. Devuelve lo que leyó el motor.
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,
) -> TextRecognitionResultEl resultado es un TextRecognitionResult con tres campos: text (la cadena), confidence (de 0.0 a 1.0) y region (dónde miró). Leer toda la pantalla funciona, pero una región ajustada es más rápida y mucho más precisa, así que el primer paso es siempre la región.
Elegir una región OCR en Asset Lab
- Lleva el dispositivo a la pantalla con el contador.
- En el Code Editor, abre el panel Recursos y haz clic en Abrir Asset Helper. Asset Lab se abre con la pantalla en directo.
- Dibuja un recuadro alrededor del texto. Incluye un poco de margen, pero ningún icono, borde ni número vecino.
- Ejecuta la prueba de OCR en directo. Ajusta el recuadro hasta que el texto salga limpio; la prueba usa el mismo motor que tu script.
- Copia las cuatro coordenadas a una
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)Imprime con repr mientras ajustas: muestra los espacios y saltos de línea sueltos que print esconde. Las regiones son coordenadas en píxeles a la resolución de captura, así que mantén todos los dispositivos en esa resolución. Consulta Asset Lab.
Elegir el modelo
model selecciona los datos de Tesseract. "eng_best" es el predeterminado y el más preciso; "eng_fast" cambia precisión por velocidad en texto limpio; "eng" es el conjunto estándar en inglés. Empieza con el predeterminado y cambia solo cuando un bucle lee decenas de veces por minuto.
Elegir un modo de segmentación de página
psm le dice a Tesseract qué forma de texto esperar. El modo equivocado es la causa más común de resultados vacíos o ilegibles.
| psm | Espera | Úsalo para |
|---|---|---|
| 7 | Una sola línea de texto (predeterminado) | Contadores, temporizadores, etiquetas de una línea |
| 8 | Una sola palabra | Un número suelto o una insignia corta |
| 6 | Un bloque uniforme de texto | Un párrafo en un diálogo |
| 11 | Texto disperso en cualquier sitio, sin orden | Una pantalla entera, una 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)Los valores van de 0 a 13, pero estos cuatro cubren casi todas las macros. Cuando una región de una sola línea no devuelve nada, prueba primero 8 y luego 6.
Arreglar texto claro sobre fondo oscuro
Tesseract espera texto oscuro sobre fondo claro. Los contadores de los juegos suelen ser lo contrario, dígitos blancos sobre una barra oscura, muchas veces con un contorno de color. color_conversion preprocesa el recorte antes del OCR.
from mas import ColorConversion
energy = mas.read_text(
region=ENERGY,
psm=7,
color_conversion=ColorConversion.BLACK_WHITE,
)ColorConversion.NONE(predeterminado) envía los píxeles tal cual.ColorConversion.BLACK_WHITEconvierte a escala de grises y aplica un umbral automático, dando blanco y negro puros. Es la mejor primera opción para texto de alto contraste sobre fondos con ruido o de color.ColorConversion.BGR_TO_GRAYoRGB_TO_GRAYdan escala de grises simple, que ayuda cuando el umbral deBLACK_WHITEse come los trazos finos.
Prueba cada opción en Asset Lab sobre la pantalla real. No existe un miembro GRAYSCALE; usa uno de los nombres de arriba.
Fijar un tiempo límite
timeout_ms es 30000 por defecto. Una región ajustada con psm=7 responde en mucho menos de un segundo; una lectura de pantalla completa con psm=11 sobre una pantalla cargada tarda más. Baja el tiempo límite en un bucle que deba seguir respondiendo y envuelve la llamada para que una lectura lenta no termine la ejecución.
try:
result = mas.read_text(region=ENERGY, timeout_ms=5000)
except mas.RPCError as e:
mas.log(f"OCR failed: {e}", level="warning")
result = NoneExtraer números del texto
result.text es una cadena, a veces con espacios, comas, una barra o una letra suelta. Analízala con una expresión regular y trata “sin número” como un 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") da 1250; current_and_max("8/50") da (8, 50). Los cambios de O y l arreglan las dos confusiones de dígitos más comunes; aplícalos solo a regiones que no contengan más que dígitos.
Usar la confianza
confidence va de 0.0 a 1.0 sobre las palabras que Tesseract encontró. Un contador limpio se lee a 0.9 o más. Cuando baja, vuelve a leer antes de actuar sobre el valor, y registra ambos para ver el patrón más tarde.
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")Reutilizar una captura
Cada read_text captura un fotograma nuevo salvo que le pases uno. Cuando un bucle lee varias regiones a la vez, haz una captura y pásala a cada llamada; los valores pertenecen entonces al mismo instante.
shot = mas.take_screenshot()
energy = mas.read_text(region=ENERGY, screenshot=shot)
gold = mas.read_text(region=GOLD, screenshot=shot)Leer texto en un emulador Android con Python: ejemplo completo
El script toca un botón hasta que el contador de energía baja de un límite o se agota un presupuesto de tiempo. Sustituye la región, el ID de imagen y el límite por los tuyos.
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()Leer antes de cada toque mantiene la macro honesta: nunca gasta energía que no puede ver. El contador unreadable convierte una región rota en una ejecución fallida, que un webhook en macro.failed puede notificar. Consulta Bucles y programación. Si prefieres describir la tarea, MAS Agent mide la región y escribe este código por ti.
Solución de problemas
El OCR devuelve una cadena vacía
La región no abarca el texto, el modo es incorrecto o el texto es claro sobre oscuro. Revisa la región en Asset Lab, cambia psm a 8 para un solo número o a 6 para un bloque, y añade color_conversion=ColorConversion.BLACK_WHITE. El texto muy pequeño también se lee como nada. Si los dígitos miden solo unos píxeles de alto, sube la resolución del emulador en sus ajustes de pantalla y vuelve a capturar todas las regiones.
Dígitos mal leídos
El cero se lee como la letra O, el uno como l, el ocho como B, o desaparece una coma. Primero ajusta la región para que ningún icono toque los dígitos. Luego prueba BLACK_WHITE y, si los trazos se rompen, BGR_TO_GRAY en su lugar. Por último, normaliza en el código: sustituye O por 0 y l por 1 en regiones de solo dígitos, quita las comas y rechaza valores que salten de forma disparatada entre lecturas.
OCR lento
Las lecturas de pantalla completa con psm=11 y eng_best son el caso lento. Lee una región, no la pantalla; usa psm=7 u 8; y pasa una sola screenshot a varias llamadas. model="eng_fast" ayuda con texto limpio. Si una lectura sigue tardando segundos, la región probablemente es grande; un contador necesita un recuadro de como mucho unos cientos de píxeles de ancho.
Ninguna herramienta de automatización está libre de riesgos al 100 %, así que automatiza con responsabilidad y bajo tu propio criterio.
Siguientes pasos
Páginas relacionadas
Gracias. Si algo está mal, cuéntanoslo en Discord.
¿Dudas? Pregunta en Discord