aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorThéo de la Hogue2023-08-30 20:32:48 +0200
committerThéo de la Hogue2023-08-30 20:32:48 +0200
commite6d7257954ea343329460a4d8e3863eacc47d222 (patch)
tree7b8195e79834aad033a25e93cdb2f2d51265750e /src
parente030928f9a182cfcdf78b93adfec422fcdb80f78 (diff)
downloadargaze-e6d7257954ea343329460a4d8e3863eacc47d222.zip
argaze-e6d7257954ea343329460a4d8e3863eacc47d222.tar.gz
argaze-e6d7257954ea343329460a4d8e3863eacc47d222.tar.bz2
argaze-e6d7257954ea343329460a4d8e3863eacc47d222.tar.xz
Fixing empty parameters cases.
Diffstat (limited to 'src')
-rw-r--r--src/argaze/ArFeatures.py66
-rw-r--r--src/argaze/ArUcoMarkers/ArUcoDetector.py15
-rw-r--r--src/argaze/ArUcoMarkers/ArUcoMarker.py28
-rw-r--r--src/argaze/GazeAnalysis/DeviationCircleCoverage.py14
-rw-r--r--src/argaze/GazeAnalysis/DispersionThresholdIdentification.py4
-rw-r--r--src/argaze/GazeAnalysis/FocusPointInside.py12
-rw-r--r--src/argaze/GazeAnalysis/VelocityThresholdIdentification.py13
-rw-r--r--src/argaze/GazeFeatures.py22
8 files changed, 104 insertions, 70 deletions
diff --git a/src/argaze/ArFeatures.py b/src/argaze/ArFeatures.py
index d92c754..6553697 100644
--- a/src/argaze/ArFeatures.py
+++ b/src/argaze/ArFeatures.py
@@ -65,7 +65,6 @@ class LoadingFailed(Exception):
super().__init__(message)
-
# Define default ArLayer draw parameters
DEFAULT_ARLAYER_DRAW_PARAMETERS = {
"draw_aoi_scene": {
@@ -413,7 +412,7 @@ class ArLayer():
# Check gaze movement validity
if gaze_movement.valid:
- if self.aoi_matcher:
+ if self.aoi_matcher is not None:
# Store aoi matching start date
matching_start = time.perf_counter()
@@ -431,12 +430,12 @@ class ArLayer():
if GazeFeatures.is_fixation(gaze_movement):
# Append fixation to aoi scan path
- if self.aoi_scan_path != None and looked_aoi != None:
+ if self.aoi_scan_path is not None and looked_aoi is not None:
aoi_scan_step = self.aoi_scan_path.append_fixation(timestamp, gaze_movement, looked_aoi)
# Is there a new step?
- if aoi_scan_step and len(self.aoi_scan_path) > 1:
+ if aoi_scan_step is not None and len(self.aoi_scan_path) > 1:
for aoi_scan_path_analyzer_module_path, aoi_scan_path_analyzer in self.aoi_scan_path_analyzers.items():
@@ -460,7 +459,7 @@ class ArLayer():
elif GazeFeatures.is_saccade(gaze_movement):
# Append saccade to aoi scan path
- if self.aoi_scan_path != None:
+ if self.aoi_scan_path is not None:
self.aoi_scan_path.append_saccade(timestamp, gaze_movement)
@@ -501,7 +500,7 @@ class ArLayer():
"""
# Use draw_parameters attribute if no parameters
- if not draw_aoi_scene and not draw_aoi_matching:
+ if draw_aoi_scene is None and draw_aoi_matching is None:
return self.draw(image, **self.draw_parameters)
@@ -509,12 +508,12 @@ class ArLayer():
self.__look_lock.acquire()
# Draw aoi if required
- if draw_aoi_scene:
+ if draw_aoi_scene is not None:
self.aoi_scene.draw(image, **draw_aoi_scene)
# Draw aoi matching if required
- if draw_aoi_matching and self.aoi_matcher:
+ if draw_aoi_matching is not None and self.aoi_matcher is not None:
self.aoi_matcher.draw(image, **draw_aoi_matching)
@@ -537,7 +536,8 @@ DEFAULT_ARFRAME_IMAGE_PARAMETERS = {
"deepness": 0
},
"draw_gaze_position": {
- "color": (0, 255, 255)
+ "color": (0, 255, 255),
+ "size": 2
}
}
@@ -880,7 +880,7 @@ class ArFrame():
try:
# Identify gaze movement
- if self.gaze_movement_identifier:
+ if self.gaze_movement_identifier is not None:
# Store movement identification start date
identification_start = time.perf_counter()
@@ -897,14 +897,14 @@ class ArFrame():
if GazeFeatures.is_fixation(identified_gaze_movement):
# Append fixation to scan path
- if self.scan_path != None:
+ if self.scan_path is not None:
self.scan_path.append_fixation(timestamp, identified_gaze_movement)
elif GazeFeatures.is_saccade(identified_gaze_movement):
# Append saccade to scan path
- if self.scan_path != None:
+ if self.scan_path is not None:
scan_step = self.scan_path.append_saccade(timestamp, identified_gaze_movement)
@@ -931,7 +931,7 @@ class ArFrame():
self.__ts_logs[scan_path_analyzer_module_path][timestamp] = scan_path_analyzer.analysis
# No valid finished gaze movement: optionnaly stop in progress fixation filtering
- elif self.gaze_movement_identifier and not self.filter_in_progress_fixation:
+ elif self.gaze_movement_identifier is not None and not self.filter_in_progress_fixation:
current_fixation = self.gaze_movement_identifier.current_fixation
@@ -940,7 +940,7 @@ class ArFrame():
identified_gaze_movement = current_fixation
# Update heatmap
- if self.heatmap:
+ if self.heatmap is not None:
# Store heatmap start date
heatmap_start = time.perf_counter()
@@ -1016,7 +1016,7 @@ class ArFrame():
"""
# Use image_parameters attribute if no parameters
- if not background_weight and not heatmap_weight and not draw_scan_path and not draw_layers and not draw_gaze_position:
+ if background_weight is None and heatmap_weight is None and draw_scan_path is None and draw_layers is None and draw_gaze_position is None:
return self.image(**self.image_parameters)
@@ -1024,19 +1024,19 @@ class ArFrame():
self.__look_lock.acquire()
# Draw background only
- if background_weight and not heatmap_weight:
+ if background_weight is not None and heatmap_weight is None:
image = self.background.copy()
# Draw mix background and heatmap if required
- elif background_weight and heatmap_weight and self.heatmap:
+ 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)
# Draw heatmap only
- elif not background_weight and heatmap_weight and self.heatmap:
+ 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)
@@ -1046,19 +1046,19 @@ class ArFrame():
image = numpy.full((self.size[1], self.size[0], 3), 0).astype(numpy.uint8)
# Draw scan path if required
- if draw_scan_path and self.scan_path != None:
+ if draw_scan_path is not None and self.scan_path is not None:
self.scan_path.draw(image, **draw_scan_path)
# Draw layers if required
- if draw_layers:
+ if draw_layers is not None:
for layer_name, draw_layer in draw_layers.items():
self.layers[layer_name].draw(image, **draw_layer)
# Draw current gaze position if required
- if draw_gaze_position:
+ if draw_gaze_position is not None:
self.__gaze_position.draw(image, **draw_gaze_position)
@@ -1250,7 +1250,7 @@ class ArScene():
frame_layer.aoi_scene = layer_aoi_scene_projection.reframe(aoi_frame_projection, new_frame.size)
- if frame_layer.aoi_scan_path != None:
+ if frame_layer.aoi_scan_path is not None:
# Edit expected AOI list by removing AOI with name equals to frame layer name
expected_aois = list(layer.aoi_scene.keys())
@@ -1441,7 +1441,12 @@ class ArScene():
# Define default ArEnvironment image_paremeters values
DEFAULT_ARENVIRONMENT_IMAGE_PARAMETERS = {
- "draw_detected_markers": True
+ "draw_detected_markers": {
+ "color": (0, 255, 0),
+ "draw_axes": {
+ "thickness": 3
+ }
+ }
}
@dataclass
@@ -1465,7 +1470,7 @@ class ArEnvironment():
def __post_init__(self):
# Setup camera frame parent attribute
- if self.camera_frame != None:
+ if self.camera_frame is not None:
self.camera_frame.parent = self
@@ -1556,11 +1561,11 @@ class ArEnvironment():
new_scenes[scene_name] = new_scene
# Setup expected aoi of each camera frame layer aoi scan path with the aoi of corresponding scene layer
- if new_camera_frame != None:
+ if new_camera_frame is not None:
for camera_frame_layer_name, camera_frame_layer in new_camera_frame.layers.items():
- if camera_frame_layer.aoi_scan_path != None:
+ if camera_frame_layer.aoi_scan_path is not None:
all_aoi_list = []
@@ -1798,11 +1803,12 @@ class ArEnvironment():
"""Get camera frame projections with ArUco detection visualisation.
Parameters:
- draw_detected_markers: ArUcoDetector.draw_detected_markers parameters (If None, detected markers are not drawn)
+ image: image where to draw
+ draw_detected_markers: ArucoMarker.draw parameters (if None, no marker drawn)
"""
# Use image_parameters attribute if no parameters
- if not draw_detected_markers:
+ if draw_detected_markers is None:
return self.image(**self.image_parameters)
@@ -1817,9 +1823,9 @@ class ArEnvironment():
image = self.camera_frame.image()
# Draw detected markers if required
- if draw_detected_markers:
+ if draw_detected_markers is not None:
- self.aruco_detector.draw_detected_markers(image)
+ self.aruco_detector.draw_detected_markers(image, draw_detected_markers)
# Unlock camera frame exploitation
self.__camera_frame_lock.release()
diff --git a/src/argaze/ArUcoMarkers/ArUcoDetector.py b/src/argaze/ArUcoMarkers/ArUcoDetector.py
index 5076f3d..135eb08 100644
--- a/src/argaze/ArUcoMarkers/ArUcoDetector.py
+++ b/src/argaze/ArUcoMarkers/ArUcoDetector.py
@@ -274,12 +274,19 @@ class ArUcoDetector():
return len(list(self.__detected_markers.keys()))
- def draw_detected_markers(self, image: numpy.array):
- """Draw traked markers."""
+ def draw_detected_markers(self, image: numpy.array, draw_marker: dict = None):
+ """Draw detected markers.
- for marker_id, marker in self.__detected_markers.items():
+ Parameters:
+ image: image where to draw
+ draw_marker: ArucoMarker.draw parameters (if None, no marker drawn)
+ """
+
+ if draw_marker is not None:
+
+ for marker_id, marker in self.__detected_markers.items():
- marker.draw(image, self.optic_parameters.K, self.optic_parameters.D)
+ marker.draw(image, self.optic_parameters.K, self.optic_parameters.D, **draw_marker)
def detect_board(self, image: numpy.array, board, expected_markers_number):
"""Detect ArUco markers board in image setting up the number of detected markers needed to agree detection.
diff --git a/src/argaze/ArUcoMarkers/ArUcoMarker.py b/src/argaze/ArUcoMarkers/ArUcoMarker.py
index 3a13c10..57bd8bd 100644
--- a/src/argaze/ArUcoMarkers/ArUcoMarker.py
+++ b/src/argaze/ArUcoMarkers/ArUcoMarker.py
@@ -12,7 +12,7 @@ from dataclasses import dataclass, field
from argaze.ArUcoMarkers import ArUcoMarkersDictionary
import numpy
-import cv2 as cv
+import cv2
import cv2.aruco as aruco
@dataclass
@@ -40,9 +40,6 @@ class ArUcoMarker():
points: numpy.array = field(init=False, repr=False)
"""Estimated 3D corners positions in camera world referential."""
- color: tuple = field(init=False, repr=False, default_factory=lambda : (0, 255, 0))
- """Color used to draw marker on image."""
-
@property
def center(self) -> numpy.array:
"""Get 2D center position in camera image referential."""
@@ -59,15 +56,24 @@ class ArUcoMarker():
return numpy.repeat(matrix, 3).reshape(dimension, dimension, 3)
- def draw(self, image: numpy.array, K, D):
- """Draw marker in image."""
+ def draw(self, image: numpy.array, K, D, color: tuple = None, draw_axes: dict = None):
+ """Draw marker in image.
+
+ Parameters:
+ image: image where to draw
+ color: marker color (if None, no marker drawn)
+ draw_axes: enable marker axes drawing
+ """
+
+ # Draw marker if required
+ if color is not None:
- # Draw marker axis if pose has been estimated
- if self.translation.size == 3 and self.rotation.size == 9:
+ aruco.drawDetectedMarkers(image, [self.corners], numpy.array([self.identifier]), color)
- cv.drawFrameAxes(image, numpy.array(K), numpy.array(D), self.rotation, self.translation, self.size)
+ # Draw marker axes if pose has been estimated and if required
+ if self.translation.size == 3 and self.rotation.size == 9 and draw_axes is not None:
- aruco.drawDetectedMarkers(image, [self.corners], numpy.array([self.identifier]), self.color)
+ cv2.drawFrameAxes(image, numpy.array(K), numpy.array(D), self.rotation, self.translation, self.size, **draw_axes)
def save(self, destination_folder, dpi):
"""Save marker image as .png file into a destination folder."""
@@ -75,5 +81,5 @@ class ArUcoMarker():
filename = f'{self.dictionary.name}_{self.dictionary.format}_{self.identifier}.png'
filepath = f'{destination_folder}/{filename}'
- cv.imwrite(filepath, self.image(dpi))
+ cv2.imwrite(filepath, self.image(dpi))
diff --git a/src/argaze/GazeAnalysis/DeviationCircleCoverage.py b/src/argaze/GazeAnalysis/DeviationCircleCoverage.py
index 98706f7..e1b33f1 100644
--- a/src/argaze/GazeAnalysis/DeviationCircleCoverage.py
+++ b/src/argaze/GazeAnalysis/DeviationCircleCoverage.py
@@ -108,35 +108,35 @@ class AOIMatcher(GazeFeatures.AOIMatcher):
looked_aoi_name_offset: ofset of text from the upper left aoi bounding box corner
"""
- if self.__matched_gaze_movement:
+ if self.__matched_gaze_movement is not None:
if GazeFeatures.is_fixation(self.__matched_gaze_movement):
# Draw matched fixation if required
- if draw_matched_fixation:
+ if draw_matched_fixation is not None:
self.__matched_gaze_movement.draw(image, **draw_matched_fixation)
# Draw matched fixation positions if required
- if draw_matched_fixation_positions:
+ if draw_matched_fixation_positions is not None:
self.__matched_gaze_movement.draw_positions(image, **draw_matched_fixation_positions)
# Draw matched aoi
- if self.looked_aoi.all() != None:
+ if self.looked_aoi.all() is not None:
# Draw looked aoi if required
- if draw_looked_aoi:
+ if draw_looked_aoi is not None:
self.looked_aoi.draw(image, **draw_looked_aoi)
# Draw matched region if required
- if draw_matched_region:
+ if draw_matched_region is not None:
self.__matched_region.draw(image, **draw_matched_region)
# Draw looked aoi name if required
- if looked_aoi_name_color:
+ if looked_aoi_name_color is not None:
top_left_corner_pixel = numpy.rint(self.looked_aoi.bounding_box[0]).astype(int) + looked_aoi_name_offset
cv2.putText(image, self.looked_aoi_name, top_left_corner_pixel, cv2.FONT_HERSHEY_SIMPLEX, 1, looked_aoi_name_color, 1, cv2.LINE_AA)
diff --git a/src/argaze/GazeAnalysis/DispersionThresholdIdentification.py b/src/argaze/GazeAnalysis/DispersionThresholdIdentification.py
index bf7b862..85f2fb5 100644
--- a/src/argaze/GazeAnalysis/DispersionThresholdIdentification.py
+++ b/src/argaze/GazeAnalysis/DispersionThresholdIdentification.py
@@ -83,12 +83,12 @@ class Fixation(GazeFeatures.Fixation):
"""
# Draw deviation circle if required
- if deviation_circle_color:
+ if deviation_circle_color is not None:
cv2.circle(image, (int(self.focus[0]), int(self.focus[1])), int(self.deviation_max), deviation_circle_color, -1)
# Draw duration border if required
- if duration_border_color:
+ if duration_border_color is not None:
cv2.circle(image, (int(self.focus[0]), int(self.focus[1])), int(self.deviation_max), duration_border_color, int(self.duration * duration_factor))
diff --git a/src/argaze/GazeAnalysis/FocusPointInside.py b/src/argaze/GazeAnalysis/FocusPointInside.py
index 2ac4411..c071f82 100644
--- a/src/argaze/GazeAnalysis/FocusPointInside.py
+++ b/src/argaze/GazeAnalysis/FocusPointInside.py
@@ -63,30 +63,30 @@ class AOIMatcher(GazeFeatures.AOIMatcher):
looked_aoi_name_offset: ofset of text from the upper left aoi bounding box corner
"""
- if self.__matched_gaze_movement:
+ if self.__matched_gaze_movement is not None:
if GazeFeatures.is_fixation(self.__matched_gaze_movement):
# Draw matched fixation if required
- if draw_matched_fixation:
+ if draw_matched_fixation is not None:
self.__matched_gaze_movement.draw(image, **draw_matched_fixation)
# Draw matched fixation positions if required
- if draw_matched_fixation_positions:
+ if draw_matched_fixation_positions is not None:
self.__matched_gaze_movement.draw_positions(image, **draw_matched_fixation_positions)
# Draw matched aoi
- if self.looked_aoi.all() != None:
+ if self.looked_aoi.all() is not None:
# Draw looked aoi if required
- if draw_looked_aoi:
+ if draw_looked_aoi is not None:
self.looked_aoi.draw(image, **draw_looked_aoi)
# Draw looked aoi name if required
- if looked_aoi_name_color:
+ if looked_aoi_name_color is not None:
top_left_corner_pixel = numpy.rint(self.looked_aoi.bounding_box[0]).astype(int) + looked_aoi_name_offset
cv2.putText(image, self.looked_aoi_name, top_left_corner_pixel, cv2.FONT_HERSHEY_SIMPLEX, 1, looked_aoi_name_color, 1, cv2.LINE_AA)
diff --git a/src/argaze/GazeAnalysis/VelocityThresholdIdentification.py b/src/argaze/GazeAnalysis/VelocityThresholdIdentification.py
index 1160a0d..ab90fe7 100644
--- a/src/argaze/GazeAnalysis/VelocityThresholdIdentification.py
+++ b/src/argaze/GazeAnalysis/VelocityThresholdIdentification.py
@@ -72,7 +72,7 @@ class Fixation(GazeFeatures.Fixation):
return self
- def draw(self, image: numpy.array, deviation_circle_color=(255, 255, 255), duration_border_color=(255, 255, 255), duration_factor: float = 1.):
+ def draw(self, image: numpy.array, deviation_circle_color: tuple = None, duration_border_color: tuple = None, duration_factor: float = 1.):
"""Draw fixation into image.
Parameters:
@@ -81,8 +81,15 @@ class Fixation(GazeFeatures.Fixation):
duration_factor: how many pixels per duration unit
"""
- cv2.circle(image, (int(self.focus[0]), int(self.focus[1])), int(self.deviation_max), deviation_circle_color, -1)
- cv2.circle(image, (int(self.focus[0]), int(self.focus[1])), int(self.deviation_max), duration_border_color, int(self.duration * duration_factor))
+ # Draw deviation circle if required
+ if deviation_circle_color is not None:
+
+ cv2.circle(image, (int(self.focus[0]), int(self.focus[1])), int(self.deviation_max), deviation_circle_color, -1)
+
+ # Draw duration border if required
+ if duration_border_color is not None:
+
+ cv2.circle(image, (int(self.focus[0]), int(self.focus[1])), int(self.deviation_max), duration_border_color, int(self.duration * duration_factor))
@dataclass(frozen=True)
class Saccade(GazeFeatures.Saccade):
diff --git a/src/argaze/GazeFeatures.py b/src/argaze/GazeFeatures.py
index 3946e0c..4c377d1 100644
--- a/src/argaze/GazeFeatures.py
+++ b/src/argaze/GazeFeatures.py
@@ -91,15 +91,16 @@ class GazePosition():
else:
return distance < self.precision
- def draw(self, image: numpy.array, color=(255, 255, 255), draw_precision=True):
+ def draw(self, image: numpy.array, color: tuple = None, size: int = None, draw_precision=True):
"""Draw gaze position point and precision circle."""
if self.valid:
int_value = (int(self.value[0]), int(self.value[1]))
- # Draw point at position
- cv2.circle(image, int_value, 2, color, -1)
+ # Draw point at position if required
+ if color is not None:
+ cv2.circle(image, int_value, size, color, -1)
# Draw precision circle
if self.precision > 0 and draw_precision:
@@ -292,12 +293,12 @@ class GazeMovement():
ts_next, next_gaze_position = gaze_positions.first
# Draw position if required
- if position_color:
+ if position_color is not None:
start_gaze_position.draw(image, position_color, draw_precision=False)
# Draw line between positions if required
- if line_color:
+ if line_color is not None:
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)
@@ -682,8 +683,15 @@ class ScanPath(list):
for step in self[-deepness:]:
- step.first_fixation.draw(image, **draw_fixations)
- step.last_saccade.draw(image, **draw_saccades)
+ # Draw fixation if required
+ if draw_fixations is not None:
+
+ step.first_fixation.draw(image, **draw_fixations)
+
+ # Draw saccade if required
+ if draw_saccades is not None:
+
+ step.last_saccade.draw(image, **draw_saccades)
class ScanPathAnalyzer():
"""Abstract class to define what should provide a scan path analyzer."""