【初學Python】關於python實現Cameo對視訊的擷取和錄製
阿新 • • 發佈:2018-12-12
學習《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()
最後完美實現。
程式碼永不停息...