OpenCV3-Python摄像头实时图像
admin 于 2018年04月13日 发表在 计算机视觉
Cameo项目,使每一步都设计成该应用的一个组件(component),以使应用具有扩展性和重用性。项目实现视频播放、内容截图、关闭调用等功能。
1. 设计方法
创建CaptureManager类和WindowManager类作为高级的I/O流接口。在应用程序代码中可以使用CaptureManager来读取新的帧,并能将帧分配到一个或多个输出中,这些输出包括静止的图像文件、视频文件以及窗口(可通过WindowManager类来实现),WindowManager类使应用程序代码能以面向对象的形式处理窗口和事件。
备注:
Python没有私有成员变量的概念,通常在变量前面添加单/双下划线(_)来表示私有变量。通常在Python中,以单下划线开始的成员变量称为保护变量(即只有类对象和子类对象能访问这些变量),而以双下划线开始的变量称为私有成员变量(即只有类对象自己能访问,子类对象不能访问这个变量)
2. 实现源码
(1) managers.py内容:
#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Created on Sun Apr 1 10:18:20 2018 @author: lu """ 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 @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): """ capture the next frame """ assert not self._enteredFrame,'previous enterFrame() had no matching exitFrame()' if self._capture is not None: self._enteredFrame = self._capture.grab() def exitFrame(self): """ Draw to the window. Write to files. Release the frame""" #check whether any grabbed frame is retrievable if self.frame is None: self._enteredFrame = False return #update the FPS estimate and related variables if self._framesElapsed == 0: self._startTime = time.time() else: timeElapsed = time.time() - self._startTime self._fpsEstimate = self._framesElapsed / timeElapsed self._framesElapsed += 1 #draw to the window, if any. 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) #write to the image file, if any if self.isWritingImage: cv2.imwrite(self._imageFilename,self._frame) self._imageFilename = None #write to the video file, if any self._writeVideoFrame() #release the frame self._frame = None self._enteredFrame = False; def writeImage(self, filename): """write the next exited frame to an image file""" self._imageFilename = filename """stop writing exited frame to a video file""" def startWritingVideo(self, filename, encoding = cv2.VideoWriter_fourcc('I','4','2','0')): self._videoFilename = filename self._videoEncoding = encoding def stopWritingVideo(self): """stop writing exited frames to a video file """ 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: #the capture's FPS is unknow so use an estimate 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) 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 destroyWindow(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)
(2) main.py内容
import numpy as np import cv2 from managers import WindowManager, CaptureManager class Cameo(object): def __init__(self): self._windowManager = WindowManager('Camo', 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.frame self._captureManager.exitFrame() self._windowManager.processEvents() def onKeypress(self, keycode): """ space -> Take a screenshot tab -> start/stop recording a creencast escape -> quit """ if keycode == 32: #space self._captureManager.writeImage('screenshot.png') elif keycode == 9: #tab if not self._captureManager.isWritingVideo: self._captureManager.startWritingVideo('screencast.avi') else: self._captureManager.stopWritingVideo() elif keycode == 27: #escape self._windowManager.destroyWindow() if __name__=="__main__": Cameo().run()
3. 实现效果图: