本文共 5430 字,大约阅读时间需要 18 分钟。
学习OpenCV一直是基于过程编程的方式,这种方法虽然直观,但容易让人感到繁琐。随着技术的发展,OpenCV逐渐引入面向对象的编程方式,这种方法提供了更加系统化和规范化的开发流程。
面向对象编程的优势显著体现在代码的可维护性和扩展性上。通过定义类和属性,我们可以更直观地管理摄像头资源和视频流处理,这种方式降低了代码的耦合度,使得程序更易于理解和改进。
下面以一个启动外部摄像头并处理视频流的例子来说明面向对象编程的优势。这个例子主要包括两个核心部分:视频流管理器和窗口管理器。
视频流管理器负责从摄像头中获取图像数据,并提供图像处理功能。窗口管理器则负责显示实时图像和处理用户输入事件。
以下是视频流管理器的实现代码:
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): 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 exitFrame()' 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) 窗口管理器负责处理窗口事件和显示图像:
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)
基于上述基础类,我们可以定义一个简单的摄像头控制类:
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.frame self._captureManager.exitFrame() self._windowManager.processEvents() def onKeypress(self, keycode): if keycode == 32: # 空格键 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() 通过上述代码示例可以看出,面向对象编程使得代码结构更加清晰,便于扩展和维护。通过定义CaptureManager和WindowManager类,我们可以更直观地管理摄像头资源和窗口显示,同时通过键盘事件处理实现了截图和录像功能。
这种编程方式不仅提高了代码的可读性,还为后续功能的开发提供了更好的基础。
转载地址:http://swpfk.baihongyu.com/