附录 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
子类来包装另一个库。