Skip to content

Commit d0a2ade

Browse files
committed
update to latest glassesTools
1 parent ec41b56 commit d0a2ade

File tree

6 files changed

+49
-34
lines changed

6 files changed

+49
-34
lines changed

requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
glassesTools[GUI]~=1.18.0 # pulls in various other dependencies such as imgui_bundle, matplotlib, numpy, opencv, pandas, polars
1+
glassesTools[GUI]~=1.23.1 # pulls in various other dependencies such as imgui_bundle, matplotlib, numpy, opencv, pandas, polars
22
aiosqlite
33
uvloop ; sys_platform != "win32"
44
pyobjc-framework-Cocoa ; sys_platform == "darwin"

src/glassesValidator/process/b_codeMarkerInterval.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
if isMacOS:
1111
import AppKit
1212

13-
from glassesTools import annotation, gaze_headref, gaze_worldref, naming, ocv, plane, propagating_thread, recording, timestamps
13+
from glassesTools import annotation, gaze_headref, gaze_worldref, naming, ocv, pose, propagating_thread, recording, timestamps
1414
from glassesTools.gui import video_player
1515
from glassesTools.validation import config, Plane as ValidationPlane
1616

@@ -62,7 +62,7 @@ def do_the_work(working_dir, config_dir, gui: video_player.GUI, show_plane):
6262
hasPlanePose = False
6363
if (working_dir / 'pose.tsv').is_file():
6464
try:
65-
poses = plane.read_dict_from_file(working_dir / 'pose.tsv')
65+
poses = pose.read_dict_from_file(working_dir / 'pose.tsv')
6666
hasPlanePose = True
6767
except:
6868
# ignore when file can't be read or is empty

src/glassesValidator/process/c_detectMarkers.py

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import pathlib
22

3-
from glassesTools import annotation, aruco, naming, plane, propagating_thread, recording
3+
from glassesTools import annotation, aruco, naming, pose, propagating_thread, recording
44
from glassesTools.gui import video_player
55
from glassesTools.validation import config, Plane as ValidationPlane
66

