Skip to content

Commit d18260c

Browse files
committed
initial commit for v3 (not yet ready)
main change is that all functionality is moved to glassesTools (except the make_video() function) logic has also changed, offset from gaze data to target is now only computed for matched targets, not for all gaze samples and all targets, so much quicker and not generating large mostly useless file fixed some bugs in the process
1 parent 2421f14 commit d18260c

27 files changed

+248
-1288
lines changed

README.md

Lines changed: 26 additions & 43 deletions
Large diffs are not rendered by default.

requirements.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
glassesTools[GUI]==1.15.0 # pulls in various other dependencies such as imgui_bundle, matplotlib, numpy, opencv, pandas, polars
2-
I2MC>=2.2.6
32
aiosqlite
43
uvloop ; sys_platform != "win32"
54
pyobjc-framework-Cocoa ; sys_platform == "darwin"

src/glassesValidator/GUI/_impl/callbacks.py

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,15 @@
1010

1111
from glassesTools import async_thread, platform, recording
1212
from glassesTools.eyetracker import EyeTracker, eye_tracker_names
13+
eye_tracker_names = [e for e in eye_tracker_names if e!=EyeTracker.Generic.value]
1314
from glassesTools.gui import msg_box, recording_table, utils as gui_utils
15+
from glassesTools.validation import config, DataQualityType, export
1416

1517
from .structs import JobDescription, Recording
1618
from . import globals, db, gui, process_pool
1719
from ...utils import Task, get_next_task
1820
from ...preprocess import make_fs_dirname
19-
from ... import config, preprocess, process, utils as gv_utils
20-
from ...process import DataQualityType, collect_data_quality, summarize_and_store_data_quality
21+
from ... import preprocess, process, utils as gv_utils
2122

2223

2324

@@ -64,7 +65,7 @@ async def deploy_config(project_path: str|pathlib.Path, config_dir: str):
6465
gui_utils.push_popup(globals, msg_box.msgbox, "Deploy configuration", f"The folder {conf_dir} already exist. Do you want to deploy a configuration to this folder,\npotentially overwriting any configuration that is already there?", msg_box.MsgBox.warn, buttons)
6566

6667
async def deploy_poster_pdf(dir: str|pathlib.Path):
67-
config.poster.deploy_default_pdf(dir)
68+
config.plane.deploy_default_pdf(dir)
6869

6970
async def remove_recording_working_dir(rec: Recording):
7071
if rec.working_directory and rec.working_directory.is_dir():
@@ -191,18 +192,18 @@ async def process_recording(rec: Recording, task: Task=None, chain=True):
191192
args = tuple()
192193
kwargs['rec_info'] = rec
193194
kwargs['copy_scene_video'] = globals.settings.copy_scene_video
194-
case Task.Coded | Task.Markers_Detected | Task.Gaze_Tranformed_To_Poster | Task.Target_Offsets_Computed | Task.Fixation_Intervals_Determined | Task.Data_Quality_Calculated | Task.Make_Video:
195+
case Task.Coded | Task.Markers_Detected | Task.Gaze_Tranformed_To_Plane | Task.Fixations_Classified | Task.Fixation_Assigned | Task.Data_Quality_Calculated | Task.Make_Video:
195196
match task:
196197
case Task.Coded:
197198
fun = process.code_marker_interval
198199
case Task.Markers_Detected:
199200
fun = process.detect_markers
200-
case Task.Gaze_Tranformed_To_Poster:
201-
fun = process.gaze_to_poster
202-
case Task.Target_Offsets_Computed:
203-
fun = process.compute_offsets_to_targets
204-
case Task.Fixation_Intervals_Determined:
205-
fun = process.determine_fixation_intervals
201+
case Task.Gaze_Tranformed_To_Plane:
202+
fun = process.gaze_to_plane
203+
case Task.Fixations_Classified:
204+
fun = process.classify_fixations
205+
case Task.Fixation_Assigned:
206+
fun = process.assign_fixations
206207
kwargs['do_global_shift'] = globals.settings.fix_assign_do_global_shift
207208
kwargs['max_dist_fac'] = globals.settings.fix_assign_max_dist_fac
208209
case Task.Data_Quality_Calculated:
@@ -267,7 +268,7 @@ async def cancel_processing_recordings(ids: list[int]):
267268
async def export_data_quality(ids: list[int]):
268269
# 1. collect all data quality from the selected recordings
269270
rec_dirs = [globals.recordings[id].working_directory for id in ids]
270-
df, default_dq_type, targets = collect_data_quality(rec_dirs)
271+
df, default_dq_type, targets = export.collect_data_quality(rec_dirs)
271272
if df is None:
272273
gui_utils.push_popup(globals, msg_box.msgbox, "Export error", "There is no data quality for the selected recordings. Did you code any validation intervals (see manual)?", msg_box.MsgBox.error)
273274
return
@@ -317,4 +318,4 @@ def show_config_popup():
317318
async def _export_data_quality(df: pd.DataFrame, pop_data: dict):
318319
dq_types = [dq for i,dq in enumerate(pop_data['dq_types']) if pop_data['dq_types_sel'][i]]
319320
targets = [t for i,t in enumerate(pop_data['targets']) if pop_data['targets_sel'][i]]
320-
summarize_and_store_data_quality(df, globals.project_path, dq_types, targets, pop_data['targets_avg'], pop_data['include_data_loss'])
321+
export.summarize_and_store_data_quality(df, globals.project_path, dq_types, targets, pop_data['targets_avg'], pop_data['include_data_loss'])

