python實現(xiàn)連連看輔助(圖像識別)
個人興趣,用python實現(xiàn)連連看的輔助程序,總結(jié)實現(xiàn)過程及知識點。
總體思路
1、獲取連連看程序的窗口并前置
2、游戲界面截圖,將每個一小圖標切圖,并形成由小圖標組成的二維列表
3、對圖片的二維列表遍歷,將二維列表轉(zhuǎn)換成由數(shù)字組成的二維數(shù)組,圖片相同的數(shù)值相同。
4、遍歷二維數(shù)組,找到可消除的對象,實現(xiàn)算法:
- 兩個圖標相鄰。(一條線連接)
- 兩個圖標同行,同列,且中間的圖標全部為空(數(shù)值為0)(一條線連接)
- 兩條線連接,轉(zhuǎn)彎一次,路徑上所有圖標為空。(二條線連接)
- 三條線連接,轉(zhuǎn)彎二次,路徑上所有圖標為空。(三條線連接)
- 分別點擊兩個圖標,并將對應(yīng)的二維數(shù)據(jù)值置為0
實現(xiàn)過程中遇到的問題
圖片切割
im = image.crop((left,top,right,bottom)) //image.crop參數(shù)為一個列表或元組,順序為(left,top,right,bottom)
找到游戲運行窗口
hdwd = win32gui.FindWindow(0,wdname) # 設(shè)置為最前顯示 win32gui.SetForegroundWindow(hdwd)
窗口不要點擊最小化,點擊后無法彈出來。
- 圖片縮放并轉(zhuǎn)為灰度
img1 = im1.resize((20, 20), Image.ANTIALIAS).convert('L')
Image.ANTIALIAS 為抗鋸齒的選項,圖片無毛邊。
- 獲取圖片每個點的RGB值
pi1 = list(img1.getdata())
列表每個元素為一個三位數(shù)的值,分別代表該點的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
# 將圖片轉(zhuǎn)化為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]之間,數(shù)值越大,相似度越高
- 圖片余弦相似度
from PIL import Image
from numpy import average, dot, linalg
# 對圖片進行統(tǒng)一化處理
def get_thum(image, size=(64, 64), greyscale=False):
# 利用image對圖像大小重新設(shè)置, Image.ANTIALIAS為高質(zhì)量的
image = image.resize(size, Image.ANTIALIAS)
if greyscale:
# 將圖片轉(zhuǎn)換為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(代數(shù)),norm則表示范數(shù)
# 求圖片的范數(shù)??
norms.append(linalg.norm(vector, 2))
a, b = vectors
a_norm, b_norm = norms
# dot返回的是點積,對二維數(shù)組(矩陣)進行計算
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]之間,數(shù)值越大,相似度越高,計算量較大,效率較低
完整代碼
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'寵物連連看經(jīng)典版2,寵物連連看經(jīng)典版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)
# 設(shè)置為最前顯示
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
# 將圖片矩陣轉(zhuǎn)換成數(shù)字矩陣
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):
'''兩條線相連,轉(zhuǎn)彎一次'''
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):
'''三條線相連,轉(zhuǎn)彎兩次'''
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()
# 將圖片矩陣轉(zhuǎn)換成數(shù)字矩陣
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()
總結(jié)
該程序其實未能完全實現(xiàn)輔助功能,主要是因為圖片切割時未找到更好的規(guī)則,造成圖片識別困難,縮放比例和判斷閥值未找到一個平衡點,閥值太大,則將不同的圖標識別為相同,閥值太小,相同的圖標又判斷為不一樣。
更多關(guān)于python游戲的精彩文章請點擊查看以下專題:
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
python3.6 實現(xiàn)AES加密的示例(pyCryptodome)
本篇文章主要介紹了python3.6 實現(xiàn)AES加密的示例(pyCryptodome),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-01-01
python3實現(xiàn)名片管理系統(tǒng)(控制臺版)
這篇文章主要為大家詳細介紹了python3實現(xiàn)名片管理系統(tǒng)控制臺版,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2020-11-11
selenium設(shè)置瀏覽器為headless無頭模式(Chrome和Firefox)
這篇文章主要介紹了selenium設(shè)置瀏覽器為headless無頭模式(Chrome和Firefox),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習或者工作具有一定的參考學(xué)習價值,需要的朋友們下面隨著小編來一起學(xué)習學(xué)習吧2021-01-01
Pandas實現(xiàn)groupby分組統(tǒng)計方法實例
在數(shù)據(jù)處理的過程,有可能需要對一堆數(shù)據(jù)分組處理,例如對不同的列進行agg聚合操作(mean,min,max等等),下面這篇文章主要給大家介紹了關(guān)于Pandas實現(xiàn)groupby分組統(tǒng)計方法的相關(guān)資料,需要的朋友可以參考下2023-06-06
python飛機大戰(zhàn)pygame游戲背景設(shè)計詳解
這篇文章主要介紹了python飛機大戰(zhàn)pygame游戲背景設(shè)計,結(jié)合實例形式詳細分析了Python使用pygame模塊設(shè)計游戲背景相關(guān)原理、流程與實現(xiàn)技巧,需要的朋友可以參考下2019-12-12

