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入门篇之对象类型
Oct 17 Python
将Python中的数据存储到系统本地的简单方法
Apr 11 Python
一文总结学习Python的14张思维导图
Oct 17 Python
Python numpy 点数组去重的实例
Apr 18 Python
python 爬虫 批量获取代理ip的实例代码
May 22 Python
终端命令查看TensorFlow版本号及路径的方法
Jun 13 Python
Python单元测试unittest的具体使用示例
Dec 17 Python
python使用Plotly绘图工具绘制散点图、线形图
Apr 02 Python
Python实现疫情通定时自动填写功能(附代码)
May 27 Python
python使用matplotlib:subplot绘制多个子图的示例
Sep 24 Python
pip/anaconda修改镜像源,加快python模块安装速度的操作
Mar 04 Python
Python PIL按比例裁剪图片
May 11 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
星际争霸 Starcraft 发展史
2020/03/14 星际争霸
PHP实现网上点歌(二)
2006/10/09 PHP
php 结果集的分页实现代码
2009/03/10 PHP
php DOS攻击实现代码(附如何防范)
2012/05/29 PHP
PHP动态柱状图实现方法
2015/03/30 PHP
Yii2验证器(Validator)用法分析
2016/07/23 PHP
php写入mysql中文乱码的实例解决方法
2019/09/17 PHP
解决thinkphp5未定义变量会抛出异常,页面错误,请稍后再试的问题
2019/10/16 PHP
jQuery 对象中的类数组操作
2009/04/27 Javascript
JS画5角星方法介绍
2013/09/17 Javascript
JS 数字转换研究总结
2013/12/26 Javascript
js实现div的切换特效上一个下一个
2014/02/11 Javascript
javascript数组输出的两种方式
2015/01/13 Javascript
jQuery模拟Marquee实现无缝滚动效果完整实例
2016/09/29 Javascript
扩展Bootstrap Tooltip插件使其可交互的方法
2016/11/07 Javascript
浅谈JS中的常用选择器及属性、方法的调用
2017/07/28 Javascript
原生JS实现图片无缝滚动方法(附带封装的运动框架)
2017/10/01 Javascript
Vue中axios拦截器如何单独配置token
2019/12/27 Javascript
js滚轮事件 js自定义滚动条的实现
2020/01/18 Javascript
CentOS下使用yum安装python-pip失败的完美解决方法
2017/08/16 Python
Python实现可获取网易页面所有文本信息的网易网络爬虫功能示例
2018/01/15 Python
python实现梯度下降算法
2020/03/24 Python
Python sorted函数详解(高级篇)
2018/09/18 Python
python3使用QQ邮箱发送邮件
2020/05/20 Python
Python装饰器使用你可能不知道的几种姿势
2019/10/25 Python
使用css3制作登录表单的步骤
2014/04/07 HTML / CSS
美国皮靴公司自1863年:The Frye Company
2016/11/30 全球购物
缓解脚、腿和背部疼痛:Z-CoiL鞋
2019/03/12 全球购物
授权委托书样本
2014/04/03 职场文书
党的群众路线教育实践活动个人对照检查材料范文
2014/09/25 职场文书
2015年行政执法工作总结
2015/05/23 职场文书
2019年员工旷工保证书!
2019/06/28 职场文书
mybatis使用oracle进行添加数据的方法
2021/04/27 Oracle
Windows下用Nginx配置https服务器及反向代理的问题
2021/09/25 Servers
《王国之心》迎来了发售的20周年, 野村哲发布贺图
2022/04/11 其他游戏
插件导致ECharts被全量引入的坑示例解析
2022/09/23 Javascript