From db4c1466c70e69de8d19cb4b01dd1f31bfc36978 Mon Sep 17 00:00:00 2001 From: Théo de la Hogue Date: Wed, 26 Jun 2024 09:18:50 +0200 Subject: Adding a way to enable/disable the copy of the camera background into scenes frames. --- src/argaze/ArFeatures.py | 104 ++++++++++++++++------------------ src/argaze/ArUcoMarker/ArUcoCamera.py | 5 ++ 2 files changed, 55 insertions(+), 54 deletions(-) diff --git a/src/argaze/ArFeatures.py b/src/argaze/ArFeatures.py index 3888503..38d1759 100644 --- a/src/argaze/ArFeatures.py +++ b/src/argaze/ArFeatures.py @@ -1102,6 +1102,7 @@ class ArCamera(ArFrame): self.__projection_cache_writer = None self.__projection_cache_reader = None self.__projection_cache_data = None + self.__copy_background_into_scenes_frames = False # Init protected attributes self._scenes = {} @@ -1289,6 +1290,54 @@ class ArCamera(ArFrame): return True + @property + def copy_background_into_scenes_frames(self) -> bool: + """Enable/disable camera frame background copy into scene frames background.""" + return self.__copy_background_into_scenes_frames + + @copy_background_into_scenes_frames.setter + @DataFeatures.PipelineStepAttributeSetter + def copy_background_into_scenes_frames(self, project: bool) -> bool: + + self.__copy_background_into_scenes_frames = project + + def _copy_background_into_scenes_frames(self): + """Copy camera frame background into scene frames background. + + !!! warning + This method have to be called once AOI have been projected into camera frame layers. + + !!! note + This method makes each frame to send an 'on_copy_background_into_scenes_frames' signal to their observers. + """ + + # Project camera frame background into each scene frame if possible + for frame in self.scene_frames(): + + # Clear frame background + frame.background = DataFeatures.TimestampedImage(numpy.full((frame.size[1], frame.size[0], 3), 0).astype(numpy.uint8), timestamp=self.background.timestamp) + + # Is there an AOI inside camera frame layers projection which its name equals to a scene frame name? + for camera_layer_name, camera_layer in self.layers.items(): + + try: + + aoi_2d = camera_layer.aoi_scene[frame.name] + + # Apply perspective transform algorithm to fill aoi frame background + width, height = frame.size + destination = numpy.float32([[0, 0], [width, 0], [width, height], [0, height]]) + mapping = cv2.getPerspectiveTransform(aoi_2d.astype(numpy.float32), destination) + frame.background = DataFeatures.TimestampedImage(cv2.warpPerspective(self.background, mapping, (width, height)), timestamp=self.background.timestamp) + + # Ignore missing frame projection + except KeyError: + + pass + + # Notify frame's 'on_copy_background_into_scenes_frames' signal observers + frame.send_signal('copy_background_into_scenes_frames', timestamp=self.background.timestamp) + def scene_frames(self) -> Iterator[ArFrame]: """Iterate over all scenes frames""" @@ -1444,44 +1493,6 @@ class ArCamera(ArFrame): except KeyError: pass - @DataFeatures.PipelineStepMethod - @DataFeatures.PipelineStepExecutionTime - def map(self): - """Project camera frame background into scene frames background. - - !!! warning - watch method needs to be called first. - """ - - # Use camera frame lock feature - with self._lock: - - # Project camera frame background into each scene frame if possible - for frame in self.scene_frames(): - - # Clear frame background - frame.background = DataFeatures.TimestampedImage(numpy.full((frame.size[1], frame.size[0], 3), 0).astype(numpy.uint8), timestamp=self.background.timestamp) - - # Is there an AOI inside camera frame layers projection which its name equals to a scene frame name? - for camera_layer_name, camera_layer in self.layers.items(): - - try: - - aoi_2d = camera_layer.aoi_scene[frame.name] - - # Apply perspective transform algorithm to fill aoi frame background - width, height = frame.size - destination = numpy.float32([[0, 0], [width, 0], [width, height], [0, height]]) - mapping = cv2.getPerspectiveTransform(aoi_2d.astype(numpy.float32), destination) - frame.background = DataFeatures.TimestampedImage(cv2.warpPerspective(self.background, mapping, (width, height)), timestamp=self.background.timestamp) - - # Ignore missing frame projection - except KeyError: - - pass - - # Notify frame's 'on_map' signal observers - frame.send_signal('map', timestamp=self.background.timestamp) # Define default ArContext image parameters DEFAULT_ARCONTEXT_IMAGE_PARAMETERS = { @@ -1601,22 +1612,7 @@ class ArContext(DataFeatures.PipelineStepObject): logging.warning('%s._process_camera_image: %s', DataFeatures.get_class_path(self), e) self.__exceptions.append(e) - - ''' - # TODO: make map step optional - try: - - logging.debug('\t> map image (%i x %i)', width, height) - - self.__pipeline.map(timestamp=timestamp) - - except DataFeatures.TimestampedException as e: - - logging.warning('%s._process_camera_image: %s', DataFeatures.get_class_path(self), e) - - self.__exceptions.append(e) - ''' - + else: raise (TypeError('Pipeline is not ArCamera instance.')) diff --git a/src/argaze/ArUcoMarker/ArUcoCamera.py b/src/argaze/ArUcoMarker/ArUcoCamera.py index 34ad57a..8ae8cb8 100644 --- a/src/argaze/ArUcoMarker/ArUcoCamera.py +++ b/src/argaze/ArUcoMarker/ArUcoCamera.py @@ -196,6 +196,11 @@ class ArUcoCamera(ArFeatures.ArCamera): # Raise exception raise e + # Copy camera frame background into scene frames background if required + if self.copy_background_into_scenes_frames: + + self._copy_background_into_scenes_frames() + @DataFeatures.PipelineStepImage @DataFeatures.PipelineStepExecutionTime def image(self, draw_detected_markers: dict = None, draw_scenes: dict = None, -- cgit v1.1