概述
通过图片识别来对分析游戏当前状态
前篇:深度强化学习制作森林冰火人游戏AI(四)获取窗口部分界面
游戏状态切换图
附言:
可以看到游戏界面的切换方法还是稍微有点多的(其实很少哈哈哈)
理论上来说,如果只是训练代码的话,如果不出意外的话只需要在分析出游戏界面和死亡胜利界面的区别就好
(但是谁能拦得住电脑抽风呢?)
更何况,我的目标是训练出更聪明玩森林冰火人的ai(只能玩这款游戏,不能玩其他版本也行),而不是只能玩某一关冰火人的ai
为了训练更聪明的ai,自然而然的需要将多个关卡都放进训练环境内,这就导致了我不可避免的需要进入选关界面。
既然四个状态已经有三个要识别了,那么最简单的游戏开始界面干脆也都加进来了
所以最终我的目标是游戏在任一状态下,算法都能出别出游戏当前状态,并朝着我的目标切换状态
游戏状态识别原理
游戏状态识别是通过比较不同的游戏界面。
将当前的游戏界面与预先定义的游戏界面作比较,相似度高则认为这是某个界面
界面区域选择
合适的比较区域可以更好地让算法得到理想的结果
在森林冰火人这款游戏里,我最终选择了左上角坐标(46,50),长15,宽15的矩形区域
相对来说还是稍微能看出来明显不同的(才发现这么相近,但总归能识别出来就好)
保存界面
这里用的是获取 部分窗口截屏 代码里面的方法获取的预定义图片
然后将其转换为np数组打印出来保存
def print_game_state(state):
arr=np.array(state)
print('np.array([')
for i in range(len(arr)):
print('[',end='')
for j in range(len(arr[i])):
print('[',arr[i][j][0],',',arr[i][j][1],',',arr[i][j][2],',',arr[i][j][3],'],',end='')
print('],')
print('])')
手动复制粘贴至代码中
识别方法
识别方法使用的是图像识别,而图像识别的方法就有很多种了
这里使用的是计算直方图相似度
# 将图片转化为RGB
from PIL import Image
regular_size=64
def make_regalur_image(img, size=(regular_size, regular_size)):
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
def pic_similar(img1, img2):
image1 = make_regalur_image(img1)
image2 = make_regalur_image(img2)
return calc_similar(image1, image2)
#计算直方图相似度
if __name__ == '__main__':
img1 = "1.JPG"
img2 = "2.JPG"
image1 = Image.open(img1)
image2 = Image.open(img2)
print("图片间的相似度为", pic_similar(image1, image2))
通过调用 pic_similar
方法,可以获得两张图片的相似度,范围【0,1】
识别游戏状态
到了这一步,我们已经有了
- 预定义的游戏状态
- 比较两张图片之间相似度的方法
接下来就是实时获取游戏界面并与预定义的游戏状态进行比较,从而获得当前游戏状态
预定义的状态部分由各位自行定义了
class game_state():
def __init__(self,window_name,reccognise,resize_h,resize_w):
self.__env=window_capture(window_name,resize_h,resize_w)
self.select=[]
self.fail=[]
self.win=[]
self.menu=[]
self.ingame=[]
#识别区域
self.__reccognise_x=reccognise[0]
self.__reccognise_y=reccognise[1]
self.__reccognise_h=reccognise[2]
self.__reccognise_w=reccognise[3]
self.state_list=dict()
self.state_list['select']=self.select
self.state_list['ingame']=self.ingame
self.state_list['fail']=self.fail
self.state_list['menu']=self.menu
self.state_list['win']=self.win
def __get_state_simulate_score(self,arr1,arr2):
pic1=Image.fromarray(np.uint8(arr1))
pic2=Image.fromarray(np.uint8(arr2))
return = pic_similar(pic1,pic2)
def get_game_state(self):
game_state_pic=self.__env.capture_part(self.__reccognise_x,self.__reccognise_y,self.__reccognise_h,self.__reccognise_w)
score_dict=dict()
for i in self.state_list:
# print(i,self.state_list[i])
plt.imshow(self.state_list[i])
plt.show()
score_dict[i]=self.__get_state_simulate_score(game_state_pic,self.state_list[i])
max_score=max( score_dict.values())
for key in score_dict:
if score_dict[key]==max_score:
return key
return "PROCESSING"