ADB命令
python执行os命令 os.system(‘cmd’)
ADB截屏命令 adb shell screencap -p /sdcard/shot.png
ADB下载手机图片 adb pull /sdcard/shot.png
图片文件操作
使用PIL.Image库 from PIL import Image
定位棋盘位置
详见代码
定位小旗子
详见代码
跳跃位置计算
详见代码
完整代码
#coding=utf-8
import os
import time
from PIL import Image
import matplotlib.pyplot as plt
import numpy as np
import random
def capture():
os.system('adb shell screencap -p /sdcard/shot.png')
os.system('adb pull /sdcard/shot.png')
def goto_location(x,y,v):
press_time = (int)(v * 1.93)
print('adb shell input swipe {x1} {y1} {x2} {y2} {v}'.format(x1=x,y1=y,x2=x,y2=y,v=press_time))
os.system('adb shell input swipe {x1} {y1} {x2} {y2} {v}'.format(x1=x,y1=y,x2=x,y2=y,v=press_time))
def locate_checkerboard(image, dir_flg):
'''
定位目标位置
:param image: 游戏画面
:dir_flg: 小旗子位置标志,dir_flg=0,小旗子处于屏幕左边,反之则小旗子处于屏幕靠右
:return: 目标位置坐标点
'''
w,h = image.size
found_aim = False
y = -1
x = -1
for i in range(h//3,h):
left_pixel = image.getpixel((0,i))
if dir_flg == 1:
for j in range(0,w//2):
pixel = image.getpixel((j,i))
if left_pixel != pixel:
found_aim = True
x = j
break
else:
for j in range(0,w//2):
pixel = image.getpixel((w-j-1,i))
if left_pixel != pixel:
found_aim = True
x = w-j-1
break
if found_aim:
y = i+40
break
if x == -1 or y == -1:
raise Exception('Not Found piece')
return x, y
def locate_piece(image_s, image_t):
pixels_t = image_t.load()
pixels_s = image_s.load()
width_t, height_t = image_t.size
width_s, height_s = image_s.size
D = []
time_start = time.time()
for i in range(50, width_s-width_t-50, 10):
for j in range(300, height_s-height_t-300, 25):
d = 0
for x in range(width_t):
for y in range(height_t):
d += abs(pixels_t[x, y] - pixels_s[i+x, j+y])
D.append((i, j, d))
print('completed %%%d' % (((i+1)/(width_s-width_t))*100) )
time_end = time.time()
print('cost time %s ms' % str((time_end-time_start)*1000))
min = D[0][2]
x = 0
y = 0
for i in range(len(D)):
d = D[i]
if min > d[2]:
min = d[2]
x = d[0]
y = d[1]
x = x+ width_t//2
y = y+ (int)(height_t*0.936)
print('piece found at (%d,%d)' % (x, y))
return x, y
def calculate_distance(x1, y1, x2, y2):
x = x1-x2
y = y1-y2
return (x**2+y**2)**0.5
def random_generate(width, height):
x1 = random.randint(100,width-100)
y1 = random.randint(200,height-200)
return x1, y1
def location(x1, y1, time):
x2 = x1 + random.randint(1,9)
y2 = y1 + random.randint(3,12)
command = 'adb shell input swipe {x1} {y1} {x2} {y2} {v}'.format(x1=x1, y1=y1, x2=x2, y2=y2,v=time)
print(command)
os.system(command)
def main_thread():
image_t = Image.open('flag_gray.png', 'r') # MAD算法模板图T
while True:
capture() # 截取游戏画面
image_s = Image.open('shot.png', 'r').convert('L') # type:Image.Image
image_s.convert()
w,h = image_s.size
x1, y1 = locate_piece(image_s, image_t) # MAD算法定位小棋子图标
f = 0
if x1 > w/2:
f = 1
print('dir_flg = %d' % f )
x2, y2 = locate_checkerboard(image_s,f) # 定位跳跃目标位置
distance = calculate_distance(x1, y1, x2, y2) # 计算小棋子到目标位置的距离
print('distance of (%d,%d)->(%d,%d) is %d pixel' % (x1, y1, x2, y2, distance))
press_time = (int)(distance * 1.966) # 根据距离计算按压时长
x, y = random_generate(w,h) # 随机生成按压坐标
print('locate to (%d,%d), press time is %d ms' % (x2,y2,press_time))
location(x, y, press_time) # 模拟手指按压屏幕
time.sleep(random.randrange(990,1990,15)/1000.0)
if __name__ == '__main__':
main_thread()
写在最后的话
相对于第一个版本,V2.0改善了两个地方,一是小旗子的定位算法,用自己的代码实现了最简单的基于灰度图像匹配的MAD算法。二是优化了棋盘位置的定位算法。
跳一跳游戏界面元素比较单一,MAD算法表现还不错,识别精度也较高。在实际运行中发现V1.0版本的棋盘定位算法在小旗子顶部高于棋盘顶部位置时会失败,通过分析得知,小旗子相对于屏幕中心位置来说,只有两种状态,一种是小旗子相对于屏幕中心处于左边,另一种则是小旗子相对于屏幕中心处于右边,在查找棋盘时,把小旗子的位置状态考虑进去。当旗子处于左边时,可以从屏幕最右边向屏幕中心开始定位棋盘,反正同理。
V2.0的不足之处在于,MAD模板匹配算法太耗时,平局耗时在8秒左右,目前有两个办法来解决这个问题,一是把MAD模块用C语言完成,从python中直接导入。二是使用OpenCV,这个强大的开源图像处理库应该实现了各种灰度图像的匹配算法,效率也应该比较高。
此版本得分在400-700分,比V1.0有所提高,但是相比其他大牛的,还是有很大差距,继续努力。。。
有需要完整工程的朋友,请联系QQ772148609。