python实现连连看辅助(图像识别)


Posted in Python onMarch 25, 2020

个人兴趣,用python实现连连看的辅助程序,总结实现过程及知识点。

总体思路

1、获取连连看程序的窗口并前置
2、游戏界面截图,将每个一小图标切图,并形成由小图标组成的二维列表
3、对图片的二维列表遍历,将二维列表转换成由数字组成的二维数组,图片相同的数值相同。
4、遍历二维数组,找到可消除的对象,实现算法:

  • 两个图标相邻。(一条线连接)
  • 两个图标同行,同列,且中间的图标全部为空(数值为0)(一条线连接)
  • 两条线连接,转弯一次,路径上所有图标为空。(二条线连接)
  • 三条线连接,转弯二次,路径上所有图标为空。(三条线连接)
  • 分别点击两个图标,并将对应的二维数据值置为0

实现过程中遇到的问题

图片切割

im = image.crop((left,top,right,bottom))
//image.crop参数为一个列表或元组,顺序为(left,top,right,bottom)

找到游戏运行窗口

hdwd = win32gui.FindWindow(0,wdname)
# 设置为最前显示
win32gui.SetForegroundWindow(hdwd)

窗口不要点击最小化,点击后无法弹出来。

  • 图片缩放并转为灰度

img1 = im1.resize((20, 20), Image.ANTIALIAS).convert('L')

Image.ANTIALIAS 为抗锯齿的选项,图片无毛边。

  • 获取图片每个点的RGB值

pi1 = list(img1.getdata())

列表每个元素为一个三位数的值,分别代表该点的RGB值。列表pi1共400个元素。(因为图片为20*20)

  • 鼠标点击消除

PyMouse.click()该方法默认双击,改为PyMouse.press() 或 PyMouse.release()

  • 判断图片相似
  • 汉明距离,平均哈希
def compare_img(self,im1,im2):
 img1 = im1.resize((20, 20), Image.ANTIALIAS).convert('L')
 img2 = im2.resize((20, 20), Image.ANTIALIAS).convert('L')
 pi1 = list(img1.getdata())
 pi2 = list(img2.getdata())
 avg1 = sum(pi1) / len(pi1)
 avg2 = sum(pi2) / len(pi2)
 hash1 = "".join(map(lambda p: "1" if p > avg1 else "0", pi1))
 hash2 = "".join(map(lambda p: "1" if p > avg2 else "0", pi2))
 match = 0
 for i in range(len(hash1)):
 if hash1[i] != hash2[i]:
 match += 1
 # match = sum(map(operator.ne, hash1, hash2))
 # match 值越小,相似度越高
 return match
  • 计算直方图
from PIL import Image

# 将图片转化为RGB
def make_regalur_image(img, size=(8, 8)):
 gray_image = img.resize(size).convert('RGB')
 return gray_image


# 计算直方图
def hist_similar(lh, rh):
 assert len(lh) == len(rh)
 hist = sum(1 - (0 if l == r else float(abs(l - r)) / max(l, r)) for l, r in zip(lh, rh)) / len(lh)
 return hist


# 计算相似度
def calc_similar(li, ri):
 calc_sim = hist_similar(li.histogram(), ri.histogram())
 return calc_sim


if __name__ == '__main__':
 image1 = Image.open('1-10.jpg')
 image1 = make_regalur_image(image1)
 image2 = Image.open('2-11.jpg')
 image2 = make_regalur_image(image2)
 print("图片间的相似度为", calc_similar(image1, image2))
 # 值在[0,1]之间,数值越大,相似度越高
  • 图片余弦相似度
from PIL import Image
from numpy import average, dot, linalg


# 对图片进行统一化处理
def get_thum(image, size=(64, 64), greyscale=False):
 # 利用image对图像大小重新设置, Image.ANTIALIAS为高质量的
 image = image.resize(size, Image.ANTIALIAS)
 if greyscale:
 # 将图片转换为L模式,其为灰度图,其每个像素用8个bit表示
 image = image.convert('L')
 return image


