#Cameo项目(人脸跟着和图像处理)
#创建CaptureManager类和WindowManager类作为高级的I/O流接口。
#在应用程序中使用CaptureManager来读取新的帧,并能将帧分配到一个或多个输出中。
#这些输出包括静止的图像文件、视频文件以及窗口(在这里我们通过WindowManager类来实现)。
#WindowManager类使应用程序能以面向对象的形式处理窗口和事件。
#使用managers.CaptureManager提取视频流
#创建一个名为manager.py的文件,首先实现CaptureManager类:
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._frameElapsed = long(0)
self._fpsEstimate = None
#将get()和set()方法变成属性
@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
#实现enterFrame()和exitFrame()函数:
def enterFrame(self):
#捕获下一帧,但是,要先检测之前的帧是否已经退出。
assert not self._enteredFrame,'previous enterFrame() had no matching exitFrame()'
if self._capture is not None:
#捕获下一帧
self._enteredFrame = self._capture.grab()
def exitFrame(self):
if self.frame is None:
self._enteredFrame = False
return
#更新fps的估计值
if self._frameElapsed == 0:
self._startTime = time.time()
else:
timeElapsed = time.time() - self._startTime()
self._fpsEstimate = self._frameElapsed / timeElapsed
self._frameElapsed += 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._writeVideoFrame()
#释放
self._frame = None
self._enteredFrame = False
#注意,enterFrame()的实现只能(同步)获取一帧,而且会推迟从一个通道的获取,
#以便随后能从变量frame中读取。exitFrame()函数可以从当前通道获取图像、
#估计帧速率、通过窗口管理器显示图像。
def writeImage(self,filename):
#将下一帧写入文件filename
#用新的filename赋值给self._imageFilename即可
self._imageFilename = filename
def startWritingVideo(self,filename,
encoding = cv2.VideoWriter_fourcc('I','4','2','0')):
#同理给属性赋值即可
self._videoFilename = filename
self._videoEncoding = encoding
def stopWriterVideo(self):
#将相关的属性设置为None即可
self._videoFilename = None
self._videoEncoding = None
self._videoWriter = None
def _writeVideoFrame(self):
if not self.isWritingVideo:
return
if self._videoWriter is None:
#获取fps
fps = self._capture.get(cv2.CAP_PROP_FPS)
#如果获取fps失败
if fps == 0.0:
if self._frameElapsed < 20:
#等待更多的帧流,以便估计的更加稳定
return
else:
fps = self._fpsEstimate
#设置size
size = (int(self._capture.get(cv2.CAP_PROP_WIDTH)),
int(self._capture.get(cv2.CAP_PROP_HEIGHT)))
self._videoWriter = cv2.VideoWriter(self._videoFilename,
self._videoEncoding,
fps,size)
self._videoWriter.weite(self._frame)
#使用managers.WindowManager抽象窗口和键盘
#OpenCV提供了创建和销毁窗口、显示图像和处理事件的函数,这些函数
#不是窗口类的方法,只需要窗口名作为参数。
#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 createdWindow(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)
#cameo.Cameo的强大实现
#在managers.py所在的目录中,创建名为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.createdWindow()
while self._windowManager.isWindowCreated:
self._captureManager.enterFrame()
frame = self._captureManager.frame
self._captureManager.exitFrame()
self._windowManager.processEvents()
def onKeypress(self,keycode):
"""处理按键事件
空格 -> 截图
tab -> 开始/停止录制
esc -> 退出
"""
#空格
if keycode == 32:
self._captureManager.writeImage('screeshot.png')
#tab
elif keycode == 9:
if not self._captureManager.isWritingVideo:
self._captureManager.startWritingVideo('screencast.avi')
else:
self._captureManager.stopWriterVideo()
#esc
elif keycode == 27:
self._windowManager.destroyWindow()
if __name__ == "__main__":
Cameo().run()
#以上代码的功能是,根据键盘的按键,实现对摄像头的图像进行截图显示,或者录制。
#除了显示镜像,没有对摄像头的图像进行其他处理。
#下面我们,会慢慢添加对图像的其他处理,如边缘检测。