src/glassesValidator/GUI/_impl/db.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ async def connect():
147147
"start_time": f'INTEGER DEFAULT 0',
148148
"duration": f'INTEGER DEFAULT 0',
149149
"eye_tracker": f'TEXT DEFAULT "{EyeTracker.Unknown.value}"',
150+
"eye_tracker_name": f'TEXT DEFAULT ""',
150151
"project": f'TEXT DEFAULT ""',
151152
"participant": f'TEXT DEFAULT ""',
152153
"firmware_version": f'TEXT DEFAULT ""',

src/glassesValidator/GUI/_impl/gui.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import concurrent.futures
2-
from typing import Tuple
32
import configparser
43
import platform
54
import asyncio
@@ -15,17 +14,18 @@
1514
import io
1615

1716
from glassesTools.eyetracker import EyeTracker, eye_tracker_names
17+
eye_tracker_names = [e for e in eye_tracker_names if e!=EyeTracker.Generic.value]
1818
from glassesTools.gui import file_picker, msg_box, recording_table, utils as gui_utils
1919
from glassesTools.gui.utils import my_checkbox, my_combo, handle_popup_stack
2020
from glassesTools.utils import hex_to_rgba_0_1
2121
from glassesTools import async_thread, platform as pltfrm, recording as gt_recording
22+
from glassesTools.validation import DataQualityType, get_DataQualityType_explanation
2223
import glassesTools
2324

2425
from .structs import DefaultStyleDark, DefaultStyleLight, Filter, FilterMode, ProcessState, Recording, TaskSimplified, filter_mode_names, get_simplified_task_state, simplified_task_names
2526
from . import globals, callbacks, db, process_pool, utils
2627
from .. import _general_imgui
2728
from ...utils import Task, Status, get_task_name_friendly, get_next_task, task_names, get_last_finished_step, get_recording_status, update_recording_status
28-
from ...process import DataQualityType, get_DataQualityType_explanation
2929

3030
imgui.io = None
3131
imgui.style = None
@@ -620,11 +620,11 @@ def update_recordings(self, subset=None):
620620
if not subset:
621621
subset = globals.recordings
622622
for recid in subset:
623-
rec_info = gt_recording.Recording.load_from_json(globals.recordings[recid].working_directory)
624-
if rec_info.duration!=globals.recordings[recid].duration:
625-
globals.recordings[recid].duration = rec_info.duration
626-
async_thread.run(db.update_recording(globals.recordings[recid], "duration"))
627623
if globals.recordings[recid].task not in [Task.Not_Imported, Task.Unknown]:
624+
rec_info = gt_recording.Recording.load_from_json(globals.recordings[recid].working_directory)
625+
if rec_info.duration!=globals.recordings[recid].duration:
626+
globals.recordings[recid].duration = rec_info.duration
627+
async_thread.run(db.update_recording(globals.recordings[recid], "duration"))
628628
last_task = get_last_finished_step(get_recording_status(globals.recordings[recid].working_directory))
629629
globals.recordings[recid].task = last_task
630630
async_thread.run(db.update_recording(globals.recordings[recid], "task"))
@@ -1632,7 +1632,7 @@ def draw_sidebar(self):
16321632
imgui.text("Use global shift:")
16331633
imgui.same_line()
16341634
gui_utils.draw_hover_text(
1635-
"If selected, for each validation interval the mean position will be removed from the gaze data and the targets, removing any overall shift of the data. This improves the matching of fixations to targets when there is a significant overall offset in the data. It may fail (backfire) if there are data samples far outside the range of the validation targets, or if there is no data for some targets."
1635+
"If selected, for each validation interval the median position will be removed from the gaze data and mean from the targets, removing any overall shift of the data. This improves the matching of fixations to targets when there is a significant overall offset in the data. It may fail (backfire) if there are data samples far outside the range of the validation targets, or if there is no data for some targets."
16361636
)
16371637
imgui.table_next_column()
16381638
imgui.set_cursor_pos_x(imgui.get_cursor_pos_x() + checkbox_offset)

src/glassesValidator/GUI/_impl/structs.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ def get_simplified_task_state(task: Task):
7676
case Task.Imported:
7777
return TaskSimplified.Imported
7878
# after stage 2 / during stage 3
79-
case Task.Coded | Task.Markers_Detected | Task.Gaze_Tranformed_To_Poster | Task.Target_Offsets_Computed | Task.Fixation_Intervals_Determined:
79+
case Task.Coded | Task.Markers_Detected | Task.Gaze_Tranformed_To_Plane | Task.Fixations_Classified | Task.Fixation_Assigned:
8080
return TaskSimplified.Coded
8181
# after stage 3:
8282
case Task.Data_Quality_Calculated:

src/glassesValidator/__init__.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
# -*- coding: utf-8 -*-
22

3-
from . import config
43
from . import GUI
54
from . import preprocess
65
from . import process

src/glassesValidator/config/__init__.py

Lines changed: 0 additions & 70 deletions
This file was deleted.

src/glassesValidator/config/markerPositions.csv

Lines changed: 0 additions & 37 deletions
This file was deleted.

src/glassesValidator/config/poster/__init__.py

Lines changed: 0 additions & 124 deletions
This file was deleted.

0 commit comments

Comments
 (0)