aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThéo de la Hogue2022-05-03 14:57:59 +0200
committerThéo de la Hogue2022-05-03 14:57:59 +0200
commit8c8f6f859e63e913257d60891005cfd95c280ed4 (patch)
tree858019e31fcbbe6ac7b362c6dabea03a22af1375
parentb560ddb3a7a687c3b2191fa32aadf4301b1ae7b4 (diff)
downloadargaze-8c8f6f859e63e913257d60891005cfd95c280ed4.zip
argaze-8c8f6f859e63e913257d60891005cfd95c280ed4.tar.gz
argaze-8c8f6f859e63e913257d60891005cfd95c280ed4.tar.bz2
argaze-8c8f6f859e63e913257d60891005cfd95c280ed4.tar.xz
Improving gaze position management to export data with appropriate precisions.
-rw-r--r--src/argaze/AreaOfInterest/AOI2DScene.py2
-rw-r--r--src/argaze/AreaOfInterest/AOIFeatures.py8
-rw-r--r--src/argaze/DataStructures.py2
-rw-r--r--src/argaze/GazeFeatures.py31
-rw-r--r--src/argaze/utils/export_tobii_segment_aruco_visual_scan.py4
-rw-r--r--src/argaze/utils/export_tobii_segment_movements.py2
-rw-r--r--src/argaze/utils/live_tobii_aruco_aois.py4
-rw-r--r--src/argaze/utils/live_tobii_session.py4
-rw-r--r--src/argaze/utils/replay_tobii_session.py4
9 files changed, 26 insertions, 35 deletions
diff --git a/src/argaze/AreaOfInterest/AOI2DScene.py b/src/argaze/AreaOfInterest/AOI2DScene.py
index 6eb0f7c..d902bea 100644
--- a/src/argaze/AreaOfInterest/AOI2DScene.py
+++ b/src/argaze/AreaOfInterest/AOI2DScene.py
@@ -41,13 +41,11 @@ class AOI2DScene(AOIFeatures.AOIScene):
for name, aoi2D in self.areas.items():
looked = aoi2D.looked(gaze_position)
- looked_at = aoi2D.look_at(gaze_position)
color = (0, 255, 0) if looked else (0, 0, 255)
if looked:
cv.putText(frame, name, aoi2D[3], cv.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 1, cv.LINE_AA)
- cv.circle(frame, looked_at.astype(int), 10, (255, 255, 255), -1)
# Draw form
aoi2D.draw(frame, color)
diff --git a/src/argaze/AreaOfInterest/AOIFeatures.py b/src/argaze/AreaOfInterest/AOIFeatures.py
index a33db26..dc38eb8 100644
--- a/src/argaze/AreaOfInterest/AOIFeatures.py
+++ b/src/argaze/AreaOfInterest/AOIFeatures.py
@@ -2,7 +2,7 @@
from dataclasses import dataclass, field
-from argaze import DataStructures
+from argaze import DataStructures, GazeFeatures
import cv2 as cv
import matplotlib.path as mpath
@@ -38,7 +38,7 @@ class AreaOfInterest(numpy.ndarray):
if self.dimension() != 2:
raise RuntimeError(f'Bad area dimension ({self.dimension()})')
- return mpath.Path(self).contains_points([(gaze_position.x, gaze_position.y)])[0]
+ return mpath.Path(self).contains_points([gaze_position])[0]
def look_at(self, gaze_position):
"""Get where the area is looked."""
@@ -46,7 +46,7 @@ class AreaOfInterest(numpy.ndarray):
if self.dimension() != 2:
raise RuntimeError(f'Bad area dimension ({self.dimension()})')
- P = numpy.array([gaze_position.x, gaze_position.y])
+ P = numpy.array(gaze_position)
clockwise_area = self.clockwise()
@@ -54,7 +54,7 @@ class AreaOfInterest(numpy.ndarray):
OX, OY = clockwise_area[1] - O, clockwise_area[-1] - O
OP = P - O
- return numpy.array([numpy.dot(OP, OX) / numpy.dot(OX, OX), numpy.dot(OP, OY) / numpy.dot(OY, OY)])
+ return ( round(numpy.dot(OP, OX) / numpy.dot(OX, OX), 3), round(numpy.dot(OP, OY) / numpy.dot(OY, OY), 3))
def draw(self, frame, color):
diff --git a/src/argaze/DataStructures.py b/src/argaze/DataStructures.py
index 44c2583..7b6ad9b 100644
--- a/src/argaze/DataStructures.py
+++ b/src/argaze/DataStructures.py
@@ -52,7 +52,7 @@ class TimeStampedBuffer(collections.OrderedDict):
super().__setitem__(key, value)
def __str__(self):
- return json.dumps(self, default = vars)
+ return str(dict(self))
def append(self, timestamped_buffer):
"""Append a timestamped buffer."""
diff --git a/src/argaze/GazeFeatures.py b/src/argaze/GazeFeatures.py
index 63a1e55..50104d4 100644
--- a/src/argaze/GazeFeatures.py
+++ b/src/argaze/GazeFeatures.py
@@ -8,15 +8,8 @@ from argaze.AreaOfInterest import AOIFeatures
import numpy
-@dataclass
-class GazePosition():
- """Define gaze position."""
-
- x: float
- y: float
-
- def as_tuple(self):
- return (self.x, self.y)
+GazePosition = tuple
+"""Define gaze position as a tuple of coordinates."""
class TimeStampedGazePositions(DataStructures.TimeStampedBuffer):
"""Define timestamped buffer to store gaze positions."""
@@ -114,8 +107,8 @@ class DispersionBasedMovementIdentifier(MovementIdentifier):
def __getEuclideanDispersion(self, ts_gaze_positions_list):
"""Euclidian dispersion algorithm"""
- x_list = [gp.x for (ts, gp) in ts_gaze_positions_list]
- y_list = [gp.y for (ts, gp) in ts_gaze_positions_list]
+ x_list = [gp[0] for (ts, gp) in ts_gaze_positions_list]
+ y_list = [gp[1] for (ts, gp) in ts_gaze_positions_list]
cx = numpy.mean(x_list)
cy = numpy.mean(y_list)
@@ -127,7 +120,7 @@ class DispersionBasedMovementIdentifier(MovementIdentifier):
dist = numpy.sum(dist, axis=1)
dist = numpy.sqrt(dist)
- return max(dist), cx, cy
+ return round(max(dist)), cx, cy
def __getDispersion(self, ts_gaze_positions_list):
"""Basic dispersion algorithm"""
@@ -205,9 +198,9 @@ class DispersionBasedMovementIdentifier(MovementIdentifier):
ts_gaze_positions = TimeStampedGazePositions()
for (ts, gp) in ts_gaze_positions_list:
- ts_gaze_positions[ts] = gp
+ ts_gaze_positions[round(ts)] = gp
- new_fixation = Fixation(duration, dispersion, GazePosition(cx, cy), ts_gaze_positions)
+ new_fixation = Fixation(round(duration), dispersion, (round(cx), round(cy)), ts_gaze_positions)
new_fixation_ts = ts_list[0]
if self.__last_fixation != None:
@@ -217,14 +210,14 @@ class DispersionBasedMovementIdentifier(MovementIdentifier):
if new_saccade_duration > 0:
- new_saccade = Saccade(new_saccade_duration, self.__last_fixation.positions.pop_last()[1], new_fixation.positions.pop_first()[1])
+ new_saccade = Saccade(round(new_saccade_duration), self.__last_fixation.positions.pop_last()[1], new_fixation.positions.pop_first()[1])
- yield new_saccade_ts, new_saccade
+ yield round(new_saccade_ts), new_saccade
self.__last_fixation = new_fixation
self.__last_fixation_ts = new_fixation_ts
- yield new_fixation_ts, new_fixation
+ yield round(new_fixation_ts), new_fixation
# dispersion too wide : consider next gaze position
else:
@@ -313,14 +306,14 @@ class PointerBasedVisualScan(VisualScanGenerator):
}
# store where the aoi is looked
- self.__step_dict[name]['look_at'][ts_current] = aoi.look_at(gaze_position).tolist()
+ self.__step_dict[name]['look_at'][round(ts_current)] = aoi.look_at(gaze_position)
elif name in self.__step_dict.keys():
ts_start = self.__step_dict[name]['start']
# aoi stops to be looked
- yield ts_start, VisualScanStep(ts_current - ts_start, name, self.__step_dict[name]['look_at'])
+ yield round(ts_start), VisualScanStep(round(ts_current - ts_start), name, self.__step_dict[name]['look_at'])
# forget the aoi
del self.__step_dict[name]
diff --git a/src/argaze/utils/export_tobii_segment_aruco_visual_scan.py b/src/argaze/utils/export_tobii_segment_aruco_visual_scan.py
index 02f5cb2..466f0b3 100644
--- a/src/argaze/utils/export_tobii_segment_aruco_visual_scan.py
+++ b/src/argaze/utils/export_tobii_segment_aruco_visual_scan.py
@@ -110,8 +110,8 @@ def main():
closest_gaze_ts, closest_gaze_position = tobii_ts_gaze_positions.pop_first_until(video_ts)
# Draw gaze position
- gaze_position = GazeFeatures.GazePosition(int(closest_gaze_position.gp[0] * video_frame.width), int(closest_gaze_position.gp[1] * video_frame.height))
- cv.circle(video_frame.matrix, gaze_position.as_tuple(), 4, (0, 255, 255), -1)
+ gaze_position = (int(closest_gaze_position.gp[0] * video_frame.width), int(closest_gaze_position.gp[1] * video_frame.height))
+ cv.circle(video_frame.matrix, gaze_position, 4, (0, 255, 255), -1)
# Store gaze position at this time in millisecond
ts_gaze_positions[video_ts/1000] = gaze_position
diff --git a/src/argaze/utils/export_tobii_segment_movements.py b/src/argaze/utils/export_tobii_segment_movements.py
index 624d758..1c741ab 100644
--- a/src/argaze/utils/export_tobii_segment_movements.py
+++ b/src/argaze/utils/export_tobii_segment_movements.py
@@ -59,7 +59,7 @@ def main():
generic_ts_gaze_positions = GazeFeatures.TimeStampedGazePositions()
for ts, tobii_data in tobii_ts_gaze_positions.items():
- generic_data = GazeFeatures.GazePosition(tobii_data.gp[0] * tobii_segment_video.get_width(), tobii_data.gp[1] * tobii_segment_video.get_height())
+ generic_data = (int(tobii_data.gp[0] * tobii_segment_video.get_width()), int(tobii_data.gp[1] * tobii_segment_video.get_height()))
generic_ts_gaze_positions[ts/1000] = generic_data
print(f'Dispersion threshold: {args.dispersion_threshold}')
diff --git a/src/argaze/utils/live_tobii_aruco_aois.py b/src/argaze/utils/live_tobii_aruco_aois.py
index 8ad458b..4f00dea 100644
--- a/src/argaze/utils/live_tobii_aruco_aois.py
+++ b/src/argaze/utils/live_tobii_aruco_aois.py
@@ -83,8 +83,8 @@ def main():
earliest_ts, earliest_gaze_position = past_gaze_positions.pop_first_until(video_ts)
# Draw gaze position
- gaze_position = GazeFeatures.GazePosition(int(earliest_gaze_position.gp[0] * video_frame.width), int(earliest_gaze_position.gp[1] * video_frame.height))
- cv.circle(video_frame.matrix, gaze_position.as_tuple(), 4, (0, 255, 255), -1)
+ gaze_position = (int(earliest_gaze_position.gp[0] * video_frame.width), int(earliest_gaze_position.gp[1] * video_frame.height))
+ cv.circle(video_frame.matrix, gaze_position, 4, (0, 255, 255), -1)
# Wait for gaze position
except (AttributeError, ValueError):
diff --git a/src/argaze/utils/live_tobii_session.py b/src/argaze/utils/live_tobii_session.py
index 561dc6c..f71b18f 100644
--- a/src/argaze/utils/live_tobii_session.py
+++ b/src/argaze/utils/live_tobii_session.py
@@ -56,8 +56,8 @@ def main():
earliest_ts, earliest_gaze_position = past_gaze_positions.pop_first_until(video_ts)
# Draw gaze position
- gaze_position = GazeFeatures.GazePosition(int(earliest_gaze_position.gp[0] * video_frame.width), int(earliest_gaze_position.gp[1] * video_frame.height))
- cv.circle(video_frame.matrix, gaze_position.as_tuple(), 4, (0, 255, 255), -1)
+ gaze_position = (int(earliest_gaze_position.gp[0] * video_frame.width), int(earliest_gaze_position.gp[1] * video_frame.height))
+ cv.circle(video_frame.matrix, gaze_position, 4, (0, 255, 255), -1)
# Wait for gaze position
except (AttributeError, ValueError):
diff --git a/src/argaze/utils/replay_tobii_session.py b/src/argaze/utils/replay_tobii_session.py
index 62c2a7e..bbde63f 100644
--- a/src/argaze/utils/replay_tobii_session.py
+++ b/src/argaze/utils/replay_tobii_session.py
@@ -54,8 +54,8 @@ def main():
closest_gaze_ts, closest_gaze_position = tobii_ts_gaze_positions.pop_first_until(video_ts)
# Draw gaze position
- gaze_position = GazeFeatures.GazePosition(int(closest_gaze_position.gp[0] * video_frame.width), int(closest_gaze_position.gp[1] * video_frame.height))
- cv.circle(video_frame.matrix, gaze_position.as_tuple(), 4, (0, 255, 255), -1)
+ gaze_position = (int(closest_gaze_position.gp[0] * video_frame.width), int(closest_gaze_position.gp[1] * video_frame.height))
+ cv.circle(video_frame.matrix, gaze_position, 4, (0, 255, 255), -1)
# Wait for gaze position
except ValueError: