在4399上找到了“别踩白块儿”网页版小游戏,然后用python3写了一个自动玩的小脚本。使用Python3,OpenCV 3.
import cv2
import numpy as np
import os
import pyscreenshot as ss
import time
def onMouse(event, x, y, flags, param):
global flag, pLeftTop, pRightBottom
if event == cv2.EVENT_LBUTTONDOWN:
if flag:
pLeftTop = (x,y)
else:
pRightBottom = (x,y)
flag = False
flag = True
pLeftTop = None
pRightBottom = None
cv2.namedWindow('frame')
cv2.setMouseCallback('frame', onMouse)
img = ss.grab(bbox=(0,0,1300,768))
img = np.array(img)
cv2.imshow('frame', img)
if cv2.waitKey(0) & 0xff == ord(' '):
cv2.destroyAllWindows()
打开网页游戏后,运行程序首先显示截图界面,用户用鼠标点击来确定游戏场景的范围(点击左上和右下),目的是为了减少之后处理的代码量。
while True:
t0 = time.time()
img = ss.grab(bbox=(pLeftTop[0],pLeftTop[1],pRightBottom[0],pRightBottom[1]), childprocess=False, backend='imagemagick') #'imagemagick' runs fastest acording my test.
t1 = time.time()
print(round(t1-t0, 2))
target = np.array(img)
print(target.shape)
if target.shape[-1] != 3:
gray = target.reshape((target.shape[0],target.shape[1],1))
else:
gray = cv2.cvtColor(target, cv2.COLOR_BGR2GRAY)
if gray[1,1] < 150 and gray[1,1] > 130: #The Grayscale value of green background in the finishing page is 140
break
ret, thresh = cv2.threshold(gray, 5, 255, cv2.THRESH_BINARY_INV)
thresh = cv2.erode(thresh, None, iterations=5)
im, contours, hierarchy = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
num = 0
for c in contours:
topMost = tuple(c[c[:,:,1].argmin()][0])
bottomMost = tuple(c[c[:,:,1].argmax()][0])
if bottomMost[1]-topMost[1] < 50:
continue
pointX = int(bottomMost[0])
pointY = int(bottomMost[1])
cv2.circle(thresh, (pointX, pointY), 2, 125, 2)
realX = pointX + pLeftTop[0]
realY = pointY + pLeftTop[1]
os.system('xdotool mousemove '+ str(realX)+' '+str(realY))
os.system('xdotool click 1')
print(realX, realY)
count += 1
if count >= 12345:
break
#cv2.imwrite(str(count)+'.png', thresh)
#cv2.imwrite(str(count)+'.1.png',target)
time.sleep(0.1)
然后进入while循环进行处理,这里有几点要说一下。经过测试,在我的渣本上用pyscreenshot截一张1300x768的图片要耗时0.6秒左右,这段时间游戏早就跑没了,所以要减少时间的瓶颈,首先缩小截图范围,其次利用一次截图尽可能做更多的操作。缩小截图范围就是根据用户点击的位置来做,而对于利用一次截图尽可能做更多操作,需要判断好黑块的位置。这里我尝试过好几种方式,最后最简单也最有效的是找最低点,如下:
上面二值图片中的灰色小点就是找到的每个黑块儿的最低点,也就是点击的点。
topMost = tuple(c[c[:,:,1].argmin()][0]) bottomMost = tuple(c[c[:,:,1].argmax()][0])上面代码可以获取目标的最高点和最低点。所以我在程序中经过二值化后的目标,再进行一次腐蚀erode操作,然后找到每个分离目标的最低点,尽可能一次多点击几个目标,因为用linux下的xdotool操作鼠标是非常快的。最后要说的一点是程序最后的sleep的时间,因为点击黑块之后整体场景会向下移动,而且越来越快,截一张图的时间游戏场景的位置就会发生变化,所以我延时0.1秒之后才进行新一轮的处理,这样正确率更高。当然,如果笔记本性能足够,完全没必要sleep哈:-)
演示视频:http://www.bilibili.com/video/av5177461/
完整代码:https://github.com/littlethunder/pianoTiles
转载请注明: 转自http://blog.csdn.net/littlethunder/article/details/51816511