Subclassing managers.WindowManager

As discussed in Chapter 2, Handling Cameras, Files and GUIs, our object-oriented design allows us to easily swap OpenCV's HighGUI window manager for another window manager, such as Pygame. To do so, we just need to subclass our managers.WindowManager class and override four methods: createWindow(), show(), destroyWindow(), and processEvents(). Also, we need to import some new dependencies.

To proceed, we need the managers.py file from Chapter 2, Handling Cameras, Files, and GUIs and the utils.py file from Chapter 4, Tracking Faces with Haar Cascades. From utils.py, we only need one function, isGray(), which we implemented in Chapter 4, Tracking Faces with Haar Cascades. Let's edit managers.py to add the following imports:

import pygame
import utils

Also in managers.py, somewhere after our WindowManager implementation, we want to add our new subclass called PygameWindowManager:

class PygameWindowManager(WindowManager):
    def createWindow(self):
        pygame.display.init()
        pygame.display.set_caption(self._windowName)
        self._isWindowCreated = True
    def show(self, frame):
        # Find the frame's dimensions in (w, h) format.
        frameSize = frame.shape[1::-1]
        # Convert the frame to RGB, which Pygame requires.
        if utils.isGray(frame):
            conversionType = cv2.COLOR_GRAY2RGB
        else:
            conversionType = cv2.COLOR_BGR2RGB
        rgbFrame = cv2.cvtColor(frame, conversionType)
        # Convert the frame to Pygame's Surface type.
        pygameFrame = pygame.image.frombuffer(
            rgbFrame.tostring(), frameSize, 'RGB')
        # Resize the window to match the frame.
        displaySurface = pygame.display.set_mode(frameSize)
        # Blit and display the frame.
        displaySurface.blit(pygameFrame, (0, 0))
        pygame.display.flip()
    def destroyWindow(self):
        pygame.display.quit()
        self._isWindowCreated = False
    def processEvents(self):
        for event in pygame.event.get():
            if event.type == pygame.KEYDOWN and 
                    self.keypressCallback is not None:
                self.keypressCallback(event.key)
            elif event.type == pygame.QUIT:
                self.destroyWindow()
                return

Note that we are using two Pygame modules: pygame.display and pygame.event.

A window is created by calling pygame.display.init() and destroyed by calling pygame.display.quit(). Repeated calls to display.init() have no effect, as Pygame is intended for single-window applications only. The Pygame window has a drawing surface of type pygame.Surface. To get a reference to this Surface, we can call pygame.display.get_surface() or pygame.display.set_mode(). The latter function modifies the Surface entity's properties before returning it. A Surface entity has a blit() method, which takes, as arguments, another Surface and a coordinate pair where the latter Surface should be "blitted" (drawn) onto the first. When we are done updating the window's Surface for the current frame, we should display it by calling pygame.display.flip().

Events, such as keypresses, are polled by calling pygame.event.get(), which returns the list of all events that have occurred since the last call. Each event is of type pygame.event.Event and has the property type, which indicates the category of an event such as pygame.KEYDOWN for keypresses and pygame.QUIT for the window's Close button being clicked. Depending on the value of type, an Event entity may have other properties, such as key (an ASCII key code) for the KEYDOWN events.

Relative to the base WindowManager that uses HighGUI, PygameWindowManager incurs some overhead cost by converting between OpenCV's image format and Pygame's Surface format of each frame. However, PygameWindowManager offers normal window closing behavior, whereas the base WindowManager does not.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset