aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/argaze/ArFeatures.py28
-rw-r--r--src/argaze/ArUcoMarkers/ArUcoCamera.py20
-rw-r--r--src/argaze/ArUcoMarkers/ArUcoMarkersGroup.py95
-rw-r--r--src/argaze/ArUcoMarkers/ArUcoScene.py18
-rw-r--r--src/argaze/GazeFeatures.py4
-rw-r--r--src/argaze/utils/demo_data/demo_aruco_markers_setup.json4
-rw-r--r--src/argaze/utils/demo_data/demo_gaze_analysis_setup.json5
7 files changed, 106 insertions, 68 deletions
diff --git a/src/argaze/ArFeatures.py b/src/argaze/ArFeatures.py
index b9a29de..96976c2 100644
--- a/src/argaze/ArFeatures.py
+++ b/src/argaze/ArFeatures.py
@@ -510,7 +510,7 @@ DEFAULT_ARFRAME_IMAGE_PARAMETERS = {
},
"deepness": 0
},
- "draw_gaze_position": {
+ "draw_gaze_positions": {
"color": (0, 255, 255),
"size": 2
}
@@ -976,7 +976,7 @@ class ArFrame():
# Return look data
return identified_gaze_movement, scan_step_analysis, layer_analysis, execution_times, exception
- def __image(self, background_weight: float = None, heatmap_weight: float = None, draw_scan_path: dict = None, draw_layers: dict = None, draw_gaze_position: dict = None) -> numpy.array:
+ def __image(self, background_weight: float = None, heatmap_weight: float = 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.
@@ -985,7 +985,9 @@ class ArFrame():
heatmap_weight: weight of heatmap overlay
draw_scan_path: [GazeFeatures.ScanPath.draw](argaze.md/#argaze.GazeFeatures.ScanPath.draw) parameters (if None, no scan path is drawn)
draw_layers: dictionary of [ArLayer.draw](argaze.md/#argaze.ArFeatures.ArLayer.draw) parameters per layer (if None, no layer is drawn)
- draw_gaze_position: [GazeFeatures.GazePosition.draw](argaze.md/#argaze.GazeFeatures.GazePosition.draw) parameters (if None, no gaze position is drawn)
+ draw_gaze_positions: [GazeFeatures.GazePosition.draw](argaze.md/#argaze.GazeFeatures.GazePosition.draw) parameters (if None, no gaze position is drawn)
+ draw_fixations: [GazeFeatures.Fixation.draw](argaze.md/#argaze.GazeFeatures.Fixation.draw) parameters (if None, no fixation is drawn)
+ draw_saccades: [GazeFeatures.Saccade.draw](argaze.md/#argaze.GazeFeatures.Saccade.draw) parameters (if None, no saccade is drawn)
"""
# Lock frame exploitation
@@ -1025,10 +1027,20 @@ class ArFrame():
self.layers[layer_name].draw(image, **draw_layer)
+ # Draw current fixation if required
+ if draw_fixations is not None and self.gaze_movement_identifier is not None:
+
+ self.gaze_movement_identifier.current_fixation.draw(image, **draw_fixations)
+
+ # Draw current saccade if required
+ if draw_saccades is not None and self.gaze_movement_identifier is not None:
+
+ self.gaze_movement_identifier.current_saccade.draw(image, **draw_saccades)
+
# Draw current gaze position if required
- if draw_gaze_position is not None:
+ if draw_gaze_positions is not None:
- self.__gaze_position.draw(image, **draw_gaze_position)
+ self.__gaze_position.draw(image, **draw_gaze_positions)
# Unlock frame exploitation
self.__look_lock.release()
@@ -1280,15 +1292,15 @@ class ArScene():
# Project layer aoi scene
yield name, aoi_scene_copy.project(tvec, rvec, self.parent.aruco_detector.optic_parameters.K)
- def draw_axis(self, image: numpy.array):
+ def draw(self, image: numpy.array, **kwargs):
"""
- Draw scene axis into image.
+ Draw scene into image.
Parameters:
image: where to draw
"""
- raise NotImplementedError('draw_axis() method not implemented')
+ raise NotImplementedError('draw() method not implemented')
@dataclass
class ArCamera(ArFrame):
diff --git a/src/argaze/ArUcoMarkers/ArUcoCamera.py b/src/argaze/ArUcoMarkers/ArUcoCamera.py
index b067666..4f555fb 100644
--- a/src/argaze/ArUcoMarkers/ArUcoCamera.py
+++ b/src/argaze/ArUcoMarkers/ArUcoCamera.py
@@ -211,11 +211,12 @@ class ArUcoCamera(ArFeatures.ArCamera):
# Return dection time and exceptions
return detection_time, exceptions
- def __image(self, draw_detected_markers: dict = None, draw_optic_parameters_grid: dict = None, **kwargs) -> numpy.array:
+ def __image(self, draw_detected_markers: dict = None, draw_scenes: dict = None, draw_optic_parameters_grid: dict = None, **kwargs) -> numpy.array:
"""Get frame image with ArUco detection visualisation.
Parameters:
draw_detected_markers: ArucoMarker.draw parameters (if None, no marker drawn)
+ draw_scenes: ArUcoScene.draw parameters (if None, no scene drawn)
draw_optic_parameters_grid: OpticParameter.draw parameters (if None, no grid drawn)
kwargs: ArCamera.image parameters
"""
@@ -230,16 +231,23 @@ class ArUcoCamera(ArFeatures.ArCamera):
# Get camera frame image
image = super().image(**kwargs)
- # Draw detected markers if required
- if draw_detected_markers is not None:
-
- self.aruco_detector.draw_detected_markers(image, draw_detected_markers)
-
# 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)
+ # Draw scenes if required
+ if draw_scenes is not None:
+
+ for scene_name, draw_scenes_parameters in draw_scenes.items():
+
+ self.scenes[scene_name].draw(image, **draw_scenes_parameters)
+
+ # Draw detected markers if required
+ if draw_detected_markers is not None:
+
+ self.aruco_detector.draw_detected_markers(image, draw_detected_markers)
+
# Unlock camera frame exploitation
self._frame_lock.release()
diff --git a/src/argaze/ArUcoMarkers/ArUcoMarkersGroup.py b/src/argaze/ArUcoMarkers/ArUcoMarkersGroup.py
index bdcf70c..5b6c69d 100644
--- a/src/argaze/ArUcoMarkers/ArUcoMarkersGroup.py
+++ b/src/argaze/ArUcoMarkers/ArUcoMarkersGroup.py
@@ -617,40 +617,26 @@ class ArUcoMarkersGroup():
self._rotation = rmat
- def draw_axis(self, image: numpy.array, K, D, consistency=2):
- """Draw group axis according a consistency score."""
-
- l = self.marker_size / 2
- ll = self.marker_size
-
- # Select color according consistency score
- n = 95 * consistency if consistency < 2 else 0
- f = 159 * consistency if consistency < 2 else 255
+ def draw_axes(self, image: numpy.array, K, D, thickness: int = 0, length: float = 0):
+ """Draw group axes."""
try:
-
- # Draw axis
- axisPoints = numpy.float32([[ll, 0, 0], [0, ll, 0], [0, 0, ll], [0, 0, 0]]).reshape(-1, 3)
+ axisPoints = numpy.float32([[length, 0, 0], [0, length, 0], [0, 0, length], [0, 0, 0]]).reshape(-1, 3)
axisPoints, _ = cv.projectPoints(axisPoints, self._rotation, self._translation, numpy.array(K), numpy.array(D))
axisPoints = axisPoints.astype(int)
- cv.line(image, tuple(axisPoints[3].ravel()), tuple(axisPoints[0].ravel()), (n,n,f), 6) # X (red)
- cv.line(image, tuple(axisPoints[3].ravel()), tuple(axisPoints[1].ravel()), (n,f,n), 6) # Y (green)
- cv.line(image, tuple(axisPoints[3].ravel()), tuple(axisPoints[2].ravel()), (f,n,n), 6) # Z (blue)
+ cv.line(image, tuple(axisPoints[3].ravel()), tuple(axisPoints[0].ravel()), (0, 0, 255), thickness) # X (red)
+ cv.line(image, tuple(axisPoints[3].ravel()), tuple(axisPoints[1].ravel()), (0, 255, 0), thickness) # Y (green)
+ cv.line(image, tuple(axisPoints[3].ravel()), tuple(axisPoints[2].ravel()), (255, 0, 0), thickness) # Z (blue)
# Ignore errors due to out of field axis: their coordinate are larger than int32 limitations.
except cv.error:
pass
- def draw_places(self, image: numpy.array, K, D, consistency=2):
- """Draw group places and their axis according a consistency score."""
+ def draw_places(self, image: numpy.array, K, D, color: tuple = None, border_size: int = 0):
+ """Draw group places."""
l = self.marker_size / 2
- ll = self.marker_size
-
- # Select color according consistency score
- n = 95 * consistency if consistency < 2 else 0
- f = 159 * consistency if consistency < 2 else 255
for identifier, place in self.places.items():
@@ -659,29 +645,66 @@ class ArUcoMarkersGroup():
T = self.places[identifier].translation
R = self.places[identifier].rotation
- # Draw place axis
- axisPoints = (T + numpy.float32([R.dot([l/2, 0, 0]), R.dot([0, l/2, 0]), R.dot([0, 0, l/2]), R.dot([0, 0, 0])])).reshape(-1, 3)
- axisPoints, _ = cv.projectPoints(axisPoints, self._rotation, self._translation, numpy.array(K), numpy.array(D))
- axisPoints = axisPoints.astype(int)
-
- cv.line(image, tuple(axisPoints[3].ravel()), tuple(axisPoints[0].ravel()), (n,n,f), 6) # X (red)
- cv.line(image, tuple(axisPoints[3].ravel()), tuple(axisPoints[1].ravel()), (n,f,n), 6) # Y (green)
- cv.line(image, tuple(axisPoints[3].ravel()), tuple(axisPoints[2].ravel()), (f,n,n), 6) # Z (blue)
-
- # Draw place
placePoints = (T + numpy.float32([R.dot([-l, -l, 0]), R.dot([l, -l, 0]), R.dot([l, l, 0]), R.dot([-l, l, 0])])).reshape(-1, 3)
placePoints, _ = cv.projectPoints(placePoints, self._rotation, self._translation, numpy.array(K), numpy.array(D))
placePoints = placePoints.astype(int)
- cv.line(image, tuple(placePoints[0].ravel()), tuple(placePoints[1].ravel()), (f,f,f), 3)
- cv.line(image, tuple(placePoints[1].ravel()), tuple(placePoints[2].ravel()), (f,f,f), 3)
- cv.line(image, tuple(placePoints[2].ravel()), tuple(placePoints[3].ravel()), (f,f,f), 3)
- cv.line(image, tuple(placePoints[3].ravel()), tuple(placePoints[0].ravel()), (f,f,f), 3)
+ cv.line(image, tuple(placePoints[0].ravel()), tuple(placePoints[1].ravel()), color, border_size)
+ cv.line(image, tuple(placePoints[1].ravel()), tuple(placePoints[2].ravel()), color, border_size)
+ cv.line(image, tuple(placePoints[2].ravel()), tuple(placePoints[3].ravel()), color, border_size)
+ cv.line(image, tuple(placePoints[3].ravel()), tuple(placePoints[0].ravel()), color, border_size)
+
+ # Ignore errors due to out of field places: their coordinate are larger than int32 limitations.
+ except cv.error:
+ pass
+
+ def draw_places_axes(self, image: numpy.array, K, D, thickness: int = 0, length: float = 0):
+ """Draw group place axes."""
+
+ for identifier, place in self.places.items():
+
+ try:
+ T = self.places[identifier].translation
+ R = self.places[identifier].rotation
+
+ axisPoints = (T + numpy.float32([R.dot([length, 0, 0]), R.dot([0, length, 0]), R.dot([0, 0, length]), R.dot([0, 0, 0])])).reshape(-1, 3)
+ axisPoints, _ = cv.projectPoints(axisPoints, self._rotation, self._translation, numpy.array(K), numpy.array(D))
+ axisPoints = axisPoints.astype(int)
+
+ cv.line(image, tuple(axisPoints[3].ravel()), tuple(axisPoints[0].ravel()), (0, 0, 255), thickness) # X (red)
+ cv.line(image, tuple(axisPoints[3].ravel()), tuple(axisPoints[1].ravel()), (0, 255, 0), thickness) # Y (green)
+ cv.line(image, tuple(axisPoints[3].ravel()), tuple(axisPoints[2].ravel()), (255, 0, 0), thickness) # Z (blue)
+
# Ignore errors due to out of field places: their coordinate are larger than int32 limitations.
except cv.error:
pass
+ def draw(self, image: numpy.array, K, D, draw_axes: dict = None, draw_places: dict = None, draw_places_axes: dict = None):
+ """Draw group axes and places.
+
+ Parameters:
+
+ draw_axes: draw_axes parameters (if None, no axes drawn)
+ draw_places: draw_places parameters (if None, no places drawn)
+ draw_places_axes: draw_places_axes parameters (if None, no places axes drawn)
+ """
+
+ # Draw axes if required
+ if draw_axes is not None:
+
+ self.draw_axes(image, K, D, **draw_axes)
+
+ # Draw places if required
+ if draw_places is not None:
+
+ self.draw_places(image, K, D, **draw_places)
+
+ # Draw places axes if required
+ if draw_places_axes is not None:
+
+ self.draw_places_axes(image, K, D, **draw_places_axes)
+
def to_obj(self, obj_filepath):
"""Save group to .obj file."""
diff --git a/src/argaze/ArUcoMarkers/ArUcoScene.py b/src/argaze/ArUcoMarkers/ArUcoScene.py
index 3bbd3f4..f6b303a 100644
--- a/src/argaze/ArUcoMarkers/ArUcoScene.py
+++ b/src/argaze/ArUcoMarkers/ArUcoScene.py
@@ -139,22 +139,16 @@ class ArUcoScene(ArFeatures.ArScene):
return tvec, rmat, 'estimate_pose_from_markers', consistent_markers
- def draw_axis(self, image: numpy.array):
+ def draw(self, image: numpy.array, draw_aruco_markers_group: dict = None):
"""
- Draw scene axis into image.
+ Draw scene into image.
Parameters:
image: where to draw
+ draw_aruco_markers_group: ArUcoMarkersGroup.draw parameters (if None, no group drawn)
"""
- self.aruco_markers_group.draw_axis(image, self.parent.aruco_detector.optic_parameters.K, self.parent.aruco_detector.optic_parameters.D)
+ # Draw group if required
+ if draw_aruco_markers_group is not None:
- def draw_places(self, image: numpy.array):
- """
- Draw scene places into image.
-
- Parameters:
- image: where to draw
- """
-
- self.aruco_markers_group.draw_places(image, self.parent.aruco_detector.optic_parameters.K, self.parent.aruco_detector.optic_parameters.D)
+ self.aruco_markers_group.draw(image, self.parent.aruco_detector.optic_parameters.K, self.parent.aruco_detector.optic_parameters.D, **draw_aruco_markers_group)
diff --git a/src/argaze/GazeFeatures.py b/src/argaze/GazeFeatures.py
index 5b89558..2dd1cab 100644
--- a/src/argaze/GazeFeatures.py
+++ b/src/argaze/GazeFeatures.py
@@ -302,7 +302,7 @@ class GazeMovement():
cv2.line(image, (int(start_gaze_position[0]), int(start_gaze_position[1])), (int(next_gaze_position[0]), int(next_gaze_position[1])), line_color, 1)
- def draw(self, image: numpy.array):
+ def draw(self, image: numpy.array, **kwargs):
"""Draw gaze movement into image."""
raise NotImplementedError('draw() method not implemented')
@@ -316,7 +316,7 @@ class UnvalidGazeMovement(GazeMovement):
super().__init__(TimeStampedGazePositions())
- def draw(self, image: numpy.array, color):
+ def draw(self, image: numpy.array, **kwargs):
pass
diff --git a/src/argaze/utils/demo_data/demo_aruco_markers_setup.json b/src/argaze/utils/demo_data/demo_aruco_markers_setup.json
index 14ebc15..9a3b79f 100644
--- a/src/argaze/utils/demo_data/demo_aruco_markers_setup.json
+++ b/src/argaze/utils/demo_data/demo_aruco_markers_setup.json
@@ -25,7 +25,7 @@
}
}
},
- "draw_gaze_position": {
+ "draw_gaze_positions": {
"color": [0, 255, 255],
"size": 4
},
@@ -115,7 +115,7 @@
}
}
},
- "draw_gaze_position": {
+ "draw_gaze_positions": {
"color": [0, 255, 255],
"size": 2
}
diff --git a/src/argaze/utils/demo_data/demo_gaze_analysis_setup.json b/src/argaze/utils/demo_data/demo_gaze_analysis_setup.json
index 0826d6f..414a6fe 100644
--- a/src/argaze/utils/demo_data/demo_gaze_analysis_setup.json
+++ b/src/argaze/utils/demo_data/demo_gaze_analysis_setup.json
@@ -92,8 +92,9 @@
}
}
},
- "draw_gaze_position": {
- "color": [0, 255, 255]
+ "draw_gaze_positions": {
+ "color": [0, 255, 255],
+ "size": 2
}
}
} \ No newline at end of file