pygame编程入门之五:Camera Module Introduction
作者: Nirav Patel(nrp@eclecti.cc)
翻译: 杨晓宏(561071777@qq.com)
Pygame 1.9支持摄像头接口,允许你捕捉静态图像,观看实时流,并做一些简单的计算机视觉。本教程将介绍所有这些用例,提供您可以基于应用程序或游戏的代码示例。您可以参考完整的API的参考文档。
注意,在Pygame 1.9中,相机模块为在Linux上使用v4l2的相机提供了本机支持。通过可视设备或OpenCV支持其他平台,但本指南将重点介绍本机模块。大多数代码对于其他平台都是有效的,但是某些诸如控件之类的东西是行不通的。该模块也被标记为实验性的,这意味着API在后续版本中可能会发生变化。
#Import and Init
import pygame
import pygame.camera
from pygame.locals import *
pygame.init()
pygame.camera.init()
由于相机模块是可选的,所以需要像上面所示的那样手动导入和初始化。
捕捉单个图像
现在我们来看看最简单的例子,打开相机,捕捉一个框架作为一个表面。在下面的例子中,我们假设在计算机上有一个/dev/video0的摄像头,并将其初始化为640到480。被称为图像的表面是当getimage()被调用时所看到的任何东西。
cam = pygame.camera.Camera("/dev/video0",(640,480))
cam.start()
image = cam.get_image()
列出连接摄像头
你可能会想,如果不知道相机的确切路径呢?我们可以要求模块提供一个安装在计算机上的相机列表,并初始化列表中的第一个摄像头。
camlist = pygame.camera.list_cameras()
if camlist:
cam = pygame.caemra.Camera(camlist[0],(640,480))
Using Camera Controls
大多数相机都支持控制,比如翻转图像和改变亮度。 set_controls() and get_controls() 可以在 using start()之后的任何地方使用。
cam.set_controls(hflip = True, vflip = False)
print camera.get_controls()
捕捉实时流
本教程的其余部分将基于捕捉实时的图像流。为此,我们将使用下面的类。正如所描述的,它将简单地将一个持续的摄像头帧流到屏幕上,有效地显示实时视频。它基本上就是您所期望的,循环getimage(),到显示表面,然后翻转它。出于性能方面的原因,我们将每次使用为相机提供相同的表面。
class Capture(object):
def __init__(self):
self.size = (640,480)
# create a display surface. standard pygame stuff
self.display = pygame.display.set_mode(self.size, 0)
# this is the same as what we saw before
self.clist = pygame.camera.list_cameras()
if not self.clist:
raise ValueError("Sorry, no cameras detected.")
self.cam = pygame.camera.Camera(self.clist[0], self.size)
self.cam.start()
# create a surface to capture to. for performance purposes
# bit depth is the same as that of the display surface.
self.snapshot = pygame.surface.Surface(self.size, 0, self.display)
def get_and_flip(self):
# if you don't want to tie the framerate to the camera, you can check
# if the camera has an image ready. note that while this works
# on most cameras, some will never return true.
if self.cam.query_image():
self.snapshot = self.cam.get_image(self.snapshot)
# blit it to the display surface. simple!
self.display.blit(self.snapshot, (0,0))
pygame.display.flip()
def main(self):
going = True
while going:
events = pygame.event.get()
for e in events:
if e.type == QUIT or (e.type == KEYDOWN and e.key == K_ESCAPE):
# close the camera safely
self.cam.stop()
going = False
self.get_and_flip()
由于 get_image()是一个阻塞调用,它可能在慢的摄像头上花费相当多的时间,这个例子使用 query_image() 来查看相机是否已经准备好了。这可以让你把游戏的framerate和你的相机分开。如果您发现您的相机不支持queryimage()函数,那么也可以让相机在单独的线程中捕获图像,从而获得大致相同的性能收益。
基本的计算机视觉
通过使用相机、转换和掩码模块,pygame可以做一些基本的计算机视觉。
颜色空间
在初始化相机时,colorspace是一个可选参数,它有“RGB”、“YUV”和“HSV”作为可能的选择。YUV和HSV通常对计算机视觉比RGB更有用,并且允许你更容易通过颜色来调整阈值,我们将在后面的教程中看到。
self.cam = pygame.camera.Camera(self.clist[0], self.size, "RGB")
../_images/camera_rgb.jpg
self.cam = pygame.camera.Camera(self.clist[0], self.size, "YUV")
../_images/camera_yuv.jpg
self.cam = pygame.camera.Camera(self.clist[0], self.size, "HSV")
../_images/camera_hsv.jpg
Thresholding
从转换模块中使用 threshold()函数,您可以做简单的绿色屏幕效果,或者在场景中隔离特定颜色的物体。在下面的例子中,我们只需要将绿色的树排除在外,使其余的图像变成黑色。检查参考文档,了解阈值函数的详细信息。
self.thresholded = pygame.surface.Surface(self.size, 0, self.display)
self.snapshot = self.cam.get_image(self.snapshot)
pygame.transform.threshold(self.thresholded,self.snapshot,(0,255,0),(90,170,170),(0,0,0),2)
当然,只有当您已经知道您要寻找的对象的确切颜色时,这才有用。
为了解决这个问题,让阈值在现实世界中可用,需要添加一个校准阶段,在这个阶段识别对象的颜色并使用它来进行阈值设置。
使用transform模块的 average_color() 函数来完成这项工作。
下面是一个校准函数例子,你可以循环,直到像按键一样的事件,以及类似。盒子里的颜色将会是这个threshold颜色。
请注意,在下面的图像中使用HSV彩色空间。
def calibrate(self):
# capture the image
self.snapshot = self.cam.get_image(self.snapshot)
# blit it to the display surface
self.display.blit(self.snapshot, (0,0))
# make a rect in the middle of the screen
crect = pygame.draw.rect(self.display, (255,0,0), (145,105,30,30), 4)
# get the average color of the area inside the rect
self.ccolor = pygame.transform.average_color(self.snapshot, crect)
# fill the upper left corner with that color
self.display.fill(self.ccolor, (0,0,50,50))
pygame.display.flip()
pygame.transform.threshold(self.thresholded,self.snapshot,self.ccolor,(30,30,30),(0,0,0),2)
你可以用同样的方法做一个简单的绿色屏幕/蓝色屏幕,首先得到一个背景图像,然后对它进行阈值处理。
下面的例子只是把相机对准了HSV彩色空间的空白白色墙壁。
def calibrate(self):
# capture a bunch of background images
bg = []
for i in range(0,5):
bg.append(self.cam.get_image(self.background))
# average them down to one to get rid of some noise
pygame.transform.average_surfaces(bg,self.background)
# blit it to the display surface
self.display.blit(self.background, (0,0))
pygame.display.flip()
pygame.transform.threshold(self.thresholded,self.snapshot,(0,255,0),(30,30,30),(0,0,0),1,self.background)
使用掩模模块
如果你只是想要显示图像,上面的东西是很棒的,但是使用蒙版模块,你也可以使用摄像头作为游戏的输入设备。例如,回到阈值的例子中,我们可以找到那个对象的位置,并使用它来控制屏幕上的对象。
def get_and_flip(self):
self.snapshot = self.cam.get_image(self.snapshot)
# threshold against the color we got before
mask = pygame.mask.from_threshold(self.snapshot, self.ccolor, (30, 30, 30))
self.display.blit(self.snapshot,(0,0))
# keep only the largest blob of that color
connected = mask.connected_component()
# make sure the blob is big enough that it isn't just noise
if mask.count() > 100:
# find the center of the blob
coord = mask.centroid()
# draw a circle with size variable on the size of the blob
pygame.draw.circle(self.display, (0,255,0), coord, max(min(50,mask.count()/400),5))
pygame.display.flip()
这是最基本的例子。
你可以追踪多个不同颜色的斑点,找到物体的轮廓,在现实生活中和在游戏对象之间进行碰撞检测,获得一个物体的角度,以获得更好的控制,等等。玩得开心!