class ThreadedEngine(object):
    def __init__(self, source, engine):
        self.source = source
        self.engine = engine
        self.thread_manager = ThreadManager(self)
        self.pred = None

    def __next__(self):
        return self.get_prediction()

    def _thread(self):
        predictions = self.inference_gen()
        for prediction in predictions:
            self.pred = prediction
            self.thread_manager.set()

    def inference_gen(self):
        while True:
            self.frame = next(self.source)
            yield self.engine.invoke(self.frame)

    def get_prediction(self):
        self.thread_manager.wait()
        return self.pred, self.frame

    def get_max_length(self):
        return self.engine.get_max_length()

    def label(self, pred):
        return self.engine.label(pred)

    def start(self):
        self.thread_manager.start()
Example #2
0
class BaseCamera(object):
    ''' Base class for streaming video in a background thread.

    This class continuously pulls new images in a thread. When a separate thread calls the 
    get() function to retrieve a frame, the ThreadManager blocks until a new frame comes in
    and then returns a frame to all listeners. This ensures that no duplicate frames are retreived.

    Attributes:
        source (str): The file path of the video source.
            For example, this could be "/dev/video0". Run v4l2-ctl --list-devices to find your device.
        resolution (tuple[int]): Stores the camera resolution.
        frame (array[int]): Stores the current frame.
        thread_manager: A separate class that handles incoming requests for frames. 

    '''
    def __init__(self, source, resolution):
        ''' Sets the video source and creates the thread manager.

        Args:
            source (str): The file path of the video stream.
            resolution (tuple[int]): The camera resolution. 

        '''

        self.source = source
        self.resolution = resolution
        self.frame = None  # current frame is stored here by background thread

        self.thread_manager = ThreadManager(self)

    def __iter__(self):
        ''' Returns itself as an iterator.

        Since the class is structured around generators, there is no need for a separate 
        iterator.

        '''

        return self

    def __next__(self):
        ''' Returns the newest frame.

        This operator allows the class usage to be abstracted. The user can call next(source), and 
        the source can be any video stream that implements this operator.

        Returns: The newest frame.

        '''

        return self.get_frame()

    def _thread(self):
        ''' Continuously pulls new frames from the camera.

        An infinite generator is used to pull new frames. Once a new frame is pulled,
        the thread manager is set, notifying all listeners and handing them the new frame.
        If there have been no listeners for 10 seconds, then the thread stops.

        '''

        frames_iterator = self.frames()
        for frame in frames_iterator:
            self.frame = frame

            # Send signal to listeners
            self.thread_manager.set()

            # if there haven't been any listeners asking for frames in
            # the last 10 seconds then stop the thread
            if self.thread_manager.time_lapsed() > 10:
                frames_iterator.close()
                print('Stopping camera thread due to inactivity.')
                break

        self.thread_manager.stop()

    def start(self):
        ''' Starts the streaming thread.
        '''

        self.thread_manager.start()

    def get_frame(self):
        ''' Waits for a new frame and returns it.
        '''

        self.thread_manager.wait()
        return self.frame

    def get_resolution(self):
        ''' Returns the camera resolution.
        '''

        return self.resolution

    @abstractmethod
    def frames(self):
        ''' Generator that continuously yields frames.

        This method must be implemented by child classes. It should be an infinite while loop
        that yields new camera frames.

        Yields: The newest camera frame.

        '''

        pass