大型生存类游戏自动代玩人工智能[2] -- 屏幕截取
使用Python中的PIL库截取屏幕
当需要获取电脑屏幕的信息时,往往需要进行屏幕截取操作。而万能的python就有非常方便快捷的方法来截取屏幕,就是用python中的图像处理库Pillow (PIL)来完成。安装PIL库的具体操作详见官方文档。
安装好PIL库以后我们最快只需两步就可以进行屏幕截取:
1.首先导入PIL库中的ImageGrab
模块
from PIL import ImageGrab
2.然后就可以用ImageGrab
模块来直接截取屏幕了
screenshot = ImageGrab.grab()
返回的screenshot
变量就是全屏图像。
如果想要指定位置的截屏,可以输入bbox
参数:
x=20
y=60
width=1024
height=576
screenshot = ImageGrab.grab(bbox=(x,y,width,height))
返回的screenshot
变量就是 左上角顶点坐标(20,60) 宽1024 高576 的屏幕图像。
想要使用OpenCV来显示图像以及进行更多的图像处理,非常必要的操作是将screenshot
转成numpy数组:
import numpy as np
screenshot_array = np.array(ImageGrab.grab(bbox=(x,y,width,height)))
转换后的screenshot_array
就是一个numpy数组,可以使用OpenCV来显示图像:
import cv2
cv2.imshow('screenshot',screenshot_array)
cv2.waitKey(0)
cv2.destroyAllWindows()
(python版OpenCV的安装详见官方文档,推荐使用Anaconda来安装)
但是显示出来的图片有RGB颜色错乱的问题,应该是转换成numpy数组时导致的,所以要得到正常的图像需要用OpenCV进行一次RGB颜色通道转换:
screenshot_array = cv2.cvtColor(screenshot_array, cv2.COLOR_BGR2RGB)
最后得到的screenshot_array
就是正常颜色的numpy数组了。
实时屏幕监控
我们的游戏代玩程序需要不断获取游戏截屏来监控游戏的状态,所以最简单的方法就是无限循环地截屏,加一个while True
死循环即可:
while True:
image_array = np.array(ImageGrab.grab(bbox=(x,y,width,height)))
image_array = cv2.cvtColor(image_array, cv2.COLOR_BGR2RGB)
cv2.imshow('screen monitoring',image_array)
if cv2.waitKey(25) & 0xFF == ord('q'):
cv2.destroyAllWindows()
break
由于PIL库的运行效率问题,这种方法的屏幕监控只能做到 10FPS 左右,更快的方法是用win32gui
库来截屏(详见这里)。不过每秒10帧的速度对于我们这个程序来说够用了,所以就不用繁琐的win32gui
来截屏了,不过下面我们还是会用到win32gui
来帮助我们截取指定窗口的屏幕信息。
用win32gui获取指定窗口位置
很多时候我们想要截屏的窗口不是全屏的,所以这个窗口有可能存在桌面的任意位置而且窗口大小也不固定。所以稳妥起见,我们需要获取我们想要截屏的窗口的位置和大小(即窗口的bbox
)。这里如果是windows系统(Mac和Linux的方法请自行查询)我们可以用到另外一个库win32gui
来实现,安装方法详见官方文档。
首先导入win32gui
库中的FindWindow
和GetWindowRect
两个模块:
from win32gui import FindWindow, GetWindowRect
然后用FindWindow
模块来获取目标窗口的程序id号,通过输入窗口名字(窗口名字可以在桌面下方的任务栏查看),这里我们的目标窗口是游戏的模拟器:
window_name = "明日之后 - MuMu模拟器"
id = FindWindow(None, window_name)
得到id号以后就可以通过GetWindowRect
来获取目标窗口的bbox
了:
bbox = GetWindowRect(id)
拿到了目标窗口的bbox
以后,只需输入到之前的ImageGrab
参数中就可以实时监视你想要的窗口了,从头到尾完整代码如下:
# coding=gbk
import numpy as np
import cv2
from PIL import ImageGrab
from win32gui import FindWindow, GetWindowRect
while True:
window_name = "明日之后 - MuMu模拟器"
id = FindWindow(None, window_name)
bbox = GetWindowRect(id)
image_array = np.array(ImageGrab.grab(bbox=bbox))
image_array = cv2.cvtColor(image_array, cv2.COLOR_BGR2RGB)
cv2.imshow('screenshot',image_array)
if cv2.waitKey(25) & 0xFF == ord('q'):
cv2.destroyAllWindows()
break
需要注意的是目标窗口必须要在打开状态并且在桌面的最上层,如果窗口处于最小化或者被其他窗口覆盖的话是无法通过这个方法获取截屏的
还有代码中的# coding=gbk
一定不能少,这个是python中的中文编码来识别"明日之后 - MuMu模拟器"
这些中文字符的
可以看到无论游戏窗口在屏幕的哪个位置都可以准确定位到。