屏幕上的图片和文字

在没有元素的游戏和自绘界面上,从截图中找到图片并点击,或者用 OCR 读取文字。两者都是可选功能,在电脑上运行。

本页为译文。如与英文版不一致,以英文版为准。 English

游戏、地图和一些自行绘制界面的应用不提供元素,dump 中只有一个大方框。坐标在这里能用,但布局一变就会失效。下面两组可选命令改为查看截图:

  • find_image 和 tap_image 查找你从之前的截图中裁剪下来的小图片。
  • ocr、ocr_find 和 ocr_tap 用 Tesseract 读取屏幕上的文字。

两者都在运行 droidline serve 的电脑上执行:服务器从手机获取截图并在本地处理,手机上不需要任何新东西。只要 dump 中有元素,就使用元素;它们更快,也更准确。

找到图片并点击

  1. 截一张原始尺寸的图:droidline screenshot screen.png。
  2. 用任意图片编辑器打开,把想要的按钮或图标裁剪下来,比它的边缘稍微往里一点。保存为 PNG。
  3. 查找它:
spot = d.find_image("play-button.png")
print(spot["x"], spot["y"], spot["score"])     # 中心坐标,以及匹配有多接近

d.tap_image("play-button.png")                  # 找到后点击它的中心
d.tap_image("next.png", threshold=0.8, timeout=20)
const spot = await d.findImage("play-button.png");
console.log(spot.x, spot.y, spot.score);

await d.tapImage("play-button.png");
await d.tapImage("next.png", { threshold: 0.8, timeout: 20 });
var spot = await d.FindImageAsync("play-button.png");
Console.WriteLine($"{spot.X} {spot.Y} {spot.Score}");

await d.TapImageAsync("play-button.png");
await d.TapImageAsync("next.png", threshold: 0.8, timeout: 20);
droidline find_image play-button.png
droidline tap_image play-button.png
droidline tap_image next.png --threshold 0.8 --timeout 20

SDK 也可以传入图片的字节,而不是路径。

两个命令都会不断重试,直到图片出现或 timeout(默认 10 秒)用完,然后以 NOT_FOUND 失败。错误信息会给出它见到的最高分,让你知道差了多少。

怎样才能匹配上:

  • 从同一部手机上裁剪。 图片按相同尺寸逐像素比较,所以来自其他屏幕尺寸或密度的图片匹配不上。每种手机型号各保留一套图片。
  • 裁剪有辨识度的部分。 纯色方块会在很多地方匹配上,而上面的文字或图标只会匹配一处。
  • 谨慎调整 threshold。 它的范围是 0 到 1,默认 0.9。按钮会有细微变化时(例如发光效果或数字),可以稍微调低。调得太低会点到别的东西。

用 OCR 读取文字

OCR 需要在运行服务器的电脑上安装 Tesseract,以及要读取的语言数据:英语是 eng,韩语是 kor,简体中文是 chi_sim。Droidline 不会替你安装。如果 tesseract 不在 PATH 中,在 config.toml 中写明它的位置:

[ocr]
tesseract = "C:/Program Files/Tesseract-OCR/tesseract.exe"

然后:

page = d.ocr("chi_sim+eng")
print(page["text"])                       # 所有行,每行一条
for line in page["lines"]:
    print(line["text"], line["bounds"])

d.ocr_find("第 12 关", "chi_sim")         # 等它出现,返回位置
d.ocr_tap("开始", "chi_sim", timeout=30)  # 等它出现,然后点击
const page = await d.ocr("chi_sim+eng");
console.log(page.text);
for (const line of page.lines) console.log(line.text, line.bounds);

await d.ocrFind("第 12 关", "chi_sim");
await d.ocrTap("开始", "chi_sim", { timeout: 30 });
var page = await d.OcrAsync("chi_sim+eng");
Console.WriteLine(page.Text);
foreach (var line in page.Lines)
    Console.WriteLine($"{line.Get<string>("text")} [{string.Join(", ", line.Get<int[]>("bounds")!)}]");

await d.OcrFindAsync("第 12 关", "chi_sim");
await d.OcrTapAsync("开始", "chi_sim", timeout: 30);
droidline ocr chi_sim+eng
droidline ocr_find "第 12 关" chi_sim
droidline ocr_tap 开始 chi_sim --timeout 30

ocr_find 和 ocr_tap 先查找与你的文字完全相同的单词,再查找包含它的行。没有 Tesseract 时,它们以 OCR_UNAVAILABLE 失败,并说明缺少什么。

OCR 读取的是图片上显示的内容,所以比元素慢,遇到很小、有装饰或对比度低的文字时也会出错。每次尝试都要截图并运行一次 Tesseract,比查找元素慢得多。