From 58d7b5e637e64536ec488e34236776cea2c7621d Mon Sep 17 00:00:00 2001 From: Théo de la Hogue Date: Tue, 23 May 2023 09:36:25 +0200 Subject: Implementing and using NGram class. --- src/argaze/GazeAnalysis/NGram.py | 34 ++++++++++++++++++++++++++++++ src/argaze/GazeAnalysis/__init__.py | 2 +- src/argaze/utils/demo_gaze_features_run.py | 29 +++++++++++++++++++++++++ 3 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 src/argaze/GazeAnalysis/NGram.py diff --git a/src/argaze/GazeAnalysis/NGram.py b/src/argaze/GazeAnalysis/NGram.py new file mode 100644 index 0000000..b985d7d --- /dev/null +++ b/src/argaze/GazeAnalysis/NGram.py @@ -0,0 +1,34 @@ +#!/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 + +@dataclass +class AOIScanPathAnalyzer(GazeFeatures.AOIScanPathAnalyzer): + """Implementation of N-gram algorithm as ... + """ + + def __post_init__(self): + + pass + + def analyze(self, aoi_scan_path: GazeFeatures.AOIScanPathType, n: int) -> list: + """Analyze aoi scan.""" + + assert(len(aoi_scan_path) > 1) + + sequence = str(aoi_scan_path) + + ngrams = zip(*[sequence[i:] for i in range(n)]) + ngrams = [tuple([aoi_scan_path.get_letter_aoi(l) for l in ngram]) for ngram in ngrams] + + return {ngram : ngrams.count(ngram) for ngram in ngrams} diff --git a/src/argaze/GazeAnalysis/__init__.py b/src/argaze/GazeAnalysis/__init__.py index 0d5cd2c..d82969d 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', 'LempelZivComplexity'] \ No newline at end of file +__all__ = ['DispersionThresholdIdentification', 'VelocityThresholdIdentification', 'TransitionMatrix', 'CoefficientK', 'LempelZivComplexity', 'NGram'] \ 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 ce3a3f3..6384205 100644 --- a/src/argaze/utils/demo_gaze_features_run.py +++ b/src/argaze/utils/demo_gaze_features_run.py @@ -98,6 +98,10 @@ def main(): lzc_analysis = 0 enable_lzc_analysis = False + ngram_analyzer = NGram.AOIScanPathAnalyzer() + ngram_analysis = {} + enable_ngram_analysis = False + gaze_movement_lock = threading.Lock() # Init timestamp @@ -116,6 +120,7 @@ def main(): nonlocal raw_cK_analysis nonlocal aoi_cK_analysis nonlocal lzc_analysis + nonlocal ngram_analysis # Edit millisecond timestamp data_ts = int((time.time() - start_ts) * 1e3) @@ -196,6 +201,10 @@ def main(): lzc_analysis = lzc_analyzer.analyze(aoi_scan_path) + if enable_ngram_analysis: + + ngram_analysis = ngram_analyzer.analyze(aoi_scan_path, 3) + except GazeFeatures.AOIScanStepError as e: print(f'Error on {e.aoi} step:', e) @@ -266,6 +275,10 @@ def main(): 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) + # Write N-Gram help + on_off = 'on' if enable_ngram_analysis else 'off' + display_hide = 'hide' if enable_ngram_analysis else 'display' + cv2.putText(aoi_matrix, f'Tri-Gram: {on_off} (Press \'n\' key to {display_hide})', (20, 240), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 255) if enable_ngram_analysis else (255, 255, 255), 1, cv2.LINE_AA) # Check fixation identification if gaze_movement_identifier[identification_mode].current_fixation != None: @@ -354,6 +367,17 @@ def main(): 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) + + # Write N-Gram + if enable_ngram_analysis: + + start = window_size[1] - ((len(ngram_analysis) + 1) * 40) + cv2.putText(aoi_matrix, f'Tri-Gram:', (window_size[0]-700, start-40), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 255), 1, cv2.LINE_AA) + + for i, (ngram, count) in enumerate(ngram_analysis.items()): + + trigram = f'{ngram[0]}>{ngram[1]}>{ngram[2]}' + cv2.putText(aoi_matrix, f'{trigram}: {count}', (window_size[0]-700, start+(i*40)), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 255), 1, cv2.LINE_AA) # Unlock gaze movement identification gaze_movement_lock.release() @@ -401,6 +425,11 @@ def main(): enable_lzc_analysis = not enable_lzc_analysis + # Enable ngram analysis with 'n' key + if key_pressed == 110: + + enable_ngram_analysis = not enable_ngram_analysis + # Stop calibration by pressing 'Esc' key if cv2.waitKey(10) == 27: break -- cgit v1.1