# 计算图片的余弦距离
def image_similarity_vectors_via_numpy(image1, image2):
 image1 = get_thum(image1)
 image2 = get_thum(image2)
 images = [image1, image2]
 vectors = []
 norms = []
 for image in images:
 vector = []
 for pixel_tuple in image.getdata():
 vector.append(average(pixel_tuple))
 vectors.append(vector)
 # linalg=linear(线性)+algebra(代数),norm则表示范数
 # 求图片的范数??
 norms.append(linalg.norm(vector, 2))
 a, b = vectors
 a_norm, b_norm = norms
 # dot返回的是点积,对二维数组(矩阵)进行计算
 res = dot(a / a_norm, b / b_norm)
 return res

if __name__ == '__main__':

 image1 = Image.open('1-9.jpg')
 image2 = Image.open('8-6.jpg')
 cosin = image_similarity_vectors_via_numpy(image1, image2)
 print('图片余弦相似度', cosin)
 # 值在[0,1]之间,数值越大,相似度越高,计算量较大,效率较低

完整代码

import win32gui
import time
from PIL import ImageGrab , Image
import numpy as np
from pymouse import PyMouse


class GameAuxiliaries(object):
 def __init__(self):
 self.wdname = r'宠物连连看经典版2,宠物连连看经典版2小游戏,4399小游戏 www.4399.com - Google Chrome'
 # self.wdname = r'main.swf - PotPlayer'
 self.image_list = {}
 self.m = PyMouse()
 def find_game_wd(self,wdname):
 # 取得窗口句柄
 hdwd = win32gui.FindWindow(0,wdname)
 # 设置为最前显示
 win32gui.SetForegroundWindow(hdwd)
 time.sleep(1)

 def get_img(self):
 image = ImageGrab.grab((417, 289, 884, 600))
 # image = ImageGrab.grab((417, 257, 885, 569))
 image.save('1.jpg','JPEG')
 for x in range(1,9):
 self.image_list[x] = {}
 for y in range(1,13):
 top = (x - 1) * 38 + (x-2)
 left =(y - 1) * 38 +(y-2)
 right = y * 38 + (y-1)
 bottom = x * 38 +(x -1)
 if top < 0:
 top = 0
 if left < 0 :
 left = 0
 im_temp = image.crop((left,top,right,bottom))
 im = im_temp.crop((1,1,37,37))
 im.save('{}-{}.jpg'.format(x,y))
 self.image_list[x][y]=im

 # 判断两个图片是否相同。汉明距离,平均哈希
 def compare_img(self,im1,im2):
 img1 = im1.resize((20, 20), Image.ANTIALIAS).convert('L')
 img2 = im2.resize((20, 20), Image.ANTIALIAS).convert('L')
 pi1 = list(img1.getdata())
 pi2 = list(img2.getdata())
 avg1 = sum(pi1) / len(pi1)
 avg2 = sum(pi2) / len(pi2)
 hash1 = "".join(map(lambda p: "1" if p > avg1 else "0", pi1))
 hash2 = "".join(map(lambda p: "1" if p > avg2 else "0", pi2))
 match = 0
 for i in range(len(hash1)):
 if hash1[i] != hash2[i]:
 match += 1
 # match = sum(map(operator.ne, hash1, hash2))
 # match 值越小,相似度越高
 return match


 # 将图片矩阵转换成数字矩阵

 def create_array(self):
 array = np.zeros((10,14),dtype=np.int32)
 img_type_list = []
 for row in range(1,len(self.image_list)+1):
 for col in range(1,len(self.image_list[1])+1):
 # im = Image.open('{}-{}.jpg'.format(row,col))
 im = self.image_list[row][col]
 for img in img_type_list:
 match = self.compare_img(im,img)
 # match = test2.image_similarity_vectors_via_numpy(im,img)
 if match <15:
 array[row][col] = img_type_list.index(img) +1

 break
 else:
 img_type_list.append(im)
 array[row][col] = len(img_type_list)

 return array

 def row_zero(self,x1,y1,x2,y2,array):
 '''相同的图片中间图标全为空'''
 if x1 == x2:
 min_y = min(y1,y2)
 max_y = max(y1,y2)
 if max_y - min_y == 1:
 return True
 for y in range(min_y+1,max_y):
 if array[x1][y] != 0 :
 return False
 return True
 else:
 return False

 def col_zero(self,x1,y1,x2,y2,array):
 '''相同的图片同列'''
 if y1 == y2:
 min_x = min(x1,x2)
 max_x = max(x1,x2)
 if max_x - min_x == 1:
 return True
 for x in range(min_x+1,max_x):
 if array[x][y1] != 0 :
 return False
 return True
 else:
 return False

 def two_line(self,x1,y1,x2,y2,array):
 '''两条线相连,转弯一次'''
 for row in range(1,9):
 for col in range(1,13):
 if row == x1 and col == y2 and array[row][col]==0 and self.row_zero(x1,y1,row,col,array) and self.col_zero(x2,y2,row,col,array):
 return True
 if row == x2 and col == y1 and array[row][col]==0 and self.row_zero(x2,y2,row,col,array) and self.col_zero(x1,y1,row,col,array):
 return True
 return False

 def three_line(self,x1,y1,x2,y2,array):
 '''三条线相连,转弯两次'''
 for row1 in range(10):
 for col1 in range(14):
 for row2 in range(10):
 for col2 in range(14):
 if array[row1][col1] == array[row2][col2] == 0 and self.row_zero(x1,y1,row1,col1,array) and self.row_zero(x2,y2,row2,col2,array) and self.col_zero(row1,col1,row2,col2,array):
 return True
 if array[row1][col1] == array[row2][col2] == 0 and self.col_zero(x1,y1,row1,col1,array) and self.col_zero(x2,y2,row2,col2,array) and self.row_zero(row1,col1,row2,col2,array):
 return True
 if array[row1][col1] == array[row2][col2] == 0 and self.row_zero(x2,y2,row1,col1,array) and self.row_zero(x1,y1,row2,col2,array) and self.col_zero(row1,col1,row2,col2,array):
 return True
 if array[row1][col1] == array[row2][col2] == 0 and self.col_zero(x2,y2,row1,col1,array) and self.col_zero(x1,y1,row2,col2,array) and self.row_zero(row1,col1,row2,col2,array):
 return True
 return False


 def mouse_click(self,x,y):

 top = (x - 1) * 38 + (x - 2)
 left = (y - 1) * 38 + (y - 2)
 right = y * 38 + (y - 1)
 bottom = x * 38 + (x - 1)
 if top < 0:
 top = 0
 if left < 0:
 left = 0

 self.m.press(int(417+(left+right)/2) ,int(289+(top+bottom)/2) )

 def find_same_img(self,array):

 for x1 in range(1,9):
 for y1 in range(1,13):
 if array[x1][y1] == 0:
 continue
 for x2 in range(1,9):
 for y2 in range(1,13):
 if x1==x2 and y1 == y2:
 continue
 if array[x2][y2] == 0 :
 continue
 if array[x1][y1] != array[x2][y2] :
 continue
 if array[x1][y1] ==array[x2][y2] and (self.row_zero(x1,y1,x2,y2,array) or self.col_zero(x1,y1,x2,y2,array) or self.two_line(x1,y1,x2,y2,array) or self.three_line(x1,y1,x2,y2,array)):
 print("可消除!x{}y{} 和 x{}y{}".format(x1,y1,x2,y2))
 self.mouse_click(x1,y1)
 time.sleep(0.1)
 self.mouse_click(x2,y2)
 time.sleep(0.1)
 array[x1][y1]=array[x2][y2]=0


 def run(self):
 #找到游戏运行窗口
 self.find_game_wd(self.wdname)
 # 截图,切割成小图标
 self.get_img()
 # 将图片矩阵转换成数字矩阵
 array = self.create_array()
 print(array)
 # 遍历矩阵,找到可消除项,点击消除
 for i in range(10):
 self.find_same_img(array)
 print(array)


