1. 程式人生 > >【初學Python】關於python實現Cameo對視訊的擷取和錄製

【初學Python】關於python實現Cameo對視訊的擷取和錄製

學習《OpenCV3計算機視覺,Python語言實現》時讀書筆記。

最近對計算機視覺產生了濃厚的興趣,又剛好在學校的圖書館看到了這本書,那可剛好滿足了我的興趣,今天先敲一個Cameo。

儲存圖片視訊時,直接通過當前日期進行儲存。

先建立一個manager.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  #裝飾器的用法具體瞭解可以參考這位小哥的部落格 
               #https://blog.csdn.net/u013205877/article/details/77804137
    def isWritingImage(self):
        # return self._imageFilename is not None 首先判斷self._imageFilename是否為None,若是,返回False,否則返回True
        # if self._imageFilename:
        #     return True
        # else:
        #     return False
        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
        # 計算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):
        """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 != -1:
            # Discard any non-ASCII info encoded by GTK.
            keycode &= 0xFF
            self.keypressCallback(keycode)

接下來建立cameo.py

import cv2
import datetime
from managers import WindowManager, CaptureManager

class Cameo(object):
    def __init__(self):
        # 建立一個視窗,並將鍵盤的回撥函式傳入
        self._windowManager = WindowManager('Video_Date', 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()
    # 定義鍵盤的回撥函式,用於self._windowManager.processEvents()的呼叫
    def onKeypress(self, keycode):
        '''
        快捷鍵設定:
        當按下“空格”鍵的時候,會進行抓屏。
        當按下‘tab’鍵的時候,就開始或者停止錄影。
        當然相應的目錄也會生成圖片或者視訊檔案
        '''
        s = datetime.datetime.now().strftime('%Y-%m-%d')
        if keycode == 32: # space
            # 截圖儲存的檔名字
            self._captureManager.writeImage(s + '.png')
        elif keycode == 9: # tab
            if not self._captureManager.isWritingVideo:
                # 告訴程式,錄影儲存的檔名字
                self._captureManager.startWritingVideo(s + '_DateVideo.avi')
            else:
                self._captureManager.stopWritingVideo()
        elif keycode == 27:  # escape
            self._windowManager.destroyWindow()

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

最後完美實現。

程式碼永不停息...