附录 A:集成 Pygame
本附录显示了如何在 OpenCV 应用中设置 Pygame 库以及如何使用 Pygame 进行窗口管理。 此外,附录还概述了 Pygame 的其他功能以及一些学习 Pygame 的资源。
注意
安装 Pygame
假设我们已经根据第 1 章,“设置 OpenCV”中描述的方法之一设置了 Python。 根据我们现有的设置,我们可以通过以下方式之一安装 Pygame:
- 带有 32 位 Python 的 Windows:从这个页面下载并安装 Pygame 1.9.1。
- 带有 64 位 Python 的 Windows:从这个页面。
-
带有 Macports 的 Mac:打开终端并运行以下命令:
```py $ sudo port install py27-game
```
-
带有 Homebrew 的 Mac:打开终端并运行以下命令来安装 Pygame 的依赖项,然后安装 Pygame 本身:
```py $ brew install sdl sdl_image sdl_mixer sdl_ttf smpeg portmidi $ /usr/local/share/python/pip install \
hg+http://bitbucket.org/pygame/pygame
```
-
Ubuntu 及其衍生版本:打开终端并运行以下命令:
```py $ sudo apt-get install python-pygame
```
-
其他类似 Unix 的系统:Pygame 在许多系统的标准存储库中可用。 典型的包装名称包括
pygame
,pygame27
,py-game
,py27-game
,python-pygame,
和python27-pygame
。
现在,Pygame 应该可以使用了。
文档和教程
Pygame 的 API 文档和一些教程可以在这个页面上在线找到。
Al Sweigart 的《使用 Python 和 Pygame 制作游戏》是一本烹饪手册,用于在 Pygame 1.9.1 中重新创建几个经典游戏。 可在这个页面上在线获得免费的电子版本,或在这个页面上下载 PDF 文件。 。
派生管理器
如第 2 章,“处理相机,文件和 GUI”中所述,我们的面向对象设计使我们可以轻松地将 OpenCV 的 HighGUI 窗口管理器替换为另一个窗口管理器,例如 Pygame 。 为此,我们只需要将managers.WindowManager
类子类化,并覆盖四种方法:createWindow()
,show()
,destroyWindow()
和processEvents()
。 另外,我们需要导入一些新的依赖项。
要继续,我们需要第 2 章,“处理摄像机,文件和 GUI”的managers.py
文件和第 4 章“使用 Haar 级联跟踪人脸”的utils.py
文件。 从utils.py
中,我们只需要一个函数isGray()
,我们在第 4 章“用 Haar 级联跟踪人脸”中实现了该函数。 让我们编辑managers.py
以添加以下导入:
import pygame
import utils
同样在managers.py
中,在实现WindowManager
之后的某个地方,我们想添加一个名为PygameWindowManager
的新子类:
class PygameWindowManager(WindowManager):
def createWindow(self):
pygame.display.init()
pygame.display.set_caption(self._windowName)
self._isWindowCreated = True
def show(self, frame):
# Find the frame's dimensions in (w, h) format.
frameSize = frame.shape[1::-1]
# Convert the frame to RGB, which Pygame requires.
if utils.isGray(frame):
conversionType = cv2.COLOR_GRAY2RGB
else:
conversionType = cv2.COLOR_BGR2RGB
rgbFrame = cv2.cvtColor(frame, conversionType)
# Convert the frame to Pygame's Surface type.
pygameFrame = pygame.image.frombuffer(
rgbFrame.tostring(), frameSize, 'RGB')
# Resize the window to match the frame.
displaySurface = pygame.display.set_mode(frameSize)
# Blit and display the frame.
displaySurface.blit(pygameFrame, (0, 0))
pygame.display.flip()
def destroyWindow(self):
pygame.display.quit()
self._isWindowCreated = False
def processEvents(self):
for event in pygame.event.get():
if event.type == pygame.KEYDOWN and \
self.keypressCallback is not None:
self.keypressCallback(event.key)
elif event.type == pygame.QUIT:
self.destroyWindow()
return
请注意,我们正在使用两个 Pygame 模块:pygame.display
和pygame.event
。
通过调用pygame.display.init()
创建窗口,并通过调用pygame.display.quit()
销毁窗口。 重复调用display.init()
不起作用,因为 Pygame 仅适用于单窗口应用。 Pygame 窗口具有pygame.Surface
类型的绘图表面。 要获得对此Surface
的引用,我们可以调用pygame.display.get_surface()
或pygame.display.set_mode()
。 后一个函数在返回Surface
实体的属性之前对其进行修改。 Surface
实体具有blit()
方法,即,该方法将另一个Surface
和一个坐标对作为参数,其中后一个Surface
应该被“涂抹”(绘制)到第一个坐标上。 完成当前帧的窗口Surface
的更新后,我们应调用pygame.display.flip()
来显示它。
通过调用pygame.event.get()
来轮询诸如keypresses
之类的事件,该事件将返回自上次调用以来发生的所有事件的列表。 每个事件的类型均为pygame.event.Event
,并具有type
属性,该属性指示事件的类别,例如,单击的pygame.KEYDOWN
和单击窗口的关闭按钮的pygame.QUIT
。 根据type
的值,Event
实体可能具有其他属性,例如KEYDOWN
事件的key
(ASCII 键代码)。
相对于使用 HighGUI 的基础WindowManager
,PygameWindowManager
通过在每帧 OpenCV 的图像格式和 Pygame 的Surface
格式之间进行转换会产生一些间接费用。 但是,PygameWindowManager
提供正常的窗口关闭行为,而基本的WindowManager
不提供。
修改应用
让我们将cameo.py
文件修改为使用PygameWindowManager
而不是WindowManager
。 在cameo.py
中找到以下行:
from managers import WindowManager, CaptureManager
替换为:
from managers import PygameWindowManager as WindowManager, \
CaptureManager
就这样! 现在,cameo.py
使用一个 Pygame 窗口,当单击标准关闭按钮时,该窗口应该关闭。
Pygame 的进一步使用
我们仅使用了pygame.display
和pygame.event
模块的一些基本功能。 Pygame 提供了更多功能,包括:
- 绘制 2D 几何
- 绘制文字
- 管理可绘制 AI 实体(精灵)的组
- 捕获与窗口,键盘,鼠标和操纵杆/游戏手柄相关的各种输入事件
- 创建自定义事件
- 播放和合成声音和音乐
例如,Pygame 可能是适合使用计算机视觉的游戏的后端,而 HighGUI 则不是。
总结
到现在为止,我们应该有一个应用,该应用使用 OpenCV 捕获(并可能操纵)图像,同时使用 Pygame 显示图像和捕获事件。 从这个基本的集成示例开始,您可能想要扩展PygameWindowManager
以包装其他 Pygame 功能,或者您可能想要创建另一个WindowManager
子类来包装另一个库。