aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorThéo de la Hogue2024-07-03 17:14:43 +0200
committerThéo de la Hogue2024-07-03 17:14:43 +0200
commit8fc18a434da400f0fe82707e23838d6cc40a787d (patch)
tree9e42c9f7edb9364e9a0afedab30194820987a907 /src
parent7b82b09e87d1475acf5040c67323421699a3ad06 (diff)
downloadargaze-8fc18a434da400f0fe82707e23838d6cc40a787d.zip
argaze-8fc18a434da400f0fe82707e23838d6cc40a787d.tar.gz
argaze-8fc18a434da400f0fe82707e23838d6cc40a787d.tar.bz2
argaze-8fc18a434da400f0fe82707e23838d6cc40a787d.tar.xz
Rewriting eye tracking context and gaze analysis sections.
Diffstat (limited to 'src')
-rw-r--r--src/argaze/ArFeatures.py4
-rw-r--r--src/argaze/utils/contexts/OpenCV.py66
-rw-r--r--src/argaze/utils/contexts/Random.py25
-rw-r--r--src/argaze/utils/demo/opencv_cursor_context.json6
-rw-r--r--src/argaze/utils/demo/opencv_window_context.json6
5 files changed, 61 insertions, 46 deletions
diff --git a/src/argaze/ArFeatures.py b/src/argaze/ArFeatures.py
index aaac6ed..8d9eceb 100644
--- a/src/argaze/ArFeatures.py
+++ b/src/argaze/ArFeatures.py
@@ -1231,7 +1231,7 @@ class ArCamera(ArFrame):
self.__projection_cache_writer.write( (timestamp, exception) )
- def _read_projection_cache(self, timestamp: int|float):
+ def _read_projection_cache(self, timestamp: int|float) -> bool:
"""Read layers aoi scene from the projection cache.
Parameters:
@@ -1504,7 +1504,7 @@ DEFAULT_ARCONTEXT_IMAGE_PARAMETERS = {
class ArContext(DataFeatures.PipelineStepObject):
"""
- Defines abstract Python context manager to handle incoming gaze data before passing them to a processing pipeline.
+ Defines abstract Python context manager to handle eye tracker data before passing them to a processing pipeline.
"""
# noinspection PyMissingConstructor
diff --git a/src/argaze/utils/contexts/OpenCV.py b/src/argaze/utils/contexts/OpenCV.py
index 111ed8e..273705a 100644
--- a/src/argaze/utils/contexts/OpenCV.py
+++ b/src/argaze/utils/contexts/OpenCV.py
@@ -26,7 +26,12 @@ import cv2
from argaze import ArFeatures, DataFeatures
-class Window(ArFeatures.LiveProcessingContext):
+class Cursor(ArFeatures.ArContext):
+ """Process cursor position over OpenCV window.
+
+ !!! warning
+ It is assumed that an OpenCV window with the same name than the context is used to display context's pipeline image.
+ """
@DataFeatures.PipelineStepInit
def __init__(self, **kwargs):
@@ -37,13 +42,13 @@ class Window(ArFeatures.LiveProcessingContext):
@DataFeatures.PipelineStepEnter
def __enter__(self):
- logging.info('OpenCV window context starts...')
+ logging.info('OpenCV.Cursor context starts...')
- # Create a window to display context
+ # Create a window
cv2.namedWindow(self.name, cv2.WINDOW_AUTOSIZE)
# Init timestamp
- self.__start_time = time.time()
+ self._start_time = time.time()
# Attach mouse event callback to window
cv2.setMouseCallback(self.name, self.__on_mouse_event)
@@ -53,7 +58,7 @@ class Window(ArFeatures.LiveProcessingContext):
@DataFeatures.PipelineStepExit
def __exit__(self, exception_type, exception_value, exception_traceback):
- logging.info('OpenCV window context stops...')
+ logging.info('OpenCV.Cursor context stops...')
# Delete window
cv2.destroyAllWindows()
@@ -61,20 +66,24 @@ class Window(ArFeatures.LiveProcessingContext):
def __on_mouse_event(self, event, x, y, flags, param):
"""Process pointer position."""
- logging.debug('Window.on_mouse_event %i %i', x, y)
+ logging.debug('OpenCV.Cursor.on_mouse_event %i %i', x, y)
if not self.is_paused():
# Process timestamped gaze position
- self._process_gaze_position(timestamp = int((time.time() - self.__start_time) * 1e3), x = x, y = y)
+ self._process_gaze_position(timestamp = int((time.time() - self._start_time) * 1e3), x = x, y = y)
-class Movie(ArFeatures.PostProcessingContext):
+class Movie(Cursor):
+ """Process movie images and cursor position over OpenCV window.
+ !!! warning
+ It is assumed that an OpenCV window with the same name than the context is used to display context's pipeline image.
+ """
@DataFeatures.PipelineStepInit
def __init__(self, **kwargs):
- # Init PostProcessingContext class
+ # Init Cursor class
super().__init__()
# Init private attributes
@@ -109,16 +118,10 @@ class Movie(ArFeatures.PostProcessingContext):
@DataFeatures.PipelineStepEnter
def __enter__(self):
- logging.info('OpenCV movie context starts...')
-
- # Create a window to display context
- cv2.namedWindow(self.name, cv2.WINDOW_AUTOSIZE)
-
- # Init timestamp
- self.__start_time = time.time()
+ logging.info('OpenCV.Movie context starts...')
- # Attach mouse event callback to window
- cv2.setMouseCallback(self.name, self.__on_mouse_event)
+ # Enter in Cursor context
+ super().__enter__()
# Open reading thread
self.__reading_thread = threading.Thread(target=self.__read)
@@ -174,33 +177,23 @@ class Movie(ArFeatures.PostProcessingContext):
@DataFeatures.PipelineStepExit
def __exit__(self, exception_type, exception_value, exception_traceback):
- logging.info('OpenCV movie context stops...')
+ logging.info('OpenCV.Movie context stops...')
+
+ # Exit from Cursor context
+ super().__exit__(exception_type, exception_value, exception_traceback)
# Close data stream
- self._stop_event.set()
+ self.stop()
# Stop reading thread
threading.Thread.join(self.__reading_thread)
- # Delete window
- cv2.destroyAllWindows()
-
- def __on_mouse_event(self, event, x, y, flags, param):
- """Process pointer position."""
-
- logging.debug('Window.on_mouse_event %i %i', x, y)
-
- if not self.is_paused():
-
- # Process timestamped gaze position
- self._process_gaze_position(timestamp = int((time.time() - self.__start_time) * 1e3), x = x, y = y)
-
def refresh(self):
"""Refresh current frame."""
self.__refresh = True
def previous(self):
-
+ """Go to previous frame."""
self.__next_image_index -= 1
# Clip image index
@@ -208,6 +201,7 @@ class Movie(ArFeatures.PostProcessingContext):
self.__next_image_index = 0
def next(self):
+ """Go to next frame."""
self.__next_image_index += 1
@@ -217,13 +211,13 @@ class Movie(ArFeatures.PostProcessingContext):
@property
def duration(self) -> int|float:
- """Get data duration."""
+ """Get movie duration."""
return self.__movie_length / self.__movie_fps
@property
def progression(self) -> float:
- """Get data processing progression between 0 and 1."""
+ """Get movie processing progression between 0 and 1."""
if self.__current_image_index is not None:
diff --git a/src/argaze/utils/contexts/Random.py b/src/argaze/utils/contexts/Random.py
index 29b9830..c7b2187 100644
--- a/src/argaze/utils/contexts/Random.py
+++ b/src/argaze/utils/contexts/Random.py
@@ -71,8 +71,29 @@ class GazePositionGenerator(ArFeatures.ArContext):
# Edit millisecond timestamp
timestamp = int((time.time() - start_time) * 1e3)
- self.__x += random.randint(-10, 10)
- self.__y += random.randint(-10, 10)
+ # Random saccade
+ if random.randint(0, 100) == 0:
+
+ rand_x = random.randint(0, int(self.__range[0] / 2))
+ rand_y = random.randint(0, int(self.__range[1] / 2))
+
+ self.__x += random.randint(-rand_x, rand_x)
+ self.__y += random.randint(-rand_y, rand_y)
+
+ # Random fixation
+ else:
+
+ self.__x += random.randint(-1, 1)
+ self.__y += random.randint(-1, 1)
+
+ # Clip position
+ if self.__x < 0 or self.__x > self.__range[0]:
+
+ self.__x = int(self.range[0] / 2)
+
+ if self.__y < 0 or self.__y > self.__range[1]:
+
+ self.__y = int(self.range[1] / 2)
logging.debug('> timestamp=%i, x=%i, y=%i', timestamp, self.__x, self.__y)
diff --git a/src/argaze/utils/demo/opencv_cursor_context.json b/src/argaze/utils/demo/opencv_cursor_context.json
new file mode 100644
index 0000000..659ffd6
--- /dev/null
+++ b/src/argaze/utils/demo/opencv_cursor_context.json
@@ -0,0 +1,6 @@
+{
+ "argaze.utils.contexts.OpenCV.Cursor" : {
+ "name": "OpenCV cursor",
+ "pipeline": "gaze_analysis_pipeline.json"
+ }
+} \ No newline at end of file
diff --git a/src/argaze/utils/demo/opencv_window_context.json b/src/argaze/utils/demo/opencv_window_context.json
deleted file mode 100644
index d589665..0000000
--- a/src/argaze/utils/demo/opencv_window_context.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "argaze.utils.contexts.OpenCV.Window" : {
- "name": "OpenCV Window",
- "pipeline": "gaze_analysis_pipeline.json"
- }
-} \ No newline at end of file