@@ -20,6 +20,7 @@ def process(working_dir, config_dir=None, show_visualization=False, show_rejecte
2020
if show_visualization:
2121
gui = video_player.GUI(use_thread = False)
2222
gui.add_window(working_dir.name)
23+
gui.set_interruptible(False)
2324
gui.set_show_controls(True)
2425
gui.set_show_play_percentage(True)
2526
gui.set_show_annotation_label(False)
@@ -52,16 +53,19 @@ def do_the_work(working_dir, config_dir, gui, show_rejected_markers):
5253
# get video file to process
5354
in_video = recInfo.get_scene_video_path()
5455

55-
# set up pose estimator and run it
56-
estimator = aruco.PoseEstimator(in_video, working_dir / naming.frame_timestamps_fname, working_dir / naming.scene_camera_calibration_fname)
57-
estimator.add_plane('validate',
58-
{'plane': val_plane, 'aruco_params': {'markerBorderBits': validationSetup['markerBorderBits']}, 'min_num_markers': validationSetup['minNumMarkers']},
59-
analyzeFrames)
56+
# set up pose estimator
57+
estimator = pose.Estimator(in_video, working_dir / naming.frame_timestamps_fname, working_dir / naming.scene_camera_calibration_fname)
58+
# first, register all ArUco planes and individual markers with ArUco manager, which
59+
# will then wrap their detection and register them with the pose estimator
60+
aruco_manager = aruco.Manager()
61+
aruco_manager.add_plane('validate', val_plane.get_plane_setup(), analyzeFrames)
62+
aruco_manager.consolidate_setup()
63+
aruco_manager.register_with_estimator(estimator)
6064
estimator.attach_gui(gui, {annotation.Event.Validate: [i for iv in analyzeFrames for i in iv]})
6165
if gui is not None:
6266
estimator.show_rejected_markers = show_rejected_markers
6367
poses, _, _ = estimator.process_video()
6468

65-
plane.write_list_to_file(poses['validate'], working_dir/'pose.tsv', skip_failed=True)
69+
pose.write_list_to_file(poses['validate'], working_dir/'pose.tsv', skip_failed=True)
6670

6771
utils.update_recording_status(working_dir, utils.Task.Markers_Detected, utils.Status.Finished)

src/glassesValidator/process/d_gazeToPlane.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import pathlib
22

3-
from glassesTools import annotation, gaze_headref, gaze_worldref, naming, ocv, plane, propagating_thread, recording
3+
from glassesTools import annotation, gaze_headref, gaze_worldref, naming, ocv, pose, propagating_thread, recording
44
from glassesTools.gui import video_player, worldgaze
55
from glassesTools.validation import config, Plane as ValidationPlane
66

@@ -38,7 +38,7 @@ def do_the_work(working_dir, config_dir, gui, show_plane, show_only_intervals):
3838
utils.update_recording_status(working_dir, utils.Task.Gaze_Tranformed_To_Plane, utils.Status.Running)
3939

4040
# get camera calibration info
41-
cameraParams = ocv.CameraParams.read_from_file(working_dir / naming.scene_camera_calibration_fname)
41+
cameraParams = ocv.CameraParams.read_from_file(working_dir / naming.scene_camera_calibration_fname)
4242

4343
# get interval coded to be analyzed, if any
4444
analyzeFrames = utils.readMarkerIntervalsFile(working_dir / "markerInterval.tsv")
@@ -47,7 +47,7 @@ def do_the_work(working_dir, config_dir, gui, show_plane, show_only_intervals):
4747
head_gazes = gaze_headref.read_dict_from_file(working_dir / naming.gaze_data_fname, episodes=analyzeFrames if not gui or show_only_intervals else None)[0]
4848

4949
# Read camera pose w.r.t. plane
50-
poses = plane.read_dict_from_file(working_dir / 'pose.tsv', episodes=analyzeFrames if not gui or show_only_intervals else None)
50+
poses = pose.read_dict_from_file(working_dir / 'pose.tsv', episodes=analyzeFrames if not gui or show_only_intervals else None)
5151

5252
# transform
5353
plane_gazes = gaze_worldref.from_head(poses, head_gazes, cameraParams)

src/glassesValidator/process/f_assignFixations.py

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import pathlib
22
import numpy as np
33

4-
from glassesTools.validation import config, assign_fixations, Plane as ValidationPlane
4+
from glassesTools.validation import config, assign_intervals, Plane as ValidationPlane
55

66
from .. import utils
77

@@ -30,13 +30,29 @@ def process(working_dir, config_dir=None, do_global_shift=True, max_dist_fac=.5)
3030
[validation_plane.bbox[1]-validation_plane.marker_size, validation_plane.bbox[3]+validation_plane.marker_size]]
3131
for idx,_ in enumerate(analyzeFrames):
3232
fix_file = working_dir / f'fixations_interval_{idx+1:02d}.tsv'
33-
assign_fixations.distance(targets,
34-
fix_file,
35-
working_dir,
36-
filename_stem='fixationAssignment',
37-
iteration=idx,
38-
background_image=(validation_plane.get_ref_image(as_RGB=True),
39-
np.array([validation_plane.bbox[x] for x in (0,2,3,1)])),
40-
plot_limits=plot_limits)
33+
selected_intervals, other_intervals = \
34+
assign_intervals.distance(targets,
35+
fix_file,
36+
do_global_shift=do_global_shift,
37+
max_dist_fac=max_dist_fac)
38+
39+
# plot output
40+
assign_intervals.plot(selected_intervals,
41+
other_intervals,
42+
targets,
43+
working_dir/'gazePlane.tsv',
44+
analyzeFrames[idx],
45+
working_dir,
46+
filename_stem='fixationAssignment',
47+
iteration=idx,
48+
background_image=(validation_plane.get_ref_image(as_RGB=True),
49+
np.array([validation_plane.bbox[x] for x in (0,2,3,1)])),
50+
plot_limits=plot_limits)
51+
52+
# store output to file
53+
assign_intervals.to_tsv(selected_intervals,
54+
working_dir,
55+
filename_stem=f'fixationAssignment',
56+
iteration=idx)
4157

