#!/usr/bin/env python2
# -*- coding: utf-8 -*-
import cv2
import win32gui
import win32ui
import win32con
import win32api
from pylab import *
from ctypes import windll
# 从x,y位置,截图长宽w,h
# 结果图片啊是个bmp编码,文件较大
# 如果只传入文件名,则截取全屏
def capture_screen_win32(filename, x=None, y=None, w=None, h=None):
if not filename.endswith('.bmp'):
filename += '.bmp' # 没有后缀时添加一个
if x is None or y is None or w is None or h is None:
display_dev = win32api.EnumDisplayMonitors(None, None)
w, h = display_dev[0][2][2], display_dev[0][2][3]
x, y = 0, 0 # 如果没有传入参数,则截取全屏
hwnd = 0 # 窗口的编号,0号表示当前活跃窗口
# 根据窗口句柄获取窗口的设备上下文DC(Divice Context)
hwnd_dc = win32gui.GetWindowDC(hwnd)
# 根据窗口的DC获取mfcDC
mfc_dc = win32ui.CreateDCFromHandle(hwnd_dc)
# mfcDC创建可兼容的DC
save_dc = mfc_dc.CreateCompatibleDC()
# 创建bigmap准备保存图片
save_bitmap = win32ui.CreateBitmap()
# 为bitmap开辟空间
save_bitmap.CreateCompatibleBitmap(mfc_dc, w, h)
# 高度saveDC,将截图保存到saveBitmap中
save_dc.SelectObject(save_bitmap)
# 截取从左上角(x,y)长宽为(w,h)的图片
save_dc.BitBlt((0, 0), (w, h), mfc_dc, (x, y), win32con.SRCCOPY)
save_bitmap.SaveBitmapFile(save_dc, filename)
# 下面释放资源
mfc_dc.DeleteDC()
save_dc.DeleteDC()
win32gui.ReleaseDC(hwnd, hwnd_dc)
win32gui.DeleteObject(save_bitmap.GetHandle())
# 鼠标左键点击一次
def mouse_click(click_y=None, click_x=None):
if click_x is not None and click_y is not None:
windll.user32.SetCursorPos(click_x, click_y)
time.sleep(1) # 每次点击都带停顿,避免操作太快了
win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0)
win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP, 0, 0, 0, 0)
# 处理水果的类,后面改成宠物连连看了
class Fruits:
def __init__(self, start_x, start_y):
# 保存游戏正真的左上角起始位置
self.start_x, self.start_y = start_x, start_y
# 存储数据为12行,16列
self.row, self.col = 12, 16
# 一个小图片区域的长宽
self.fruit_x, self.fruit_y = 36, 32
# 保存矩阵数据,预留为12行和16列
self.data = [[0 for _ in range(self.col)] for _ in range(self.row)]
def capture_game_data(self, threshold=0.99):
# 将游戏界面截图一张,用于分析每个位置的水果
capture_screen_win32('game', self.start_x, self.start_y, 608, 392)
# 每个水果格子缓存图像数据的画布,每个格子长35,宽31,要存rgb值
canvas = np.zeros((self.fruit_y, self.fruit_x, 3), dtype='uint8')
# 读取游戏截图的彩色图数据
game_rgb = cv2.imread('game.bmp')
# 标记水果的编号
flag_fruits = 1
for f_y in range(self.row - 2):
for f_x in range(self.col - 2):
# 已经被标记的不用重复标记
if self.data[f_y + 1][f_x + 1] == 0:
# 扣一个长方形,将原图数据缓存到canvas,要存rgb值
for c_y in range(self.fruit_y):
for c_x in range(self.fruit_x):
px, py = c_x + 44 * f_x, c_y + 40 * f_y
canvas[c_y, c_x, 0] = game_rgb[py, px, 0]
canvas[c_y, c_x, 1] = game_rgb[py, px, 1]
canvas[c_y, c_x, 2] = game_rgb[py, px, 2]
if np.mean(canvas) < 30.0:
continue # 此处没有要消除的图片
# 匹配当前抠出的水果,通过z匹配得到该水果的所有位置
res = cv2.matchTemplate(game_rgb, canvas, cv2.TM_CCOEFF_NORMED)
loc = np.where(res >= threshold) # 这个阈值很重要,要取合适的
for pt in zip(*loc[::-1]):
my, mx = (pt[1] + 10) // 40 + 1, (pt[0] + 10) // 44 + 1
if self.data[my][mx] == 0:
# 当前位置没有标记水果,则标记一下,加入判断避免重复标记
self.data[my][mx] = flag_fruits
# 下面的循环将剔除已经被标记的区域,之后的匹配更快
for c_y in range(self.fruit_y):
for c_x in range(self.fruit_x):
px, py = pt[0] + c_x, pt[1] + c_y
game_rgb[py, px, 0], game_rgb[py, px, 1], game_rgb[py, px, 2] = 0, 0, 0
# cv2.putText(game_rgb, str(flag_fruits), (pt[0], pt[1] + 25), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 2)
flag_fruits += 1 # 标记完一个水果就标记下一个
print flag_fruits
# cv2.imwrite('c3.png', game_rgb)
def print_data(self):
# 将数据存入文件,查看每个图片的编号和位置
fw = open('data.txt', 'w')
for mi in range(self.row):
for mj in range(self.col):
fw.write('%3i' % self.data[mi][mj])
fw.write('\n')
fw.close()
def is_win(self):
# 返回False表示已经胜利,返回True表示还要继续
for win_y in range(self.row):
for win_x in range(self.col):
if self.data[win_y][win_x] > 0:
return True
return False
def click_fruits(self, click_y1, click_x1, click_y2, click_x2):
# 根据编号位置,和图像起始位置,计算鼠标点击位置
mouse_click(self.start_y + 40 * (click_y1 - 1) + 20, self.start_x + 44 * (click_x1 - 1) + 20)
mouse_click(self.start_y + 40 * (click_y2 - 1) + 20, self.start_x + 44 * (click_x2 - 1) + 20)
# 已经连线后,这两个点标记为空白,后面的计算才能正常
self.data[click_y1][click_x1], self.data[click_y2][click_x2] = 0, 0
def play_game(self):
self.capture_game_data()
self.print_data()
# 这里分析数据来控制鼠标玩游戏
while self.is_win():
# 为每个编号的水果添加坐标数组
num_list = {}
# 遍历整个矩阵,找出那种需要拐弯相连的水果
for play_y in range(1, self.row - 1):
for play_x in range(1, self.col - 1):
tmp_num = self.data[play_y][play_x]
if tmp_num > 0: # 当前位置有编号才行
if tmp_num in num_list: # 判断字典key存在则追加,不存在则创建
num_list[tmp_num].append([play_y, play_x])
else:
num_list[tmp_num] = [[play_y, play_x]]
# 遍历相同水果不同位置,看看能不能连起来
for values in num_list.values():
# 得到每种编号水果位置的个数
val_len = len(values)
for val_i in range(val_len):
y1, x1 = values[val_i][0], values[val_i][1]
# 确保该点没有被消除,因为运算过程中可能消掉
if self.data[y1][x1] > 0:
for val_j in range(val_i + 1, val_len):
y2, x2 = values[val_j][0], values[val_j][1]
# 确保该点没有被消除,因为运算过程中可能消掉
if self.data[y2][x2] > 0:
if self.connect_pos(y1, x1, y2, x2):
- 1
- 2
- 3
前往页