概要
在编写代码时,有时我们需要抓取屏幕的截图进行进一步的处理和分析。我尝试了Python中的两种不同方法来实现此功能,并进行了比较。
方法一:使用PIL库的ImageGrab.grab()方法
PIL(Python Imaging Library)库的ImageGrab模块提供了grab()方法来实现屏幕截图。以下是实现细节:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
|
import win32api
import win32con
import win32gui
import win32ui
import time
import matplotlib.pyplot as plt
from PIL import ImageGrab
class GameScreenshot:
def __init__(self, gamename="Setris"):
self.gamename = gamename
self.hwnd = self.get_game_handle()
self.window_rect = self.get_window_rect()
def is_game_top(self):
"""判断游戏是否处于顶部,返回布尔值"""
return win32gui.GetForegroundWindow() == self.hwnd if self.hwnd else False
def is_game_running(self):
"""判断游戏是否在运行,返回布尔值"""
return win32gui.IsWindow(self.hwnd) if self.hwnd else False
def get_game_handle(self):
"""获取游戏句柄,返回整数值"""
return win32gui.FindWindow(None, self.gamename) or 0
def get_window_rect(self):
"""获取游戏窗口的矩形坐标,返回一个四元组"""
if self.hwnd:
return win32gui.GetWindowRect(self.hwnd)
else:
return None
def get_game_img(self):
"""获取游戏截图,返回Image对象"""
if self.hwnd:
grab_image = ImageGrab.grab(self.window_rect)
return grab_image
return None
def get_game_img_in_top(self, timeout=3):
"""获取游戏截图,若游戏不在顶部则强制游戏处于顶部并返回Image对象"""
if self.hwnd:
start_time = time.time()
while not self.is_game_top():
if time.time() - start_time > timeout:
print("窗口置顶超时,跳过截图")
return None
win32gui.SetForegroundWindow(self.hwnd)
return self.get_game_img()
game = GameScreenshot()
if game.is_game_running():
print("游戏句柄:", game.hwnd)
if not game.is_game_top():
win32gui.SetForegroundWindow(game.hwnd)
# 计算抓取100次截图所需时间
start = time.time()
for _ in range(100):
img = game.get_game_img()
end = time.time()
print("截图时间:", end - start)
plt.imshow(img)
else:
print("游戏未运行")
|
输出结果为:
游戏句柄: 2229214
截图时间: 3.0059990882873535
方法二:使用PyQt5库抓取屏幕截图
另一种方法是利用PyQt5库来抓取屏幕截图,具体代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
import numpy as np
import time
from PyQt5 import QtWidgets
from PyQt5.QtGui import QPixmap, QImage
from PyQt5.QtWidgets import QApplication
import win32gui
class Pyqt5Catcher:
def __init__(self, window_title):
self.window_title = window_title
self.app = QApplication([])
self.hwnd = win32gui.FindWindow(None, window_title)
self.screen = QApplication.primaryScreen()
screenshot = self.screen.grabWindow(self.hwnd).toImage()
self.imgarr = np.empty((screenshot.height(), screenshot.width(), 4), dtype=np.uint8)
def catch(self):
screenshot = self.screen.grabWindow(self.hwnd).toImage()
ptr = screenshot.bits()
ptr.setsize(screenshot.height() * screenshot.bytesPerLine())
np.copyto(self.imgarr, np.frombuffer(ptr, np.uint8).reshape(screenshot.height(), screenshot.width(), 4))
return self.imgarr[..., :3]
catcher = Pyqt5Catcher('Setris')
start = time.time()
for i in range(100):
img = catcher.catch()
end = time.time()
print(end - start)
print(img.shape)
# show img with plt
import matplotlib.pyplot as plt
plt.imshow(img)
|
输出结果为:
0.025999784469604492
(144, 160, 3)
结果比较和总结
使用PIL库的ImageGrab.grab()方法抓取100次截图的时间约为3秒。而使用PyQt5库的时间仅为0.02秒。显然,PyQt5在性能上表现得更好。如果截图速度要求高,个人认为推荐使用PyQt5。但也要根据具体需求和情况进行选择。