if __name__ == '__main__':
 ga = GameAuxiliaries()
 ga.run()

总结

该程序其实未能完全实现辅助功能,主要是因为图片切割时未找到更好的规则,造成图片识别困难,缩放比例和判断阀值未找到一个平衡点,阀值太大,则将不同的图标识别为相同,阀值太小,相同的图标又判断为不一样。

更多关于python游戏的精彩文章请点击查看以下专题:

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
MySQLdb ImportError: libmysqlclient.so.18解决方法
Aug 21 Python
python基于windows平台锁定键盘输入的方法
Mar 05 Python
Python函数式编程指南(一):函数式编程概述
Jun 24 Python
python字典基本操作实例分析
Jul 11 Python
在Python的Django框架中更新数据库数据的方法
Jul 17 Python
spyder常用快捷键(分享)
Jul 19 Python
python使用Flask操作mysql实现登录功能
May 14 Python
python3使用SMTP发送HTML格式邮件
Jun 19 Python
浅谈Python3 numpy.ptp()最大值与最小值的差
Aug 24 Python
numpy数组做图片拼接的实现(concatenate、vstack、hstack)
Nov 08 Python
Python如何实现爬取B站视频
May 20 Python
Python小白不正确的使用类变量实例
May 29 Python
Django中多种重定向方法使用详解
Jul 17 #Python
200行python代码实现2048游戏
Jul 17 #Python
Django后端接收嵌套Json数据及解析详解
Jul 17 #Python
Python制作微信好友背景墙教程(附完整代码)
Jul 17 #Python
python代码编写计算器小程序
Mar 30 #Python
Django Channels 实现点对点实时聊天和消息推送功能
Jul 17 #Python
Python Django的安装配置教程图文详解
Jul 17 #Python
You might like
php 动态添加记录
2009/03/10 PHP
PHP jQuery表单,带验证具体实现方法
2014/02/15 PHP
php使用imagick模块实现图片缩放、裁剪、压缩示例
2014/04/17 PHP
JS异常处理try..catch语句的作用和实例
2014/05/05 PHP
在Nginx上部署ThinkPHP项目教程
2015/02/02 PHP
判断iframe是否加载完成的完美方法
2010/01/07 Javascript
HTML DOM的nodeType值介绍
2011/03/31 Javascript
深入理解JavaScript系列(30):设计模式之外观模式详解
2015/03/03 Javascript
js生成随机数的过程解析
2015/11/24 Javascript
jquery中object对象循环遍历的方法
2015/12/18 Javascript
提升jQuery的性能需要做好七件事
2016/01/11 Javascript
动态创建按钮的JavaScript代码
2016/01/29 Javascript
JavaScript隐式类型转换
2016/03/15 Javascript
JavaScript 经典实例日常收集整理(常用经典)
2016/03/30 Javascript
功能强大的Bootstrap效果展示(二)
2016/08/03 Javascript
vue多级多选菜单组件开发
2020/09/08 Javascript
基于jQuery实现弹幕APP
2017/02/10 Javascript
React Native中NavigatorIOS组件的简单使用详解
2018/01/27 Javascript
jQuery中可见性过滤器简单用法示例
2018/03/31 jQuery
基于 jQuery 实现键盘事件监听控件
2019/04/04 jQuery
Vue移动端实现图片上传及超过1M压缩上传
2019/12/23 Javascript
基于javascript处理二进制图片流过程详解
2020/06/08 Javascript
浅析微信小程序自定义日历组件及flex布局最后一行对齐问题
2020/10/29 Javascript
原生js实现点击按钮复制内容到剪切板
2020/11/19 Javascript
Python 拷贝对象(深拷贝deepcopy与浅拷贝copy)
2008/09/06 Python
Python实现PS图像调整黑白效果示例
2018/01/25 Python
对python打乱数据集中X,y标签对的方法详解
2018/12/14 Python
Python如何获得百度统计API的数据并发送邮件示例代码
2019/01/27 Python
python简单验证码识别的实现方法
2019/05/10 Python
python取余运算符知识点详解
2019/06/27 Python
pytorch中的embedding词向量的使用方法
2019/08/18 Python
Python Merge函数原理及用法解析
2020/09/16 Python
PyCharm 2020.2下配置Anaconda环境的方法步骤
2020/09/23 Python
python 爬取小说并下载的示例
2020/12/07 Python
竞选学生会主席演讲稿
2014/04/24 职场文书
SQL中的三种去重方法小结
2021/11/01 SQL Server