在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秒左右,这段时间游戏早就跑没了,所以要减少时间的瓶颈,首先缩小截图范围,其次利用一次截图尽可能做更多的操作。缩小截图范围就是根据用户点击的位置来做,而对于利用一次截图尽可能做更多操作,需要判断好黑块的位置。这里我尝试过好几种方式,最后最简单也最有效的是找最低点,如下:
上面二值图片中的灰色小点就是找到的每个黑块儿的最低点,也就是点击的点。
</pre><pre code_snippet_id="1742613" snippet_file_name="blog_20160703_3_102017" name="code" class="python">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