From f4914d604e8652b45fba4272ebabbeecce95595c Mon Sep 17 00:00:00 2001 From: Théo de la Hogue Date: Tue, 23 Apr 2024 11:21:33 +0200 Subject: Defining new abstract contexts for live and post processing. --- src/argaze/ArFeatures.py | 92 +++++++++++++++++++++++++++ src/argaze/utils/contexts/TobiiProGlasses2.py | 27 ++++++-- 2 files changed, 115 insertions(+), 4 deletions(-) diff --git a/src/argaze/ArFeatures.py b/src/argaze/ArFeatures.py index ab30e01..b77cd7f 100644 --- a/src/argaze/ArFeatures.py +++ b/src/argaze/ArFeatures.py @@ -1692,3 +1692,95 @@ class ArContext(DataFeatures.PipelineStepObject): """Resume pipeline processing.""" self._pause_event.clear() + + +class LiveProcessingContext(ArContext): + """ + Defines abstract live data processing context. + """ + + def calibrate(self): + """Launch device calibration process.""" + + raise NotImplementedError + + def calibration_status(self) -> str: + """Get device calibration status.""" + + raise NotImplementedError + + def start_recording(self): + """Start device data recording.""" + + raise NotImplementedError + + def stop_recording(self): + """Stop device data recording.""" + + raise NotImplementedError + + def pause_recording(self): + """Pause device data recording.""" + + raise NotImplementedError + + def cancel_recording(self): + """Cancel device data recording.""" + + raise NotImplementedError + + def recording_status(self) -> str: + """Get device recording status.""" + + raise NotImplementedError + +# Define default PostProcessingContext image parameters +DEFAULT_POST_PROCESSING_CONTEXT_IMAGE_PARAMETERS = { + "draw_progression": True +} + +class PostProcessingContext(ArContext): + """ + Defines abstract post data processing context. + """ + + @DataFeatures.PipelineStepInit + def __init__(self, **kwargs): + + super().__init__() + + self._image_parameters = {**DEFAULT_ARCONTEXT_IMAGE_PARAMETERS, **DEFAULT_POST_PROCESSING_CONTEXT_IMAGE_PARAMETERS} + + @property + def duration(self) -> int|float: + """Get data duration.""" + + raise NotImplementedError + + @property + def progression(self) -> float: + """Get data processing progression between 0 and 1.""" + + raise NotImplementedError + + @DataFeatures.PipelineStepImage + def image(self, draw_progression: bool = None, **kwargs): + """ + Get pipeline image with post processing information. + + Parameters: + draw_times: draw pipeline execution times + draw_exceptions: draw pipeline exception messages + """ + logging.debug('PostProcessingContext.image %s', self.name) + + image = super().image(**kwargs) + height, width, _ = image.shape + + if draw_progression: + + p = int(self.progression * width) + + cv2.rectangle(image, (0, 0), (p, 2), (255, 255, 255), -1) + + return image diff --git a/src/argaze/utils/contexts/TobiiProGlasses2.py b/src/argaze/utils/contexts/TobiiProGlasses2.py index 57668c6..4491c34 100644 --- a/src/argaze/utils/contexts/TobiiProGlasses2.py +++ b/src/argaze/utils/contexts/TobiiProGlasses2.py @@ -1124,19 +1124,21 @@ class LiveStream(ArFeatures.ArContext): json_data = self.__post_request('/api/system/conf/', data) -class PostProcessing(ArFeatures.ArContext): +class PostProcessing(ArFeatures.PostProcessingContext): @DataFeatures.PipelineStepInit def __init__(self, **kwargs): - # Init ArContext class + # Init parent class super().__init__() # Init private attributes self.__segment = None - self.__start = math.nan + self.__start = 0. self.__end = math.nan self.__parser = TobiiJsonDataParser() + self.__duration = 0. + self.__progression = 0. self.__data_counts_dict = { 'DirSig': 0, @@ -1249,6 +1251,9 @@ class PostProcessing(ArFeatures.ArContext): if self.start >= self.end: raise ValueError('Start reading timestamp is equal or greater than end reading timestamp.') + self.__duration = self.end - self.start + self.__progression = 0. + # TODO: log various info calibrated = bool(info["seg_calibrated"]) start_date = datetime.datetime.strptime(info["seg_t_start"], TOBII_DATETIME_FORMAT) @@ -1351,7 +1356,7 @@ class PostProcessing(ArFeatures.ArContext): # Catch inconstistent timestamps if self.__last_data_ts is not None: - if self.__data_ts - self.__last_data_ts <= 0: + if data_ts - self.__last_data_ts <= 0: logging.error('! %i gaze position more recent than the previous one', data_ts) @@ -1378,6 +1383,9 @@ class PostProcessing(ArFeatures.ArContext): # Process empty gaze position self._process_gaze_position(timestamp=data_ts) + # Update progression + self.__progression = (video_ts - self.start) / self.__duration + # Set stop event ourself self._stop_event.set() @@ -1484,3 +1492,14 @@ class PostProcessing(ArFeatures.ArContext): # Return millisecond timestamp, data object and type return ts * 1e-3, data_object, data_object_type + @property + def duration(self) -> int|float: + """Get data duration.""" + + return self.__duration + + @property + def progression(self) -> float: + """Get data processing progression between 0 and 1.""" + + return self.__progression \ No newline at end of file -- cgit v1.1