화면의 그림과 글자
요소가 없는 게임과 직접 그린 화면에서, 스크린샷 속 그림을 찾아 누르거나 OCR로 글자를 읽습니다. 둘 다 선택 기능이며 PC에서 실행됩니다.
번역된 페이지입니다. 영어 문서와 내용이 다르면 영어 문서가 기준입니다. English
게임, 지도, 화면을 직접 그리는 일부 앱은 요소를 드러내지 않아서 dump에 큰 상자 하나만 나옵니다. 좌표로도 다룰 수 있지만 레이아웃이 움직이면 깨집니다. 다음 두 가지 선택 기능은 대신 스크린샷을 봅니다.
find_image와tap_image는 미리 찍은 스크린샷에서 잘라 낸 작은 그림을 찾습니다.ocr,ocr_find,ocr_tap은 Tesseract로 화면의 글자를 읽습니다.
둘 다 droidline serve를 실행하는 PC에서 동작합니다. 서버가 폰에서 스크린샷을 받아 그 자리에서 처리하므로 폰에는 새로 필요한 것이 없습니다. dump에 요소가 있다면 요소를 쓰세요. 더 빠르고 정확합니다.
그림을 찾아 누르기
- 원래 크기로 스크린샷을 찍습니다.
droidline screenshot screen.png - 아무 이미지 편집기로 열어 원하는 버튼이나 아이콘을 테두리보다 조금 안쪽으로 잘라 냅니다. PNG로 저장하세요.
- 찾습니다.
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 20SDK에는 경로 대신 그림의 바이트를 넘겨도 됩니다.
두 명령 모두 그림이 나타나거나 timeout(기본 10초)이 지날 때까지 다시 시도하고, 끝내 못 찾으면 NOT_FOUND로 실패합니다. 메시지에 가장 높았던 점수가 나오므로 얼마나 빗나갔는지 알 수 있습니다.
잘 찾히게 하려면 다음을 지키세요.
- 같은 폰에서 잘라 내세요. 같은 크기에서 픽셀 단위로 비교하므로, 화면 크기나 밀도가 다른 폰의 그림은 맞지 않습니다. 폰 모델마다 그림을 따로 두세요.
- 눈에 띄는 부분을 자르세요. 단색 사각형은 여러 곳에서 맞고, 그 위의 글자나 아이콘은 한 곳에서만 맞습니다.
threshold는 조심해서 바꾸세요. 0에서 1 사이이고 기본값은 0.9입니다. 빛나는 효과나 숫자처럼 버튼이 조금씩 바뀌면 조금 낮추세요. 너무 낮추면 엉뚱한 곳을 누릅니다.
OCR로 글자 읽기
OCR에는 서버를 실행하는 PC에 Tesseract와 읽을 언어의 데이터가 필요합니다. 영어는 eng, 한국어는 kor, 중국어 간체는 chi_sim입니다. Droidline이 설치해 주지 않습니다. tesseract가 PATH에 없으면 config.toml에 위치를 적으세요.
[ocr]
tesseract = "C:/Program Files/Tesseract-OCR/tesseract.exe"
그다음:
page = d.ocr("kor+eng")
print(page["text"]) # 모든 줄, 한 줄에 하나씩
for line in page["lines"]:
print(line["text"], line["bounds"])
d.ocr_find("레벨 12", "kor") # 보일 때까지 기다렸다가 위치를 반환
d.ocr_tap("시작", "kor", timeout=30) # 기다렸다가 누르기const page = await d.ocr("kor+eng");
console.log(page.text);
for (const line of page.lines) console.log(line.text, line.bounds);
await d.ocrFind("레벨 12", "kor");
await d.ocrTap("시작", "kor", { timeout: 30 });var page = await d.OcrAsync("kor+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", "kor");
await d.OcrTapAsync("시작", "kor", timeout: 30);droidline ocr kor+eng
droidline ocr_find "레벨 12" kor
droidline ocr_tap 시작 kor --timeout 30ocr_find와 ocr_tap은 먼저 넘긴 글자와 똑같은 단어를 찾고, 없으면 그 글자가 들어간 줄을 찾습니다. Tesseract가 없으면 무엇이 없는지 알려 주며 OCR_UNAVAILABLE로 실패합니다.
OCR은 그림에 보이는 대로 읽기 때문에 요소보다 느리고, 작거나 꾸민 글자, 배경과 대비가 약한 글자에서 틀리기도 합니다. 시도할 때마다 스크린샷을 찍고 Tesseract를 한 번 실행하므로, 요소를 찾을 때보다 훨씬 오래 걸립니다.