附录 A:与 Pygame 集成
本附录显示了如何在 OpenCV 应用中设置 Pygame 库以及如何使用 Pygame 进行窗口管理。 此外,附录还概述了 Pygame 的其他功能以及一些学习 Pygame 的资源。
注意
安装 Pygame
假设我们已经根据第 1 章,“设置 OpenCV”中描述的方法之一设置了 Python。 根据我们现有的设置,我们可以通过以下方式之一安装 Pygame:
- 带有 32 位 Python 的 Windows:从以下位置下载并安装 Pygame 1.9.1。
- 带有 64 位 Python 的 Windows:从以下位置下载并安装 Pygame 1.9.2 预览版。
-
带有 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 文件。
派生Manager.WindowManager
如第 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子类来包装另一个库。