4258
utils.update_recording_status(working_dir, utils.Task.Fixation_Assigned, utils.Status.Finished, skip_if_missing=True)

src/glassesValidator/utils/__init__.py

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
import pathlib
22
import enum
3-
import json
43
import csv
54

65
from .makeVideo import process as make_video
76

8-
from glassesTools import utils
7+
from glassesTools import json, utils
98
from glassesTools.recording import Recording
109
from glassesTools.eyetracker import EyeTracker
1110

@@ -25,7 +24,7 @@ class Task(utils.AutoName):
2524
Make_Video = enum.auto()
2625
Unknown = enum.auto()
2726
task_names = [x.value for x in Task]
28-
utils.register_type(utils.CustomTypeEntry(Task,'__enum.Task__', utils.enum_val_2_str, lambda x: getattr(Task, x.split('.')[1])))
27+
json.register_type(json.TypeEntry(Task,'__enum.Task__', utils.enum_val_2_str, lambda x: getattr(Task, x.split('.')[1])))
2928

3029
def get_task_name_friendly(name: str | Task):
3130
if isinstance(name,Task):
@@ -85,15 +84,13 @@ class Status(utils.AutoName):
8584
Finished = enum.auto()
8685
Errored = enum.auto()
8786
status_names = [x.value for x in Status]
88-
utils.register_type(utils.CustomTypeEntry(Status,'__enum.Status__', utils.enum_val_2_str, lambda x: getattr(Status, x.split('.')[1])))
87+
json.register_type(json.TypeEntry(Status,'__enum.Status__', utils.enum_val_2_str, lambda x: getattr(Status, x.split('.')[1])))
8988

9089

9190
_status_file = 'glassesValidator.recording'
9291
def _create_recording_status_file(file: pathlib.Path):
9392
task_status_dict = {utils.enum_val_2_str(getattr(Task,x)): Status.Not_Started for x in Task.__members__ if x not in ['Not_Imported', 'Make_Video', 'Unknown']}
94-
95-
with open(file, 'w') as f:
96-
json.dump(task_status_dict, f, cls=utils.CustomTypeEncoder)
93+
json.dump(task_status_dict, file)
9794

9895

9996
def get_recording_status(path: str | pathlib.Path, create_if_missing = False, skip_if_missing=False):
@@ -106,8 +103,8 @@ def get_recording_status(path: str | pathlib.Path, create_if_missing = False, sk
106103
elif skip_if_missing:
107104
return None
108105

109-
with open(file, 'r') as f:
110-
return json.load(f, object_hook=utils.json_reconstitute)
106+
recording_states = json.load(file)
107+
return {k: Status(recording_states[k]) for k in recording_states} # turn state value from string back into enum instance
111108

112109
def get_last_finished_step(status: dict[str,Status]):
113110
last = Task.Not_Imported
@@ -130,9 +127,7 @@ def update_recording_status(path: str | pathlib.Path, task: Task, status: Status
130127
while (next_task:=get_next_task(next_task)) is not None:
131128
rec_status[utils.enum_val_2_str(next_task)] = Status.Not_Started
132129

133-
file = path / _status_file
134-
with open(file, 'w') as f:
135-
json.dump(rec_status, f, cls=utils.CustomTypeEncoder, indent=2)
130+
json.dump(rec_status, path / _status_file)
136131

137132
return rec_status
138133

0 commit comments

Comments
 (0)