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 相关文章推荐
python使用正则搜索字符串或文件中的浮点数代码实例
Jul 11 Python
Python脚本实现DNSPod DNS动态解析域名
Feb 14 Python
浅谈python中的getattr函数 hasattr函数
Jun 14 Python
Python获取文件所在目录和文件名的方法
Jan 12 Python
Python人脸识别初探
Dec 21 Python
python爬虫之urllib,伪装,超时设置,异常处理的方法
Dec 19 Python
Python实现简单层次聚类算法以及可视化
Mar 18 Python
PyQt5 对图片进行缩放的实例
Jun 18 Python
Flask模板引擎Jinja2使用实例
Apr 23 Python
Python 程序员必须掌握的日志记录
Aug 17 Python
用Python实现童年贪吃蛇小游戏功能的实例代码
Dec 07 Python
Python爬虫实现selenium处理iframe作用域问题
Jan 27 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正则的Unknown Modifier错误解决方法
2010/03/02 PHP
php设计模式 Decorator(装饰模式)
2011/06/26 PHP
Laravel模板引擎Blade中section的一些标签的区别介绍
2015/02/10 PHP
php无限极分类实现方法分析
2019/07/04 PHP
DOM_window对象属性之--clipboardData对象操作代码
2011/02/03 Javascript
jQuery对表单的操作代码集合
2011/04/06 Javascript
动态获取复选框checkbox选中个数的jquery代码
2013/06/25 Javascript
jquery 操作iframe的几种方法总结
2013/12/13 Javascript
jQuery dataTables与jQuery UI 对话框dialog的使用教程
2016/09/02 Javascript
vue-router实现组件间的跳转(参数传递)
2017/11/07 Javascript
记一次Vue.js混入mixin的使用(分权限管理页面)
2019/04/17 Javascript
一次让你了解全部JavaScript的作用域
2019/06/24 Javascript
JavaScript动态生成表格的示例
2020/11/02 Javascript
JavaScript实现弹出窗口效果
2020/12/09 Javascript
python虚拟环境virualenv的安装与使用
2016/12/18 Python
Python中将变量按行写入txt文本中的方法
2018/04/03 Python
详解python3中tkinter知识点
2018/06/21 Python
Python基于BeautifulSoup和requests实现的爬虫功能示例
2019/08/02 Python
使用OpenCV实现仿射变换—旋转功能
2019/08/29 Python
python网络编程 使用UDP、TCP协议收发信息详解
2019/08/29 Python
Window系统下Python如何安装OpenCV库
2020/03/05 Python
Python基于stuck实现scoket文件传输
2020/04/02 Python
Django多层嵌套ManyToMany字段ORM操作详解
2020/05/19 Python
理解Django 中Call Stack机制的小Demo
2020/09/01 Python
Keras保存模型并载入模型继续训练的实现
2021/02/20 Python
python实现控制台输出颜色
2021/03/02 Python
浅谈HTML5 FileReader分布读取文件以及其方法简介
2017/11/09 HTML / CSS
html5 canvas实现给图片添加平铺水印
2019/08/20 HTML / CSS
德国最新街头服饰网上商店:BODYCHECK
2019/09/15 全球购物
学校机关党总支领导班子整改工作方案
2014/10/26 职场文书
关爱留守儿童主题班会
2015/08/13 职场文书
2016党校学习心得体会
2016/01/07 职场文书
领导干部学习心得体会
2016/01/23 职场文书
2016年度创先争优活动总结
2016/04/05 职场文书
农村房屋租赁合同(范本)
2019/07/23 职场文书
Win10鼠标轨迹怎么开 Win10显示鼠标轨迹方法
2022/04/06 数码科技