aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/argaze/AreaOfInterest/AOI2DScene.py18
-rw-r--r--src/argaze/AreaOfInterest/AOI3DScene.py41
-rw-r--r--src/argaze/AreaOfInterest/AOIFeatures.py68
-rw-r--r--src/argaze/GazeFeatures.py34
-rw-r--r--src/argaze/TobiiGlassesPro2/TobiiVideo.py10
-rw-r--r--src/argaze/utils/export_tobii_segment_aruco_visual_scan.py2
-rw-r--r--src/argaze/utils/live_tobii_aruco_aois.py2
7 files changed, 70 insertions, 105 deletions
diff --git a/src/argaze/AreaOfInterest/AOI2DScene.py b/src/argaze/AreaOfInterest/AOI2DScene.py
index 929cc30..ee172f8 100644
--- a/src/argaze/AreaOfInterest/AOI2DScene.py
+++ b/src/argaze/AreaOfInterest/AOI2DScene.py
@@ -8,16 +8,7 @@ import cv2 as cv
import matplotlib.path as mpath
class AOI2DScene(AOIFeatures.AOIScene):
- """Define AOI 2D scene as:
- ```
- {
- 'dimension': 2,
- 'name 1': AOI 1,
- 'name 2': AOI 2,
- ...
- }
- ```
- """
+ """Define AOI 2D scene."""
def __init__(self, **aois_2d):
@@ -29,9 +20,7 @@ class AOI2DScene(AOIFeatures.AOIScene):
def look_at(self, gaze_position: GazeFeatures.GazePosition):
"""Store gaze position as a pointer inside looked AOIs."""
- for name in self.areas():
-
- aoi2D = self[name]
+ for name, aoi2D in self.areas.items():
if mpath.Path(aoi2D.vertices).contains_points([(gaze_position.x, gaze_position.y)])[0]:
@@ -45,9 +34,8 @@ class AOI2DScene(AOIFeatures.AOIScene):
def draw(self, frame):
"""Draw AOI polygons on frame."""
- for name in self.areas():
+ for name, aoi2D in self.areas.items():
- aoi2D = self[name]
inside = aoi2D.pointer != None
color = (0, 255, 0) if inside else (0, 0, 255)
diff --git a/src/argaze/AreaOfInterest/AOI3DScene.py b/src/argaze/AreaOfInterest/AOI3DScene.py
index 2930983..d126f45 100644
--- a/src/argaze/AreaOfInterest/AOI3DScene.py
+++ b/src/argaze/AreaOfInterest/AOI3DScene.py
@@ -1,5 +1,6 @@
#!/usr/bin/env python
+from dataclasses import dataclass, field
import math
import re
@@ -9,35 +10,18 @@ from argaze.AreaOfInterest import AOIFeatures, AOI2DScene
import numpy
import cv2 as cv
+@dataclass
class AOI3DScene(AOIFeatures.AOIScene):
- """Define AOI 3D scene as:
- ```
- {
- 'dimension': 3,
- 'rotation': (x, y, z) tuples,
- 'translation': (x, y, z) tuples,
- 'name 1': AOI 1,
- 'name 2': AOI 2,
- ...
- }
- ```
- """
-
- def __init__(self, **aois_3d):
+ """Define AOI 3D scene."""
- # append rotation and translation matrix
- aois_3d['rotation'] = numpy.asarray([0., 0., 0.])
- aois_3d['translation'] = numpy.asarray([0., 0., 0.])
+ rotation: list = field(init=False, default=numpy.asarray([0., 0., 0.]))
+ translation: list = field(init=False, default=numpy.asarray([0., 0., 0.]))
- super().__init__(**aois_3d)
+ def __post_init__(self, **aois):
# set dimension member
self.dimension = 3
- def areas(self):
- """Get areas names"""
- return self.keys()[3::]
-
def load(self, obj_filepath: str):
"""Load AOI3D scene from .obj file."""
@@ -103,7 +87,8 @@ class AOI3DScene(AOIFeatures.AOIScene):
# retreive all aoi3D vertices
for name, face in faces.items():
- self.append(name, AOIFeatures.AreaOfInterest(**{'vertices': [ vertices[i-1] for i in face ]}))
+ aoi3D = AOIFeatures.AreaOfInterest(vertices=[ vertices[i-1] for i in face ])
+ self.append(name, aoi3D)
except IOError:
raise IOError(f'File not found: {obj_filepath}')
@@ -112,11 +97,9 @@ class AOI3DScene(AOIFeatures.AOIScene):
"""Project 3D scene onto 2D scene according optical parameters.
**Returns:** AOI2DScene"""
- aoi2D_scene = {}
-
- for name in self.areas():
+ aoi2D_scene = AOI2DScene.AOI2DScene()
- aoi3D = self[name]
+ for name, aoi3D in self.areas.items():
vertices_3D = numpy.array(aoi3D.vertices).astype('float32')
@@ -125,6 +108,6 @@ class AOI3DScene(AOIFeatures.AOIScene):
aoi2D = AOIFeatures.AreaOfInterest(vertices_2D)
- aoi2D_scene[name] = aoi2D
+ aoi2D_scene.append(name, aoi2D)
- return AOI2DScene.AOI2DScene(**aoi2D_scene)
+ return aoi2D_scene
diff --git a/src/argaze/AreaOfInterest/AOIFeatures.py b/src/argaze/AreaOfInterest/AOIFeatures.py
index 4788100..b78a104 100644
--- a/src/argaze/AreaOfInterest/AOIFeatures.py
+++ b/src/argaze/AreaOfInterest/AOIFeatures.py
@@ -1,43 +1,39 @@
#!/usr/bin/env python
+from dataclasses import dataclass, field
+
from argaze import DataStructures
-class AreaOfInterest(DataStructures.DictObject):
- """Define 2D/3D Area Of Interest
- ```
- {
- 'vertices': array of (x, y(,z)) tuples for each vertices of the area
- 'pointer': None or (x, y(,z)) tuple to set where the area is looked
- }
- ```
- """
-
- def __init__(self, vertices, pointer = None):
-
- super().__init__(type(self).__name__, **{'dimension': len(vertices[0]),'vertices': vertices, 'pointer': pointer})
-
-class AOIScene(DataStructures.DictObject):
- """Define AOI scene as:
- ```
- {
- 'dimension': 2 or 3,
- 'name 1': AOI 1,
- 'name 2': AOI 2,
- ...
- }
- ```
- """
-
- def __init__(self, **aois):
-
- # append dimension member
- aois['dimension'] = None
-
- super().__init__(type(self).__name__, **aois)
-
- def areas(self):
- """Get areas names."""
- return self.keys()[:-1]
+@dataclass
+class AreaOfInterest():
+ """Define 2D/3D Area Of Interest."""
+
+ dimension: int = field(init=False, default=None)
+ """number of the coordinates to code vertice or pointer positions."""
+
+ vertices: list(tuple())
+ """for each vertices of the area."""
+
+ pointer: tuple = None
+ """to set where the area is looked."""
+
+ def __post_init__(self):
+
+ self.dimension = len(self.vertices[0])
+
+@dataclass
+class AOIScene():
+ """Define 2D/3D AOI scene."""
+
+ dimension: int = field(init=False, default=None)
+ """dimension of the AOIs in scene."""
+
+ areas: dict = field(init=False, default_factory=dict)
+ """all aois in the scene."""
+
+ def append(self, name, aoi: AreaOfInterest):
+ """Add an aoi to the scene."""
+ self.areas[name] = aoi
class TimeStampedAOIScenes(DataStructures.TimeStampedBuffer):
"""Define timestamped buffer to store AOI scenes in time."""
diff --git a/src/argaze/GazeFeatures.py b/src/argaze/GazeFeatures.py
index dfbfc2d..a382ddc 100644
--- a/src/argaze/GazeFeatures.py
+++ b/src/argaze/GazeFeatures.py
@@ -1,5 +1,6 @@
#!/usr/bin/env python
+from dataclasses import dataclass
import math
from argaze import DataStructures
@@ -9,16 +10,12 @@ import numpy
FIXATION_MAX_DURATION = 1000
+@dataclass
class GazePosition(DataStructures.DictObject):
"""Define gaze position."""
- def __init__(self, x, y):
-
- super().__init__(type(self).__name__, **{'x': x, 'y': y})
-
- def __iter__(self):
- yield self.x
- yield self.y
+ x: float
+ y: float
class TimeStampedGazePositions(DataStructures.TimeStampedBuffer):
"""Define timestamped buffer to store gaze positions."""
@@ -30,12 +27,13 @@ class TimeStampedGazePositions(DataStructures.TimeStampedBuffer):
super().__setitem__(key, value)
+@dataclass
class Fixation(DataStructures.DictObject):
"""Define fixation"""
- def __init__(self, duration, dispersion, cx, cy):
-
- super().__init__(type(self).__name__, **{'duration': duration, 'dispersion': dispersion, 'centroid': [cx, cy]})
+ duration: float
+ dispersion: float
+ centroid: tuple((float, float))
class TimeStampedFixations(DataStructures.TimeStampedBuffer):
"""Define timestamped buffer to store fixations."""
@@ -177,7 +175,7 @@ class DispersionBasedFixationIdentifier(FixationIdentifier):
if duration > 0:
# return timestamp and fixation
- return ts_list[0], Fixation(duration, dispersion, cx, cy)
+ return ts_list[0], Fixation(duration, dispersion, (cx, cy))
return -1, None
@@ -193,12 +191,13 @@ class DispersionBasedFixationIdentifier(FixationIdentifier):
return -1, None
+@dataclass
class VisualScanStep(DataStructures.DictObject):
"""Define a visual scan step as a duration, the name of the area of interest and all its frames during the step."""
- def __init__(self, duration, aoi, frames = []):
-
- super().__init__(type(self).__name__, **{'duration': duration, 'aoi': aoi, 'frames': frames})
+ duration: float
+ aoi: str
+ frames: DataStructures.TimeStampedBuffer
class TimeStampedVisualScanSteps(DataStructures.TimeStampedBuffer):
"""Define timestamped buffer to store visual scan steps."""
@@ -230,9 +229,7 @@ class VisualScanGenerator():
if step == None:
continue
- if step.get_type() == 'VisualScanStep':
-
- visual_scan_steps[ts] = step
+ visual_scan_steps[ts] = step
return visual_scan_steps
@@ -260,9 +257,8 @@ class PointerBasedVisualScan(VisualScanGenerator):
#if not aoi_scene_current.looked:
# raise ValueError('TimeStampedAOIScenes must be looked using look_at method.')
- for name in aoi_scene_current.areas():
+ for name, aoi in aoi_scene_current.areas.items():
- aoi = aoi_scene_current[name]
aoi_looked = aoi.pointer != None
if aoi_looked:
diff --git a/src/argaze/TobiiGlassesPro2/TobiiVideo.py b/src/argaze/TobiiGlassesPro2/TobiiVideo.py
index e6ec064..f3c8c78 100644
--- a/src/argaze/TobiiGlassesPro2/TobiiVideo.py
+++ b/src/argaze/TobiiGlassesPro2/TobiiVideo.py
@@ -1,5 +1,6 @@
#!/usr/bin/env python
+from dataclasses import dataclass, field
import threading
import uuid
import time
@@ -12,12 +13,13 @@ import cv2 as cv
import av
import numpy
-class TobiiVideoFrame(DataStructures.DictObject):
+@dataclass
+class TobiiVideoFrame():
"""Define tobii video frame"""
- def __init__(self, matrix, width, height):
-
- super().__init__(type(self).__name__, **{'matrix': matrix, 'width': width, 'height': height})
+ matrix: list
+ width: int
+ height: int
class TobiiVideoSegment():
"""Handle Tobii Glasses Pro 2 segment video file."""
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 290bdb7..312e10d 100644
--- a/src/argaze/utils/export_tobii_segment_aruco_visual_scan.py
+++ b/src/argaze/utils/export_tobii_segment_aruco_visual_scan.py
@@ -87,7 +87,7 @@ def main():
# Create AOIs 3D scene
aoi3D_scene = AOI3DScene.AOI3DScene()
aoi3D_scene.load(args.aoi_scene)
- print(f'AOIs names: {aoi3D_scene.areas()}')
+ print(f'AOIs names: {aoi3D_scene.areas.keys()}')
# Create timestamped buffer to store AOIs scene in time
ts_aois_scenes = AOIFeatures.TimeStampedAOIScenes()
diff --git a/src/argaze/utils/live_tobii_aruco_aois.py b/src/argaze/utils/live_tobii_aruco_aois.py
index 1bc79eb..7642aaf 100644
--- a/src/argaze/utils/live_tobii_aruco_aois.py
+++ b/src/argaze/utils/live_tobii_aruco_aois.py
@@ -57,7 +57,7 @@ def main():
# Create AOIs 3D scene
aoi3D_scene = AOI3DScene.AOI3DScene()
aoi3D_scene.load(args.aoi_scene)
- print(f'AOIs names: {aoi3D_scene.areas()}')
+ print(f'AOIs names: {aoi3D_scene.areas.keys()}')
# Start streaming
tobii_controller.start_streaming()