使用OPENCV 截取摄像头图片,录制视频(附详细注释)

基础类: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._framesElapsed = 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):
        try:
            # _enteredFrame 捕获到的视频帧
            # 返回一个图片
            if self._enteredFrame and self._frame is None:
                # retrieve 是视频捕获对象的一个方法,用于检索捕获到的视频帧。
                # self._frame 和 self._channel 是自定义的变量,可能用于存储检索到的帧和通道信息。
                _, self._frame = self._capture.retrieve(self._frame, self._channel)
                return self._frame
        except Exception as e:
            print("获取帧,发生异常"+e)



    @property
    def isWritingImage(self):
        return self._imageFilename is not None

    @property
    def isWritingVideo(self):
        return self._videoFilename is not None

    def enterFrame(self):
        #assert 是一个用于调试和测试的语句。它用于检查一个条件是否为真,如果条件为假,就会抛出一个 AssertionError 异常。
        #_enteredFrame =false 会进入条件
        assert not self._enteredFrame, print("Frame already entered")
        if self._capture is not None:
            #grab() 方法通常用于获取下一帧的视频数据
            self._enteredFrame = self._capture.grab()

    # exitFrame的实现从当前通道获取图像,估计帧率,通过窗口管理器(如果有的话)显示图像,并完成将图像写入文件的所有挂起请求。
    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)
                self.previewWindowManager.show(mirroredFrame)
            else:
                self.previewWindowManager.show(self._frame)

        if self.isWritingImage:
            cv2.imwrite(self._imageFilename, self._frame)
            self._imageFilename = None

        self._frame=None
        self._enteredFrame =None


    # 公共方法
    # 写图片写入视频,停止写入
    def writeImage(self, filename):
        self._imageFilename = filename

    def startWritingVideo(self,filename,encoding=cv2.VideoWriter.fourcc('M','J','P','G')):
        self._videoFilename = filename
        self._videoWriter = encoding

    def stopWritingVideo(self):
        self._videoWriter= None
        self._videoEncoding= None
        self._videoFilename= None

    def _writeVideoFrame(self):

        if not self.isWritingVideo:
            return False
        if self._videoWriter is not None:
            fps = self._capture.get(cv2.CAP_PROP_FPS)
            #获取不到FPS 使用推理
            if fps <= 0.0 :
                # 在帧率未知的情况下,我们在捕获会话开始时,跳过一些帧,这样就有时间构建帧率的估计。
                if self._framesElapsed < 20:
                    return
                else:
                    fps = self._fpsEstimate
                    #fps = 30
                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)













基础类:WindowsManager 

对窗口的操作,打开 显示 销毁等

import cv2

# 对窗口的所有操作 打开 显示 销毁 绑定事件
class WindowsManager(object):
    def __init__(self,windowsName,keypressCallbak=None):
        self.keypressCallbak = keypressCallbak
        self._windowsName = windowsName
        self._isWindowsCreated=False

    @property
    def isWindowsCreated(self):
        return self._isWindowsCreated

    @property
    def createWindow(self):
        cv2.namedWindow(self._windowsName)
        self._isWindowsCreated= True

    def show(self,frame):
        cv2.imshow(self._windowsName,frame)

    def destoryWindows(self):
        cv2.destroyWindow(self._windowsName)
        self._isWindowsCreated=False

    def processEvents(self):
        keycode=cv2.waitKey(1)
        if self.keypressCallbak is not None and keycode != -1:
            self.keypressCallbak(keycode)


 Main

from CaptureManager import *
from WindowsManager import *
import cv2
class cameo:
    def __init__(self):
        self._windowManager = WindowsManager("Capture", self.onKeypress)
        self._captureManager = CaptureManager(cv2.VideoCapture(0),self._windowManager,True)

    def run(self):
        self._windowManager.createWindow
        #设置窗口属性
        while self._windowManager.isWindowsCreated:
            #enterFrame的实现只(同步地)抓取一帧
            self._captureManager.enterFrame()
            #处理并返回帧
            frame = self._captureManager.frame

            if frame is not None:
                pass
            #exitFrame的实现从当前通道获取图像,估计帧率,通过窗口管理器(如果有的话)显示图像,并完成将图像写入文件的所有挂起请求。
            self._captureManager.exitFrame()
            #接收用户输入并且触发事件
            self._windowManager.processEvents()

    # 键盘事件
    # 控制 CaptureManager 写入图片,写入视频等
    # 控制 WindowsManager 关闭窗口
    def onKeypress(self,keycode):
        if keycode == 32: #空格
            self._captureManager.writeImage('Sce.png')
        elif keycode ==9:  #Tab
            if not self._captureManager.isWritingVideo:
                self._captureManager.startWritingVideo('Sce.avi')
        elif keycode == 27: #ESC
            self._windowManager.destoryWindows()
        else: #停止视频录制
            self._captureManager.stopWritingVideo()

if __name__== "__main__":
    cameo().run()


  • 5
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值