aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--setup.py2
-rw-r--r--src/argaze/GazeAnalysis/LempelZivComplexity.py55
-rw-r--r--src/argaze/GazeAnalysis/__init__.py2
-rw-r--r--src/argaze/utils/demo_gaze_features_run.py31
4 files changed, 84 insertions, 6 deletions
diff --git a/setup.py b/setup.py
index eb81438..5c9973c 100644
--- a/setup.py
+++ b/setup.py
@@ -35,7 +35,7 @@ setup(
packages=find_packages(where='src'),
python_requires='>=3.11',
- install_requires=['opencv-python>=4.7.0', 'opencv-contrib-python>=4.7.0', 'numpy', 'pandas', 'matplotlib', 'shapely'],
+ install_requires=['opencv-python>=4.7.0', 'opencv-contrib-python>=4.7.0', 'numpy', 'pandas', 'matplotlib', 'shapely', 'lempel_ziv_complexity'],
project_urls={
'Bug Reports': 'https://git.recherche.enac.fr/projects/argaze/issues',
diff --git a/src/argaze/GazeAnalysis/LempelZivComplexity.py b/src/argaze/GazeAnalysis/LempelZivComplexity.py
new file mode 100644
index 0000000..b8d14ca
--- /dev/null
+++ b/src/argaze/GazeAnalysis/LempelZivComplexity.py
@@ -0,0 +1,55 @@
+#!/usr/bin/env python
+
+""" """
+
+__author__ = "Théo de la Hogue"
+__credits__ = []
+__copyright__ = "Copyright 2023, Ecole Nationale de l'Aviation Civile (ENAC)"
+__license__ = "BSD"
+
+from typing import TypeVar, Tuple, Any
+from dataclasses import dataclass, field
+
+from argaze import GazeFeatures
+
+from lempel_ziv_complexity import lempel_ziv_complexity
+
+@dataclass
+class AOIScanPathAnalyzer(GazeFeatures.AOIScanPathAnalyzer):
+ """Implementation of Lempel ziv complexity algorithm as described in Lounis paper.
+ """
+
+ def __post_init__(self):
+
+ pass
+
+ def analyze(self, aoi_scan_path: GazeFeatures.AOIScanPathType) -> Any:
+ """Analyze aoi scan."""
+
+ assert(len(aoi_scan_path) > 1)
+
+ self.__index = ord('A')
+ aoi_letter = {}
+
+ def __get_letter(aoi):
+
+ try :
+
+ return aoi_letter[aoi_scan_step.aoi]
+
+ except KeyError:
+
+ letter = chr(self.__index)
+ aoi_letter[aoi_scan_step.aoi] = letter
+ self.__index += 1
+ return letter
+
+ # Convet each AOI name into a single char
+ sequence = ''
+ for aoi_scan_step in aoi_scan_path:
+
+ sequence += __get_letter(aoi_scan_step.aoi)
+
+ print(sequence)
+
+ return lempel_ziv_complexity(sequence)
diff --git a/src/argaze/GazeAnalysis/__init__.py b/src/argaze/GazeAnalysis/__init__.py
index a980ed3..0d5cd2c 100644
--- a/src/argaze/GazeAnalysis/__init__.py
+++ b/src/argaze/GazeAnalysis/__init__.py
@@ -2,4 +2,4 @@
.. include:: README.md
"""
__docformat__ = "restructuredtext"
-__all__ = ['DispersionThresholdIdentification', 'VelocityThresholdIdentification', 'TransitionMatrix', 'CoefficientK'] \ No newline at end of file
+__all__ = ['DispersionThresholdIdentification', 'VelocityThresholdIdentification', 'TransitionMatrix', 'CoefficientK', 'LempelZivComplexity'] \ No newline at end of file
diff --git a/src/argaze/utils/demo_gaze_features_run.py b/src/argaze/utils/demo_gaze_features_run.py
index 5ab3ed0..3326bc8 100644
--- a/src/argaze/utils/demo_gaze_features_run.py
+++ b/src/argaze/utils/demo_gaze_features_run.py
@@ -89,13 +89,15 @@ def main():
raw_cK_analyzer = CoefficientK.ScanPathAnalyzer()
raw_cK_analysis = 0
-
aoi_cK_analyzer = CoefficientK.AOIScanPathAnalyzer()
aoi_cK_analysis = 0
-
ck_mode = 'raw'
enable_ck_analysis = False
+ lzc_analyzer = LempelZivComplexity.AOIScanPathAnalyzer()
+ lzc_analysis = 0
+ enable_lzc_analysis = False
+
gaze_movement_lock = threading.Lock()
# Init timestamp
@@ -113,6 +115,7 @@ def main():
nonlocal tm_density
nonlocal raw_cK_analysis
nonlocal aoi_cK_analysis
+ nonlocal lzc_analysis
# Edit millisecond timestamp
data_ts = int((time.time() - start_ts) * 1e3)
@@ -189,6 +192,10 @@ def main():
aoi_cK_analysis = aoi_cK_analyzer.analyze(aoi_scan_path)
+ if enable_lzc_analysis:
+
+ lzc_analysis = lzc_analyzer.analyze(aoi_scan_path)
+
except GazeFeatures.AOIScanStepError as e:
print(f'Error on {e.aoi} step:', e)
@@ -254,6 +261,12 @@ def main():
display_hide = 'hide' if enable_ck_analysis else 'display'
cv2.putText(aoi_matrix, f'coefficient K: {on_off} (Press \'k\' key to {display_hide})', (20, 160), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 255) if enable_ck_analysis else (255, 255, 255), 1, cv2.LINE_AA)
+ # Write LZC help
+ on_off = 'on' if enable_lzc_analysis else 'off'
+ display_hide = 'hide' if enable_lzc_analysis else 'display'
+ cv2.putText(aoi_matrix, f'Lempel-Ziv complexity: {on_off} (Press \'z\' key to {display_hide})', (20, 200), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 255) if enable_lzc_analysis else (255, 255, 255), 1, cv2.LINE_AA)
+
+
# Check fixation identification
if gaze_movement_identifier[identification_mode].current_fixation != None:
@@ -337,6 +350,11 @@ def main():
cv2.putText(aoi_matrix, f'AOI: Focal attention', (20, window_size[1]-80), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 0), 1, cv2.LINE_AA)
+ # Write LZC
+ if enable_lzc_analysis:
+
+ cv2.putText(aoi_matrix, f'Lempel-Ziv complexity: {lzc_analysis}', (20, window_size[1]-200), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 255), 1, cv2.LINE_AA)
+
# Unlock gaze movement identification
gaze_movement_lock.release()
@@ -345,8 +363,8 @@ def main():
key_pressed = cv2.waitKey(10)
- #if key_pressed != -1:
- # print(key_pressed)
+ if key_pressed != -1:
+ print(key_pressed)
# Switch identification mode with 'm' key
if key_pressed == 109:
@@ -378,6 +396,11 @@ def main():
enable_tm_analysis = not enable_tm_analysis
+ # Enable LZC analysis with 'z' key
+ if key_pressed == 122:
+
+ enable_lzc_analysis = not enable_lzc_analysis
+
# Stop calibration by pressing 'Esc' key
if cv2.waitKey(10) == 27:
break