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动态导入模块的方法实例分析
Jun 28 Python
Python实现聊天机器人的示例代码
Jul 09 Python
python中的插值 scipy-interp的实现代码
Jul 23 Python
利用python求积分的实例
Jul 03 Python
python区块及区块链的开发详解
Jul 03 Python
Django Channels 实现点对点实时聊天和消息推送功能
Jul 17 Python
python发qq消息轰炸虐狗好友思路详解(完整代码)
Feb 15 Python
Python模拟FTP文件服务器的操作方法
Feb 18 Python
Python结合Window计划任务监测邮件的示例代码
Aug 05 Python
python 机器学习的标准化、归一化、正则化、离散化和白化
Apr 16 Python
python数据分析之用sklearn预测糖尿病
Apr 22 Python
Python-OpenCV实现图像缺陷检测的实例
Jun 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
PHP Zip解压 文件在线解压缩的函数代码
2010/05/26 PHP
深入理解PHP中的Streams工具
2015/07/03 PHP
PHP+Mysql+jQuery文件下载次数统计实例讲解
2015/10/10 PHP
php生成唯一数字id的方法汇总
2015/11/18 PHP
laravel5创建service provider和facade的方法详解
2016/07/26 PHP
php实现文件与16进制相互转换的方法示例
2017/02/16 PHP
js去空格技巧分别去字符串前后、左右空格
2013/10/21 Javascript
extjs每个组件要设置唯一的ID否则会出错
2014/06/15 Javascript
JavaScript中用于四舍五入的Math.round()方法讲解
2015/06/15 Javascript
jQuery插件EasyUI设置datagrid的checkbox为禁用状态的方法
2016/08/05 Javascript
详解webpack解惑:require的五种用法
2017/06/09 Javascript
ionic中的$ionicPlatform.ready事件中的通用设置
2017/06/11 Javascript
微信小程序实现MUI数字输入框效果
2018/01/31 Javascript
浅谈实现vue2.0响应式的基本思路
2018/02/13 Javascript
当vue路由变化时,改变导航栏的样式方法
2018/08/22 Javascript
详解vuex 渐进式教程实例代码
2018/11/27 Javascript
vue实现滑动到底部加载更多效果
2020/10/27 Javascript
layui实现根据table数据判断按钮显示情况的方法
2019/09/26 Javascript
VUE+elementui组件在table-cell单元格中绘制微型echarts图
2020/04/20 Javascript
Node.js 中如何收集和解析命令行参数
2021/01/08 Javascript
Python中logging模块的用法实例
2014/09/29 Python
python登录豆瓣并发帖的方法
2015/07/08 Python
详解利用django中间件django.middleware.csrf.CsrfViewMiddleware防止csrf攻击
2018/10/09 Python
Python使用selenium + headless chrome获取网页内容的方法示例
2019/10/16 Python
python应用Axes3D绘图(批量梯度下降算法)
2020/03/25 Python
标签和贴纸印刷:Lightning Labels
2018/03/22 全球购物
Club Monaco加拿大官网:设计师男女服装
2019/09/29 全球购物
网络通讯中,端口有什么含义,端口的取值范围
2012/11/23 面试题
专科文秘应届生求职信
2013/11/18 职场文书
《雪地里的小画家》教学反思
2014/02/22 职场文书
大学生心理活动总结
2014/07/04 职场文书
学生吸烟检讨书
2014/09/14 职场文书
大学迎新生标语
2014/10/06 职场文书
2015年村级财务管理制度
2015/08/04 职场文书
MySQL 慢查询日志深入理解
2021/04/22 MySQL
Python可视化神器pyecharts绘制水球图
2022/07/07 Python