原
基于Python的Cameo实现详解
以下内容为学习<OpenCV 3计算机视觉Python与原实现>(原书第2版)过程中,对编码的相关注释(菜鸟级).
同时参考了文章:Python 使用Opencv实现cameo功能,
该代码由managers.py,cameo.py两部分组成,运行cameo.py实现控制摄像头拍摄及录屏,截图的功能.
详细代码及注释如下:
managers.py
import cv2
import numpy as np
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#判断之前的窗口是否存在,默认为False
self._frame = None#当前帧的图像
self._imageFilename = None#图片名称,当截取图片时赋值,截取完毕后重新赋值None
self._videoFilename = None#视屏名称,当截取视屏时赋值,截取完毕后重新赋值None
self._videoEncoding = None#视频录制过程中赋值encoding,结束时赋值None
self._videoWriter = None#在视频录制时赋值cv2.VideoWriter作用,指定视频格式并进行frame的记录,录制结束后赋值None
self._startTime = None#计算fps的起始时间
self._framesElapsed = float(0)#视频共录制帧数
self._fpsEstimate = None#fps值
#设置只读属性
@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:#在已存在窗口且frame为空的情况下,使用retrieve()方法提取摄像头数据
#_enteredFrame为第一帧提取出的摄像头数据
_, 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,if any'''
#But first, check that any previous(之前的) frame was exited.
#assert:判断条件是否成立,成立继续运行程序,不成立返回提醒值,程序中断
#assert True,'提醒条件'
#assert false,'提醒条件'
#判断之前的窗口是否存在,若存在报错
#self._enteredFrame-->False
assert not self._enteredFrame,'previous enterFrame() had no matching exitFrame()'
if self._capture is not None:#判断是否存在控制器
self._enteredFrame = self._capture.grab()#capture = cv2.VideoCapture(0),返回True值
#self._enteredFrame -->True
#VideoCapure里的read是grab和retrieve的结合,由下面的函数介绍可知grab是指向下一个帧,retrieve是解码并返回一个
# 帧,而且retrieve比grab慢一些,所以当不需要当前的帧或画面时,可以使用grab跳过,与其使用read更省时间。
# 因为有的时候缓冲区的画面是存在了延迟的。当不需要的时候可以多grab之后再read的话,就能比一直read更省时间,
# 因为没有必要把不需要的帧解码,由介绍可知也可以使用grab实现硬件同步。
#视频显示,视频录制,视频保存的功能
def exitFrame(self):
'''Draw to the window. Write to files. Release(释放) the frame'''
#Check whether any grabbed frame is retrievable
#The getter may retrieve and cache the frame
print(4,' ',self._frame is None)
if self._frame is None:
self._enteredFrame = False#_enteredFrame为False时,为第一次抓取视屏信息,采用grab()方式
#为True时为非第一次抓取,采用retrieve方式抓取
return
#计算fps
#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 = np.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
#开始录制
def startWritingVideo(self, filename, encoding = cv2.VideoWriter_fourcc('I','4','2','0')):
'''Start writing exited frames to a video file.'''
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)#获取fps
if fps == 0.0:#如果未获取到fps
#The capture's FPS is unknown so use an estimate.
if self._framesElapsed<20:#如果现有帧数小于20,无法计算直接退出子程序
#Wait until more frames elapse so that the estimate is more stable
return
else:
fps = self._fpsEstimate
size = (int(self._capture.get(cv2.CAP_PROP_FRAME_WIDTH)),
int(self._capture.get(cv2.CAP_PROP_FRAME_HEIGHT)))
#创建videoWriter
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#在cameo.py中实例化为'Cameo'
self._isWindowCreated = False#控制是否循环提取摄像头信息
@property
def isWindowCreated(self):#作为窗口是否存在的判别条件,self._isWindowCreated在createWindow中已修改为True
return self._isWindowCreated
#创建窗口
def createWindow(self):
cv2.namedWindow(self._windowName)#创建视屏窗口
self._isWindowCreated = True#修改类属性,说明已经创建窗口,为Ture
#显示窗口
def show(self, frame):
cv2.imshow(self._windowName, frame)
#注销窗口
def destroyWindow(self):
cv2.destroyWindow(self._windowName)
self._isWindowCreated = False
#执行键盘操作的回调函数
def processEvent(self):
keycode = cv2.waitKey(1)#等待1微秒获取键盘输入信息
if self.keypressCallback is not None and keycode != -1:#如果编辑了外界设备输入程序且输入不为0
#Discard any non-ASCII info encoded by GTK
keycode &= 0xFF#使用GTK进行编码
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):
'''Run the main loop'''
self._windowManager.createWindow()#创建窗口,设置self._isWindowCreated = True控制循环提取摄像头信息
while self._windowManager.isWindowCreated:
#这里的enterFrame作用使得从程序从摄像头中取数据
self._captureManager.enterFrame()#开启窗口
#frame是原始帧数据,未做任何改动
frame = self._captureManager.frame#获得当前帧
#TODO: filter the frame(Chapter 3)
#exitFrame()主要功能:实现截屏,录屏
self._captureManager.exitFrame()#根据控制参数,选择是否进行截屏和录屏,并将self._frame等参数还原准备下一次循环
#回调函数
self._windowManager.processEvent()
def onKeypress(self, keycode):
'''Handle a keypress
space -> Take a screenshot
tab -> State/stop recording a screencast
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()
还能输入1000个字符
博文
博文
博文
博文
博文
博文
博文
博文
博文
博文
9篇文章
排名:千里之外
480篇文章
排名:3000+
33篇文章
排名:千里之外
55篇文章
排名:千里之外
博文
博文
博文
博文
博文
博文
博文
博文
博文
博文
博文
博文
博文
博文
博文
博文
博文
博文
博文
博文
博文
博文
博文
博文
博文
博文
博文
博文
博文
博文
博文
博文
博文
博文
博文
博文
博文
博文
博文
博文
博文
博文
博文
博文
博文
博文
博文
博文
博文
博文
博文
博文
博文
博文
博文
没有更多推荐了,