aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/argaze/ArFeatures.py163
-rw-r--r--src/argaze/ArUcoMarkers/ArUcoCamera.py39
-rw-r--r--src/argaze/DataFeatures.py5
3 files changed, 87 insertions, 120 deletions
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()