
2.2.5 捕捉摄像头帧
摄像头帧流也可以用VideoCapture对象来表示。但是,对于摄像头,我们通过传递摄像头设备索引(而不是视频文件名称)来构造VideoCapture对象。我们来考虑下面这个例子,它从摄像头抓取10秒的视频,并将其写入AVI文件。代码与2.2.4节的示例(从视频文件获取的,而不是从摄像头中获取的)类似,更改的内容标记为粗体:

对于某些系统上的一些摄像头,cameraCapture.get(cv2.CAP_PROP_FRAME_WIDTH)和cameraCapture.get(cv2.CAP_PROP_FRAME_HEIGHT)可能会返回不准确的结果。为了更加确定图像的实际大小,可以先抓取一帧,再用像h,w=frame.shape[:2]这样的代码来获得图像的高度和宽度。有时,你可能会遇到摄像头在开始产生大小稳定的好帧之前,产生一些大小不稳定的坏帧的情况。如果你关心的是如何防范这种情况,在开始捕捉会话时你可能想要读取并忽略一些帧。
可是,在大多数情况下,VideoCapture的get方法不会返回摄像头帧率的准确值,通常会返回0。http://docs.opencv.org/modules/highgui/doc/reading_and_writing_images_and_video.html上的官方文档警告如下:
当查询VideoCapture实例使用的后端不支持的属性时,返回值为0。
注意:
读/写属性涉及许多层。沿着这条链可能会发生一些意想不到的结果[sic]。
VideoCapture->API Backend->Operating System->DeviceDriver->Device Hardware
返回值可能与设备实际使用的值不同,也可能使用设备相关规则(例如,步长或者百分比)对其进行编码。有效的行为取决于[sic]设备驱动程序和API后端。
要为摄像头创建合适的VideoWriter类,我们必须对帧率做一个假设(就像前面代码中所做的那样),或者使用计时器测量帧率。后一种方法更好,我们将在本章后面对其进行介绍。
当然,摄像头数量及其顺序取决于系统。可是,OpenCV不提供任何查询摄像头数量或者摄像头属性的方法。如果用无效的索引构造VideoCapture类,VideoCapture类将不会产生任何帧,它的read方法将返回(False,None)。要避免试图从未正确打开的VideoCapture对象检索帧,你可能想先调用VideoCapture.isOpened方法,返回一个布尔值。
当我们需要同步一组摄像头或者多摄像头相机(如立体摄像机)时,read方法是不合适的。我们可以改用grab和retrieve方法。对于一组(两台)摄像机,可以使用类似于下面的代码:
