Managers.py
'''
通常在python中,以单下划线开始的成员变量称为保护变量(即只有类对象和子类对象才能访问这些变量)
而以双下划线开始的变量称为私有成员变量(即只有类对象自己能访问,子类对象不能访问这个变量)
'''
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:
ret,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,"先前的enterframe函数没有匹配的exitframe函数"
if self._capture is not None:
self._enteredFrame=self._capture.grab()
def exitFrame(self):
'''写入窗口,写入文件,释放帧'''
#检查是否任何grabbed的帧已经被retrievalable
#the getter may retrieve and cache the frame
if self.frame is None:
self._enteredFrame=False
return
#更新帧率(fps)估值和相关变量
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._writeVideoFrame()
#释放帧
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 _writeVideoFrame(self):
if not self.isWritingVideo:
return
if self._videoWriter is None:
fps=self._capture.get(cv2.CAP_PROP_FPS)
if fps==0.0:
#捕捉的帧率(fps)是未知的,所以使用了估计
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)
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.frame
#Todo 滤波该帧
self._captureManager.exitFrame()
self._windowManager.processEvents()
def onKeypress(self,keycode):
'''获取键盘动作
其中space空格键->截图
tab换行键->开启或停止录屏(screencast)
esc->退出'''
if keycode==32: #空格键
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:#esc键
self._windowManager.destroyWindow()
if __name__=='__main__':
cameo().run()
filters.py
import cv2
import numpy
import utils
def strokeEdge(src,dst,blurKsize=7,edgeKsize=5):
'''blurKsize参数会作为medianBlur()函数的ksize函数
edgeKsize参数会作为Laplacian()函数的ksize函数'''
if blurKsize>=3:
blurredSrc=cv2.medianBlur(src,blurKsize)#模糊函数
graySrc=cv2.cvtColor(blurredSrc,cv2.COLOR_BGR2GRAY)
else:
graySrc=cv2.cvtColor(src,cv2.COLOR_BGR2GRAY)
cv2.Laplacian(graySrc,cv2.CV_8U,graySrc,ksize=edgeKsize)
normalizedInverseAlpha=(1.0/255)*(255-graySrc)
channels=cv2.split(src)
for channel in channels:
channel[:]=channel*normalizedInverseAlpha
cv2.merge(channels,dst)
class VconvolutionFilter(object):
'''一个滤波效果,运用卷积到V(或者是所有的BGR)'''
def __init__(self,kernel):
self._kernel=kernel
def apply(self,src,dst):
'''运用该滤波使用bgr或者灰度图像'''
cv2.filter2D(src,-1,self._kernel,dst)
class SharpenFilter(VconvolutionFilter):
'''一像素半径的锐化滤波'''
def __init__(self):
kernel=numpy.array([[-1,-1,-1],
[-1,9,-1],
[-1,-1,-1]]) #权重加起来为1
VconvolutionFilter.__init__(self,kernel)
class FindEdgesFilter(VconvolutionFilter):
'''一像素半径的 边缘寻找滤波'''
def __init__(self):
kernel=numpy.array([[-1,-1,-1],
[-1,8,-1],
[-1,-1,-1]]) #权重加起来为0