From d93c046febc7c82cce72936648a5a6359c79c1d4 Mon Sep 17 00:00:00 2001 From: Théo de la Hogue Date: Wed, 17 Apr 2024 08:08:35 +0200 Subject: Allowing to pause/resume pipeline processing. --- src/argaze/ArFeatures.py | 21 ++++++++++++++++ src/argaze/__main__.py | 25 +++++++++++++++++-- src/argaze/utils/contexts/TobiiProGlasses2.py | 35 ++++++++++++++++++++++++--- 3 files changed, 76 insertions(+), 5 deletions(-) diff --git a/src/argaze/ArFeatures.py b/src/argaze/ArFeatures.py index a37a4d3..0b51f9f 100644 --- a/src/argaze/ArFeatures.py +++ b/src/argaze/ArFeatures.py @@ -1154,11 +1154,15 @@ class ArCamera(ArFrame): self.__projection_cache_writer = UtilsFeatures.FileWriter(path=self.__projection_cache) self.__projection_cache_reader = None + logging.info('ArCamera %s writes projection into %s', self.name, self.__projection_cache) + # The file exist: read projection from the cache else: self.__projection_cache_writer = None self.__projection_cache_reader = UtilsFeatures.FileReader(path=self.__projection_cache) + + logging.info('ArCamera %s reads projection from %s', self.name, self.__projection_cache) def _clear_projection(self): """Clear layers projection.""" @@ -1670,3 +1674,20 @@ class ArContext(DataFeatures.PipelineStepObject): cv2.putText(image, f'error: {e}', (20, height - (i + 1) * 50 + 25), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 1, cv2.LINE_AA) return image + + @DataFeatures.PipelineStepMethod + def pause(self): + """Pause pipeline processing.""" + + raise NotImplementedError('pause() method not implemented') + + def is_paused(self) -> bool: + """Is pipeline processing paused?""" + + raise NotImplementedError('is_paused() method not implemented') + + @DataFeatures.PipelineStepMethod + def resume(self): + """Resume pipeline processing.""" + + raise NotImplementedError('resume() method not implemented') diff --git a/src/argaze/__main__.py b/src/argaze/__main__.py index c80657e..96fda23 100644 --- a/src/argaze/__main__.py +++ b/src/argaze/__main__.py @@ -18,6 +18,7 @@ __license__ = "GPLv3" import argparse import logging +import json import contextlib from . import load @@ -28,8 +29,7 @@ import cv2 # Manage arguments parser = argparse.ArgumentParser(description=__doc__.split('-')[0]) parser.add_argument('context_file', metavar='CONTEXT_FILE', type=str, help='JSON context filepath') -parser.add_argument('-v', '--verbose', action='store_true', default=False, - help='enable verbose mode to print information in console') +parser.add_argument('-v', '--verbose', action='store_true', default=False, help='enable verbose mode to print information in console') args = parser.parse_args() @@ -41,9 +41,11 @@ with load(args.context_file) as context: # Loaded object must be a subclass of ArContext if not issubclass(type(context), ArContext): + raise TypeError('Loaded object is not a subclass of ArContext') if args.verbose: + print(context) # Create a window to display context @@ -62,6 +64,7 @@ with load(args.context_file) as context: if issubclass(type(context.pipeline), ArCamera): for scene_frame in context.pipeline.scene_frames(): + cv2.imshow(scene_frame.name, scene_frame.image()) # Key interaction @@ -69,7 +72,25 @@ with load(args.context_file) as context: # Esc: close window if key_pressed == 27: + raise KeyboardInterrupt() + # Space bar: pause/resume pipeline processing + if key_pressed == 32: + + try: + + if context.is_paused(): + + context.resume() + + else: + + context.pause() + + except NotImplementedError: + + pass + # Stop frame display cv2.destroyAllWindows() diff --git a/src/argaze/utils/contexts/TobiiProGlasses2.py b/src/argaze/utils/contexts/TobiiProGlasses2.py index 4cf88f0..b46ebd9 100644 --- a/src/argaze/utils/contexts/TobiiProGlasses2.py +++ b/src/argaze/utils/contexts/TobiiProGlasses2.py @@ -1259,6 +1259,9 @@ class PostProcessing(ArFeatures.ArContext): # Create stop event self.__stop_event = threading.Event() + # Create pause event + self.__pause_event = threading.Event() + # Open reading thread self.__reading_thread = threading.Thread(target=self.__read) @@ -1281,15 +1284,24 @@ class PostProcessing(ArFeatures.ArContext): for video_ts, video_image, data_list in self: + # Check pause event (and stop event) + while self.__pause_event.is_set() and not self.__stop_event.is_set(): + + logging.debug('> reading is paused at %i', video_ts) + + self._process_camera_image(timestamp=video_ts, image=video_image) + + time.sleep(1) + + # Check stop event if self.__stop_event.is_set(): + break logging.debug('> read image at %i timestamp', video_ts) # Process camera image - self._process_camera_image( - timestamp=video_ts, - image=video_image) + self._process_camera_image(timestamp=video_ts, image=video_image) height, width, _ = video_image.shape @@ -1457,3 +1469,20 @@ class PostProcessing(ArFeatures.ArContext): # Return millisecond timestamp, data object and type return ts * 1e-3, data_object, data_object_type + + @DataFeatures.PipelineStepMethod + def pause(self): + """Pause pipeline processing.""" + + self.__pause_event.set() + + def is_paused(self) -> bool: + """Is pipeline processing paused?""" + + return self.__pause_event.is_set() + + @DataFeatures.PipelineStepMethod + def resume(self): + """Resume pipeline processing.""" + + self.__pause_event.clear() \ No newline at end of file -- cgit v1.1