1. 程式人生 > >數字影象處理筆記(一):利用OpenCV的Cameo框架搭建實驗環境

數字影象處理筆記(一):利用OpenCV的Cameo框架搭建實驗環境

1 - 引言

Python的應用程式可以通過面向物件的方法來實現,OpenCV提供了一個Cameo框架可以捕捉電腦的攝像頭。我們可以通過編寫新增框架裡的類和方法來對攝像頭捕捉到的畫面進行影象處理和實驗,是一個很好的學習方法,下面讓我們來搭建一下這個Cameo框架

2 - 使用managers.CaptureManager提取視訊流

無論影象來自視訊檔案還是攝像頭,OpenCV都可以獲取、顯示和記錄影象流,但是每種情況都有一些需要特殊考慮的地方。CaptureManager類對一些差異進行了抽象,並提供了更高階的介面從獲取流中分配影象,再將影象分到一個或多個輸出中(如影象檔案、視訊檔案或視窗)

建立managers.py檔案

# 使用managers.CaptureManager提取視訊流
import numpy
import cv2
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 = int(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):
        assert not self._enteredFrame, 'previous enterFrame() had no matching exitFram()'
        if self._capture is not None:
            self._enteredFrame = self._capture.grab()

    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).copy()
                self.previewWindowManager.show(mirroredFrame)
            else:
                self.previewWindowManager.show(self._frame)
        if self.isWritingImage:
            cv2.imwrite(self._imageFilename, self._frame)
            self._imageFilename = None
        self._writerVideoFrame()
        self._frame = None
        self._enteredFrame = False

    def writeImage(self, filename):
        self._imageFilename = filename

    def startWritingVideo(self, filename, encoding=cv2.VideoWriter_fourcc('I', '4', '2', '0')):
        self._videoFilename = filename
        self._videoEncoding = encoding

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

    def _writerVideoFrame(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)

# 使用managers.WindowManager抽象視窗和鍵盤
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 destoryWindow(self):
        cv2.destroyWindow(self._windowName)
        self._isWindowCreated = False
    def processEvents(self):
        keycode = cv2.waitKey(1)
        if self.keypressCallback is not None and keycode != -1:
            keycode &= 0xFF
            self.keypressCallback(keycode)

3 - 使用manager.WindowManager抽象視窗和鍵盤

對於一個應用程式,我們還需要能夠實現人機互動,通過manager.WindowManager抽象視窗和鍵盤,我們可以通過鍵盤來實現人機互動
建立一個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):
        self._windowManager.createWindow()
        while self._windowManager.isWindowCreated:
            self._captureManager.enterFrame()
            frame = self._captureManager.enterFrame
            self._captureManager.exitFrame()
            self._windowManager.processEvents()
    def onKeypress(self,keycode):
        if keycode == 32:  # space
            self._captureManager.writeImage('cameo/screenshot.png')
        elif keycode == 9:  # tab
            if not self._captureManager.isWritingVideo:
                self._captureManager.startWritingVideo('cameo/screenshot.avi')
            else:
                self._captureManager.stopWritingVideo()
        elif keycode == 27:    # escape
            self._windowManager.destoryWindow()
if __name__ == "__main__":
    Cameo().run()

3 - 實現效果

至此,我們已經搭建好了一個Cameo最原始的框架,可以捕捉攝像頭並且通過鍵盤實現截圖和錄製視訊,在之後的學習中,我們會慢慢的擴充這個框架來學習影象處理的各種演算法

在這裡插入圖片描述

按下空格鍵後儲存攝像頭捕捉到的圖片
在這裡插入圖片描述
按下ESC退出