From 91c05620f6eef8778b9311afbdfe8ec23ee1fe7e Mon Sep 17 00:00:00 2001 From: Théo de la Hogue Date: Wed, 24 Jan 2024 11:06:53 +0100 Subject: Using with statement to handle SharedObject locker. --- src/argaze/ArFeatures.py | 163 +++++++++++++-------------------- src/argaze/ArUcoMarkers/ArUcoCamera.py | 39 ++++---- src/argaze/DataFeatures.py | 5 + 3 files changed, 87 insertions(+), 120 deletions(-) (limited to 'src') diff --git a/src/argaze/ArFeatures.py b/src/argaze/ArFeatures.py index ff29baa..1b3e504 100644 --- a/src/argaze/ArFeatures.py +++ b/src/argaze/ArFeatures.py @@ -372,11 +372,8 @@ class ArLayer(DataFeatures.SharedObject, DataFeatures.PipelineStepObject): gaze_movement: gaze movement to project """ - # Use try block to always release the layer lock in finally block - try: - - # Lock layer exploitation - self.acquire() + # Use layer locker feature + with self.locker: # Update current gaze movement self.__gaze_movement = gaze_movement @@ -420,11 +417,6 @@ class ArLayer(DataFeatures.SharedObject, DataFeatures.PipelineStepObject): if self.aoi_scan_path is not None: self.aoi_scan_path.append_saccade(timestamp, gaze_movement) - - finally: - - # Unlock layer exploitation - self.release() def draw(self, image: numpy.array, draw_aoi_scene: dict = None, draw_aoi_matching: dict = None): """ @@ -440,21 +432,18 @@ class ArLayer(DataFeatures.SharedObject, DataFeatures.PipelineStepObject): return self.draw(image, **self.draw_parameters) - # Lock layer exploitation - self.acquire() - - # Draw aoi if required - if draw_aoi_scene is not None: + # Use layer locker feature + with self.locker: - self.aoi_scene.draw(image, **draw_aoi_scene) + # Draw aoi if required + if draw_aoi_scene is not None: - # Draw aoi matching if required - if draw_aoi_matching is not None and self.aoi_matcher is not None: + self.aoi_scene.draw(image, **draw_aoi_scene) - self.aoi_matcher.draw(image, self.aoi_scene, **draw_aoi_matching) + # Draw aoi matching if required + if draw_aoi_matching is not None and self.aoi_matcher is not None: - # Unlock layer exploitation - self.release() + self.aoi_matcher.draw(image, self.aoi_scene, **draw_aoi_matching) # Define default ArFrame image parameters DEFAULT_ARFRAME_IMAGE_PARAMETERS = { @@ -815,11 +804,8 @@ class ArFrame(DataFeatures.SharedObject, DataFeatures.PipelineStepObject): gaze_position: gaze position to project """ - # Use try block to always release the frame lock in finally block - try: - - # Lock frame exploitation - self.acquire() + # Use frame locker feature + with self.locker: # No gaze movement identified by default self.__identified_gaze_movement = GazeFeatures.UnvalidGazeMovement() @@ -891,11 +877,6 @@ class ArFrame(DataFeatures.SharedObject, DataFeatures.PipelineStepObject): layer.look(timestamp, self.__identified_gaze_movement) - finally: - - # Unlock frame exploitation - self.release() - def __image(self, background_weight: float = None, heatmap_weight: float = None, draw_gaze_position_calibrator: dict = None, draw_scan_path: dict = None, draw_layers: dict = None, draw_gaze_positions: dict = None, draw_fixations: dict = None, draw_saccades: dict = None) -> numpy.array: """ Get background image with overlaid visualisations. @@ -911,65 +892,62 @@ class ArFrame(DataFeatures.SharedObject, DataFeatures.PipelineStepObject): draw_saccades: [GazeFeatures.Saccade.draw](argaze.md/#argaze.GazeFeatures.Saccade.draw) parameters (if None, no saccade is drawn) """ - # Lock frame exploitation - self.acquire() + # Use frame locker feature + with self.locker: - # Draw background only - if background_weight is not None and (heatmap_weight is None or self.heatmap is None): + # Draw background only + if background_weight is not None and (heatmap_weight is None or self.heatmap is None): - image = self.background.copy() + image = self.background.copy() - # Draw mix background and heatmap if required - elif background_weight is not None and heatmap_weight is not None and self.heatmap: + # Draw mix background and heatmap if required + elif background_weight is not None and heatmap_weight is not None and self.heatmap: - background_image = self.background.copy() - heatmap_image = cv2.resize(self.heatmap.image, dsize=self.size, interpolation=cv2.INTER_LINEAR) - image = cv2.addWeighted(heatmap_image, heatmap_weight, background_image, background_weight, 0) + background_image = self.background.copy() + heatmap_image = cv2.resize(self.heatmap.image, dsize=self.size, interpolation=cv2.INTER_LINEAR) + image = cv2.addWeighted(heatmap_image, heatmap_weight, background_image, background_weight, 0) - # Draw heatmap only - elif background_weight is None and heatmap_weight is not None and self.heatmap: + # Draw heatmap only + elif background_weight is None and heatmap_weight is not None and self.heatmap: - image = cv2.resize(self.heatmap.image, dsize=self.size, interpolation=cv2.INTER_LINEAR) + image = cv2.resize(self.heatmap.image, dsize=self.size, interpolation=cv2.INTER_LINEAR) - # Draw black image - else: - - image = numpy.full((self.size[1], self.size[0], 3), 0).astype(numpy.uint8) + # Draw black image + else: - # Draw gaze position calibrator - if draw_gaze_position_calibrator is not None: + image = numpy.full((self.size[1], self.size[0], 3), 0).astype(numpy.uint8) - self.gaze_position_calibrator.draw(image, size=self.size, **draw_gaze_position_calibrator) + # Draw gaze position calibrator + if draw_gaze_position_calibrator is not None: - # Draw scan path if required - if draw_scan_path is not None and self.scan_path is not None: + self.gaze_position_calibrator.draw(image, size=self.size, **draw_gaze_position_calibrator) - self.scan_path.draw(image, **draw_scan_path) + # Draw scan path if required + if draw_scan_path is not None and self.scan_path is not None: - # Draw current fixation if required - if draw_fixations is not None and self.gaze_movement_identifier is not None: + self.scan_path.draw(image, **draw_scan_path) - self.gaze_movement_identifier.current_fixation.draw(image, **draw_fixations) + # Draw current fixation if required + if draw_fixations is not None and self.gaze_movement_identifier is not None: - # Draw current saccade if required - if draw_saccades is not None and self.gaze_movement_identifier is not None: + self.gaze_movement_identifier.current_fixation.draw(image, **draw_fixations) - self.gaze_movement_identifier.current_saccade.draw(image, **draw_saccades) + # Draw current saccade if required + if draw_saccades is not None and self.gaze_movement_identifier is not None: - # Draw layers if required - if draw_layers is not None: + self.gaze_movement_identifier.current_saccade.draw(image, **draw_saccades) - for layer_name, draw_layer in draw_layers.items(): + # Draw layers if required + if draw_layers is not None: - self.layers[layer_name].draw(image, **draw_layer) + for layer_name, draw_layer in draw_layers.items(): - # Draw current gaze position if required - if draw_gaze_positions is not None: + self.layers[layer_name].draw(image, **draw_layer) - self.__calibrated_gaze_position.draw(image, **draw_gaze_positions) + # Draw current gaze position if required + if draw_gaze_positions is not None: - # Unlock frame exploitation - self.release() + self.__calibrated_gaze_position.draw(image, **draw_gaze_positions) return image @@ -1370,11 +1348,8 @@ class ArCamera(ArFrame): # Project gaze position into camera frame super().look(timestamp, gaze_position) - # Use try block to always release the camera frame lock in finally block - try: - - # Lock camera frame exploitation - self.acquire() + # Use camera frame locker feature + with self.locker: # Project gaze position into each scene frames if possible for scene_frame in self.scene_frames: @@ -1402,11 +1377,6 @@ class ArCamera(ArFrame): pass - finally: - - # Unlock camera frame exploitation - self.release() - def map(self): """Project camera frame background into scene frames background. @@ -1414,32 +1384,29 @@ class ArCamera(ArFrame): watch method needs to be called first. """ - # Lock camera frame exploitation - self.acquire() - - # Project camera frame background into each scene frame if possible - for frame in self.scene_frames: + # Use camera frame locker feature + with self.locker: - # 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(): + # Project camera frame background into each scene frame if possible + for frame in self.scene_frames: - try: + # 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(): - aoi_2d = camera_layer.aoi_scene[frame.name] + try: - # 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 = cv2.warpPerspective(self.background, mapping, (width, height)) + aoi_2d = camera_layer.aoi_scene[frame.name] - # Ignore missing frame projection - except KeyError: + # 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 = cv2.warpPerspective(self.background, mapping, (width, height)) - pass + # Ignore missing frame projection + except KeyError: - # Unlock camera frame exploitation - self.release() + pass def to_json(self, json_filepath): """Save camera to .json file.""" diff --git a/src/argaze/ArUcoMarkers/ArUcoCamera.py b/src/argaze/ArUcoMarkers/ArUcoCamera.py index dcabd81..916c9ed 100644 --- a/src/argaze/ArUcoMarkers/ArUcoCamera.py +++ b/src/argaze/ArUcoMarkers/ArUcoCamera.py @@ -150,11 +150,8 @@ class ArUcoCamera(ArFeatures.ArCamera): This method timestamps camera frame and its layers. """ - # Use try block to always release the camera frame lock in finally block - try: - - # Lock camera frame exploitation - self.acquire() + # Use camera frame locker feature + with self.locker: # Detect aruco markers self.aruco_detector.detect_markers(image) @@ -201,13 +198,8 @@ class ArUcoCamera(ArFeatures.ArCamera): pass - finally: - - # Unlock camera frame exploitation - self.release() - - # Timestamp camera frame - self.timestamp = timestamp + # Timestamp camera frame + self.timestamp = timestamp def __image(self, draw_detected_markers: dict = None, draw_scenes: dict = None, draw_optic_parameters_grid: dict = None, **kwargs: dict) -> numpy.array: """Get frame image with ArUco detection visualisation. @@ -223,22 +215,25 @@ class ArUcoCamera(ArFeatures.ArCamera): # Note: don't lock/unlock camera frame here as super().image manage it. image = super().image(**kwargs) - # Draw optic parameters grid if required - if draw_optic_parameters_grid is not None: + # Use frame locker feature + with self.locker: + + # Draw optic parameters grid if required + if draw_optic_parameters_grid is not None: - self.aruco_detector.optic_parameters.draw(image, **draw_optic_parameters_grid) + self.aruco_detector.optic_parameters.draw(image, **draw_optic_parameters_grid) - # Draw scenes if required - if draw_scenes is not None: + # Draw scenes if required + if draw_scenes is not None: - for scene_name, draw_scenes_parameters in draw_scenes.items(): + for scene_name, draw_scenes_parameters in draw_scenes.items(): - self.scenes[scene_name].draw(image, **draw_scenes_parameters) + self.scenes[scene_name].draw(image, **draw_scenes_parameters) - # Draw detected markers if required - if draw_detected_markers is not None: + # Draw detected markers if required + if draw_detected_markers is not None: - self.aruco_detector.draw_detected_markers(image, draw_detected_markers) + self.aruco_detector.draw_detected_markers(image, draw_detected_markers) return image diff --git a/src/argaze/DataFeatures.py b/src/argaze/DataFeatures.py index 1e6abfe..4dfd911 100644 --- a/src/argaze/DataFeatures.py +++ b/src/argaze/DataFeatures.py @@ -368,12 +368,17 @@ class SharedObject(): self._execution_times = {} self._exceptions = {} + @property + def locker(self) -> threading.Lock: + return self._lock + def acquire(self): self._lock.acquire() def release(self): self._lock.release() + @property def locked(self) -> bool: return self._lock.locked() -- cgit v1.1