1 - 引言
Python的应用程序可以通过面向对象的方法来实现,OpenCV提供了一个Cameo框架可以捕捉电脑的摄像头。我们可以通过编写添加框架里的类和方法来对摄像头捕捉到的画面进行图像处理和实验,是一个很好的学习方法,下面让我们来搭建一下这个Cameo框架
2 - 使用managers.CaptureManager提取视频流
无论图像来自视频文件还是摄像头,OpenCV都可以获取、显示和记录图像流,但是每种情况都有一些需要特殊考虑的地方。CaptureManager类对一些差异进行了抽象,并提供了更高级的接口从获取流中分配图像,再将图像分到一个或多个输出中(如图像文件、视频文件或窗口)
建立managers.py文件
# 使用managers.CaptureManager提取视频流
import numpy
import cv2
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 = int(0)
self._fpsEstimate = None
@property
def channel(self):
return self._channel
@channel.setter
def channel(self, value):
if self._channel != value:
self._channel = value
self._frame = None
@property
def frame(self):
if self._enteredFrame and self._frame is None:
_, self._frame = self._capture.retrieve()
return self._frame
@property
def isWritingImage(self):
return self._imageFilename is not None
@property
def isWritingVideo(self):
return self._videoFilename is not None
def enterFrame(self):
assert not self._enteredFrame, 'previous enterFrame() had no matching exitFram()'
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._framesElapsed == 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._writerVideoFrame()
self._frame = None
self._enteredFrame = False
def writeImage(self, filename):
self._imageFilename = filename
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 _writerVideoFrame(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)
# 使用managers.WindowManager抽象窗口和键盘
class WindowManager(object):
# 实现支持键盘事件
def __init__(self, windowName, keypressCallback = None):
self.keypressCallback = keypressCallback
self._windowName = windowName
self._isWindowCreated = False
@property
def isWindowCreated(self):
return self._isWindowCreated
def createWindow(self):
cv2.namedWindow(self._windowName)
self._isWindowCreated = True
def show(self, frame):
cv2.imshow(self._windowName, frame)
def destoryWindow(self):
cv2.destroyWindow(self._windowName)
self._isWindowCreated = False
def processEvents(self):
keycode = cv2.waitKey(1)
if self.keypressCallback is not None and keycode != -1:
keycode &= 0xFF
self.keypressCallback(keycode)
3 - 使用manager.WindowManager抽象窗口和键盘
对于一个应用程序,我们还需要能够实现人机交互,通过manager.WindowManager抽象窗口和键盘,我们可以通过键盘来实现人机交互
创建一个cameo.py文件
import cv2
from managers import WindowManager, CaptureManager
class Cameo(object):
def __init__(self):
self._windowManager = WindowManager('Cameo', self.onKeypress)
self._captureManager = CaptureManager(cv2.VideoCapture(0), self._windowManager, True)
def run(self):
self._windowManager.createWindow()
while self._windowManager.isWindowCreated:
self._captureManager.enterFrame()
frame = self._captureManager.enterFrame
self._captureManager.exitFrame()
self._windowManager.processEvents()
def onKeypress(self,keycode):
if keycode == 32: # space
self._captureManager.writeImage('cameo/screenshot.png')
elif keycode == 9: # tab
if not self._captureManager.isWritingVideo:
self._captureManager.startWritingVideo('cameo/screenshot.avi')
else:
self._captureManager.stopWritingVideo()
elif keycode == 27: # escape
self._windowManager.destoryWindow()
if __name__ == "__main__":
Cameo().run()
3 - 实现效果
至此,我们已经搭建好了一个Cameo最原始的框架,可以捕捉摄像头并且通过键盘实现截图和录制视频,在之后的学习中,我们会慢慢的扩充这个框架来学习图像处理的各种算法
按下空格键后保存摄像头捕捉到的图片
按下ESC退出