Python이 Brain Wars를 플레이 해 보았습니다 1
개요
이미지 처리 연습이 끝나면 Python이 Brain Wars를 플레이하게했습니다.
Brain Wars란 무엇입니까?
심플한 내용의 미니게임을 통해 전세계 유저와 실시간으로 대전하고 스코어를 겨루는 '실시간 대전형 뇌 트레이닝'. 실제로 플레이한 적이 있는 분도 많지 않을까?
이번에 플레이하는 게임
앱 내에는 21 종류의 게임이 준비되어 있지만, 이번에는 그 중에서 Matching
를 선택했다. 표시된 카드 중에서 일치하는 쌍을 찾아 탭하는 간단한 게임
프로그램 동작
이런 식으로 작동합니다. 그건 그렇고, 내 최고의 점수는 23이므로 적어도 나보다 훨씬 강합니다.
흐름은 자연스럽게 이런 느낌 ↓
1. 카드가 표시된 영역을 캡처
2. 캡처한 이미지에서 각 카드의 이미지와 좌표를 가져옵니다.
3. 이미지 유사도 (SSIM)를 계산하여 일치 쌍을 식별합니다.
4. 일치 쌍을 클릭
5. 1~4를 게임이 끝날 때까지 반복한다
해설
어떻게 프로그램을 구현했는지 순서대로 해설해 나간다
환경
심플한 내용의 미니게임을 통해 전세계 유저와 실시간으로 대전하고 스코어를 겨루는 '실시간 대전형 뇌 트레이닝'. 실제로 플레이한 적이 있는 분도 많지 않을까?
이번에 플레이하는 게임
앱 내에는 21 종류의 게임이 준비되어 있지만, 이번에는 그 중에서 Matching
를 선택했다. 표시된 카드 중에서 일치하는 쌍을 찾아 탭하는 간단한 게임
프로그램 동작
이런 식으로 작동합니다. 그건 그렇고, 내 최고의 점수는 23이므로 적어도 나보다 훨씬 강합니다.
흐름은 자연스럽게 이런 느낌 ↓
1. 카드가 표시된 영역을 캡처
2. 캡처한 이미지에서 각 카드의 이미지와 좌표를 가져옵니다.
3. 이미지 유사도 (SSIM)를 계산하여 일치 쌍을 식별합니다.
4. 일치 쌍을 클릭
5. 1~4를 게임이 끝날 때까지 반복한다
해설
어떻게 프로그램을 구현했는지 순서대로 해설해 나간다
환경
이런 식으로 작동합니다. 그건 그렇고, 내 최고의 점수는 23이므로 적어도 나보다 훨씬 강합니다.
흐름은 자연스럽게 이런 느낌 ↓
1. 카드가 표시된 영역을 캡처
2. 캡처한 이미지에서 각 카드의 이미지와 좌표를 가져옵니다.
3. 이미지 유사도 (SSIM)를 계산하여 일치 쌍을 식별합니다.
4. 일치 쌍을 클릭
5. 1~4를 게임이 끝날 때까지 반복한다
해설
어떻게 프로그램을 구현했는지 순서대로 해설해 나간다
환경
Brain Wars는 스마트폰에서만 플레이할 수 있다. 그래서 Vysor이라는 Chrome 확장 플러그인을 사용하여 Ubuntu에서 스마트 폰을 조작하여 플레이했습니다.
사용한 주요 라이브러리 및 역할
mss
: 스크린 캡처 opencv
: 카드 윤곽 추출 및 좌표 계산 scikit-image
: 이미지 유사도 (SSIM) 계산 pyautogui
: 클릭 자동화 1. 카드 표시 영역 캡처
처음에는
PIL
의 ImageGrab
를 사용하려고 생각했지만, 아무래도 Mac과 Windows만 지원합니다. 라는 것이므로, mss 라고 하는 라이브러리를 사용했다. 게임 레벨이 올라가면 카드의 행 수가 3열로 늘어나므로 캡처 영역이 약간 넓게 설정되어 있습니다.2. 각 카드의 이미지와 좌표 취득
3. 매치 페어 식별
이미지 유사도 (SSIM)를 계산하려면
scikit-image
의 compare_ssim을 사용했습니다. 각 카드의 조합(카드 매수가 6장의 경우라면, 15패턴)마다 SSIM을 산출하고, 스코어가 최대가 되는 것을 매치 페어로 했다4. 일치 쌍 클릭
2
에서 구한 각 카드의 중심 좌표와 3
에서 구한 매치 페어의 Index로부터 클릭 좌표를 결정했다. 클릭 자동화에는 pyautogui
를 사용했습니다. 매우 사용하기 쉬운 라이브러리로 마음에 드는코드
import mss
import numpy as np
import time
import cv2
import pyautogui as pag
from skimage.measure import compare_ssim as ssim
def contour_center(contour):
"""Compute the center coordinates of a contour"""
M = cv2.moments(contour)
cx = int(M['m10'] / (M['m00'] + 1))
cy = int(M['m01'] / (M['m00'] + 1))
return cx, cy
def process_img(img):
"""Extract card images and compute their locations"""
cards = []
locs = []
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
_, thresh = cv2.threshold(img_gray, 245, 255, cv2.THRESH_BINARY)
_, cnts, _ = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# filter contours by area
area_thresh = 6000
cnts = list(filter(lambda x: cv2.contourArea(x) > area_thresh, cnts))
for i, cnt in enumerate(cnts):
x, y, w, h = cv2.boundingRect(cnt)
if i == 0: resize_h, resize_w = h, w
card = thresh[y:y + h, x:x + w]
card = cv2.resize(card, (resize_w, resize_h))
cards.append(card)
cx, cy = contour_center(cnt)
locs.append((cx, cy))
# sort cards and locs from top left to bottom right
cards = [card for _, card in sorted(zip(locs, cards), key=lambda x: [x[0][1], x[0][0]])]
locs = sorted(locs, key=lambda x: [x[1], x[0]])
return cards, locs
def find_match(cards):
"""Find a matching pair"""
num_card = len(cards)
max_score = 0
for i in range(num_card - 1):
for j in range(i + 1, num_card):
score = ssim(cards[i], cards[j])
if score > max_score:
match_pair = (i, j)
max_score = score
return match_pair
def grab_screen(bbox):
"""Capture the specified area on the screen"""
with mss.mss() as sct:
left, top, width, height = bbox
grab_area = {'left': left, 'top': top, 'width': width, 'height': height}
img = sct.grab(grab_area)
return np.array(img)[:, :, :3]
def main():
bbox = (785, 300, 1215 - 785, 740 - 300)
while True:
img = grab_screen(bbox)
cards, locs = process_img(img)
if len(locs) < 6:
print('Done')
exit()
match_pair = find_match(cards)
print('Matching pair:', match_pair)
for idx in match_pair:
x, y = locs[idx]
pag.click(bbox[0] + x, bbox[1] + y)
time.sleep(0.25)
if __name__ == '__main__':
main()
향후 전망
Matching
이외의 게임도 자동화 해 볼 예정
Reference
이 문제에 관하여(Python이 Brain Wars를 플레이 해 보았습니다 1), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://qiita.com/harupy/items/72990f9ddd17428f2a65
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
import mss
import numpy as np
import time
import cv2
import pyautogui as pag
from skimage.measure import compare_ssim as ssim
def contour_center(contour):
"""Compute the center coordinates of a contour"""
M = cv2.moments(contour)
cx = int(M['m10'] / (M['m00'] + 1))
cy = int(M['m01'] / (M['m00'] + 1))
return cx, cy
def process_img(img):
"""Extract card images and compute their locations"""
cards = []
locs = []
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
_, thresh = cv2.threshold(img_gray, 245, 255, cv2.THRESH_BINARY)
_, cnts, _ = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# filter contours by area
area_thresh = 6000
cnts = list(filter(lambda x: cv2.contourArea(x) > area_thresh, cnts))
for i, cnt in enumerate(cnts):
x, y, w, h = cv2.boundingRect(cnt)
if i == 0: resize_h, resize_w = h, w
card = thresh[y:y + h, x:x + w]
card = cv2.resize(card, (resize_w, resize_h))
cards.append(card)
cx, cy = contour_center(cnt)
locs.append((cx, cy))
# sort cards and locs from top left to bottom right
cards = [card for _, card in sorted(zip(locs, cards), key=lambda x: [x[0][1], x[0][0]])]
locs = sorted(locs, key=lambda x: [x[1], x[0]])
return cards, locs
def find_match(cards):
"""Find a matching pair"""
num_card = len(cards)
max_score = 0
for i in range(num_card - 1):
for j in range(i + 1, num_card):
score = ssim(cards[i], cards[j])
if score > max_score:
match_pair = (i, j)
max_score = score
return match_pair
def grab_screen(bbox):
"""Capture the specified area on the screen"""
with mss.mss() as sct:
left, top, width, height = bbox
grab_area = {'left': left, 'top': top, 'width': width, 'height': height}
img = sct.grab(grab_area)
return np.array(img)[:, :, :3]
def main():
bbox = (785, 300, 1215 - 785, 740 - 300)
while True:
img = grab_screen(bbox)
cards, locs = process_img(img)
if len(locs) < 6:
print('Done')
exit()
match_pair = find_match(cards)
print('Matching pair:', match_pair)
for idx in match_pair:
x, y = locs[idx]
pag.click(bbox[0] + x, bbox[1] + y)
time.sleep(0.25)
if __name__ == '__main__':
main()
Matching
이외의 게임도 자동화 해 볼 예정
Reference
이 문제에 관하여(Python이 Brain Wars를 플레이 해 보았습니다 1), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/harupy/items/72990f9ddd17428f2a65텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)