将摄像头数据显示在窗口中并具有录像、截屏功能

复习

先前写过两个读取摄像头数据的小Demo复习内容:
OpenCV获取摄像头数据并显示在窗口里 Python实现
从摄像头中读取数据并写入文件

Cameo

这次是一个功能更加强大的Demo不仅仅是将摄像头获取的视频数据显示在窗口中,而且还可以通过快捷键来实现截屏、保存视频数据。
首先我们先来看看Cameo的主程序:

# -- coding: utf-8 --

import cv2
import os

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()
        while self._windowManager.isWindowCreated:
            '''这里的enterFrame就是告诉程序从摄像头中取数据'''
            self._captureManager.enterFrame()

            '''下面的这个frame是原始帧数据,这里没有做任何修改,后面的教程会对这个帧数据进行修改'''
            frame = self._captureManager._frame
            '''exitFrame看起来是像是退出的意思,其实主要功能都是在这里方法里实现的,截屏、录像都是在这里'''
            self._captureManager.exitFrame()
            self._windowManager.processEvents()

    def onKeypress(self, keycode):
        '''
        快捷键设置:
        当按下“空格”键的时候,会进行抓屏。
        当按下‘tab’键的时候,就开始或者停止录像。
        当然相应的目录也会生成图片或者视频文件
        '''

        if keycode == 32:#space
            '''告诉程序,截屏保存的文件名字'''
            self._captureManager.writeImage('changeOnePixel.png')
        elif keycode == 9:#tab
            if not self._captureManager.isWritingVideo:
                '''告诉程序,录像保存的文件名字'''
                self._captureManager.startWritingVideo('record.avi')
            else:
                self._captureManager.stopWritingVideo()
        elif keycode == 27: #escape
            self._windowManager.destroyWindow()


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

功能类的实现

# -- coding: utf-8 --
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 = 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:
            _, 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"""
        assert not self._enteredFrame, \
        'previous enterFrame() had no mathcing exitFrame'
        if self._capture is not None:
            self._enteredFrame = self._capture.grab()

    '''程序里最复杂的就是这方法了,担负了视频显示、视频视频录制、截屏保存的功能。'''
    def exitFrame (self):
        """Draw to the window. Write to files. Release the frame"""
        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):
        """Wirte the next exited frame to an image file."""
        self._imageFilename = filename

    def startWritingVideo(self, filename, encodeing = cv2.VideoWriter_fourcc('I', '4', '2', '0')):
        """Start wirting exited frames to a video file."""
        self._videoFilename = filename
        self._videoEncoding = encodeing

    def stopWritingVideo(self):
        """Stop writing eited frames to a video file."""
        self._videoFilename = None
        self._videoEncodding = 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:
                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 != 255:
            #Discard any non-ASCII info encoded by GTK.
            keycode &= 0xFF
            self.keypressCallback(keycode)
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值