Python-OpenCV学习笔记(五)
使用managers.CaptureManager提取视频流CaptureManager类能对异性差异进行抽象,并提供了更加高级的接口从获取流中分配图像,再将图像分配到一个或多个输出中(如图像文件、视频文件或窗口)。在VideoCapture类中初始化CaptureManager类,在应用程序主循环的每一次迭代中通常应调用CaptureManager中的enterFrame()和exitFrame()函数。在调用enterFrame()和exitFrame()函数之间,应用程序可能会设定通道属性并获取帧属性。通道属性的初始值为0.只有在多台摄像头的情况下,通道属性的初始值非0,。帧属性是调用enterFrame()函数时与当前通道状态对应的图像。可能会经常调用CapTureManager类的writeImage(),startWritingVideo()和stopWritingVideo()函数。在调用exitFrame()函数之前,会有延迟写入文件。并且,在调用existFrame()函数过程中,帧属性可能会在窗口中显示,这取决于应用程序代码是将WindowManager类作为CaptureManager的构造函数参数还是设置previewWindowManager属性。如果应用程序代码处理了帧属性,那么在记录文件和窗口中会有所体现。CaptureManager类有一个称为shouldMirrorPreview的构造函数参数和属性,如果想要帧在窗口中镜像,但不记录在文件中,可将shouldMirrorPreciew设置为True。Opencv不能为摄像头提供准确的帧速率。解决这个问题的方法是通过帧计数器和Python标准的time.time()函数来估计帧数率。创建一个名为managers.py,该文件包含了CaptureM的实现,这各实现结果很长分成几段,先导入包、构造函数和属性: import cv2 import numpy import time class CaptureManager(object): def __init_(self,capture,previewWindowManager=None,shouldMirrorPreview=False): self.previewWindowManager=previewWindowManager self.shouldMirrorPreview=shouldMirrorPreview self._capture=capture self._channel=0 self._enteredFrame=False self._frame=None self._imageFilename=None self._videoFilename=None self._videoEncoding=None self._videoWriter=None self._startTime=None self._framesElapsed=numpy.long(0) self._fpsEstimate=None def channel(self): return self._channel def frame(self): if self._enteredFrame and self._frame is None: _,self._frame=self._capture.retyieve() return self._frame def isWritingImage(self): return self._imageFilename is not None def isWritingVideo(self): return self._videoFilename is not None 大多数成员变量为非公有变量,这类变量名前会加一个下划线进行标识。这些非公有变量与当前帧的状态以及文件写入操作有关。Python没有石油成员变量的概念,通常在变量前面加单/双下划线来表示私有变量。通常在Python中,以单下划线开始的成员变量称为保护变量,而异双下划线开始的变量称为私有成员变量。 def enterFrame(self): assert not self._enteredFrame if self._capture is not None: self._enteredFrame=self._capture.grab() def exitFrame(self): if self.frame is None: self._enteredFrame=False return if self._enteredFrame==0: self._startTime=time.time() else: timeElapsed=time.time()-self._startTime self._fpsEstimate=self._framesElapsed/timeElapsed self._framesElapsed+=1 if self.previewWindowManager is not None: if self.shouldMirrorPreview: mirroredFrame=numpy.fliplr(self._frame).copy() self.previewWindowManager.show(mirroredFrame) else: self.previewWindowManager.show(self._frame) if self.isWritingImage: cv2.imwrite(self._imageFilename,self._frame) self._imageFilename=None self._videoWriter() self._frame=None self._enteredFrame=False enterFrame()的实现只能(同步)获取一帧,而且会推出从一个通道获取,以便随后能从变量frame中读取。exitFrame()函数可以从当前通道获取图像、估计帧速率、通过窗口管理器显示图像,执行暂停的请求,从而向文件中写入图像。 def writeImage(self,fileneme): self._imageFilename=fileneme def startWritingVideo(self,filename,encoding=cv2.VideoWriter_fourcc('I','4','2','0')): self._videoFilename=filename self._videoEncoding=encoding def stopWritingVideo(self): self._videoFilename=None self._videoEncoding=None self._videoWriter=None def _writeVideoFrame(self): if not self.isWritingVideo: return if self._videoWriter is None: fps=self._capture.get(cv2.CAP_PROP_FPS) if fps==0.0: if self._framesElapsed<20: return else: fps=self._fpsEstimate size=(int(self._capture.get(cv2.CAP_PROP_FRAME_WIDTH)), int(self._capture.get(cv2.CAP_PROP_FRAME_HEIGHT))) self._videoWriter=cv2.VideoWriter( self._videoFilename,self._videoEncoding,fps,size ) self._videoWriter.write(self._frame) writeImage(),startWritingVideo()和stopWritingVideo()是公有函数,简单地记录了文件的写入操作参数,实际写入会推迟到下一下exitFrame()函数。