学习到openCV部分的视频流提取,按照书上的教程逐步实现,最后发现书上面代码和结构都有编写问题。通过论坛上面看了别人的实现方式,最终实现了视频流的录制以及截图功能的实现。
先放两张图:
图1 截图功能实现
图2 录制的视屏文件,正常打开(清晰流畅,此处仅放个截图了)。
使用设备:普通杰瑞微通摄像头USB,接口cv2.VideoCapture(1),python3.7
论坛上的代码多少有些小问题,直接使用就输出不了图像,常见问题差不多都是调用的时候少个下划线,开头缩进不正确等。
本代码分为两部分第一部分为managers.py,第二部分为主函数cameo.py。
详细代码如下:
第一部分:managers.py
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 = float(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 exitFrame()'
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._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) #获取fps
if fps == 0.0: #未获取到ps
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(1),self._windowManager,True)
def run(self):
self._windowManager.createWindow()
while self._windowManager.isWindowCreated:
self._captureManager.enterFrame()
frame = self._captureManager.frame
if frame is not None:
pass
self._captureManager.exitFrame()
self._windowManager.processEvents()
def onKeypress(self,keycode):
if keycode == 32: #space键,截屏
print("截图成功!")
self._captureManager.writeImage('screenshot.png')
elif keycode == 9: #tab 判断开始录制还是结束
if not self._captureManager.isWritingVideo:
print("开始录制!")
self._captureManager.startWritingVideo("screencast.avi")
else:
print("录制结束!")
self._captureManager.stopWritingVideo()
elif keycode == 27: #ESc键退出
print("退出!")
self._windowManager.destroyWindow()
if __name__ == "__main__":
Cameo().run()