glassesTools 1.3.2__tar.gz → 1.3.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. {glassestools-1.3.2/src/glassesTools.egg-info → glassestools-1.3.4}/PKG-INFO +5 -4
  2. {glassestools-1.3.2 → glassestools-1.3.4}/README.md +1 -1
  3. {glassestools-1.3.2 → glassestools-1.3.4}/requirements.txt +3 -2
  4. {glassestools-1.3.2 → glassestools-1.3.4}/src/glassesTools/aruco.py +4 -6
  5. {glassestools-1.3.2 → glassestools-1.3.4}/src/glassesTools/gaze_headref.py +6 -6
  6. {glassestools-1.3.2 → glassestools-1.3.4}/src/glassesTools/gaze_worldref.py +13 -16
  7. {glassestools-1.3.2 → glassestools-1.3.4}/src/glassesTools/importing/SMI_ETG.py +4 -3
  8. {glassestools-1.3.2 → glassestools-1.3.4}/src/glassesTools/importing/SeeTrue_STONE.py +3 -3
  9. {glassestools-1.3.2 → glassestools-1.3.4}/src/glassesTools/importing/adhawk_mindlink.py +1 -1
  10. {glassestools-1.3.2 → glassestools-1.3.4}/src/glassesTools/importing/pupilLabs.py +2 -2
  11. {glassestools-1.3.2 → glassestools-1.3.4}/src/glassesTools/importing/tobii_G2.py +1 -1
  12. {glassestools-1.3.2 → glassestools-1.3.4}/src/glassesTools/importing/tobii_G3.py +1 -1
  13. {glassestools-1.3.2 → glassestools-1.3.4}/src/glassesTools/ocv.py +2 -2
  14. {glassestools-1.3.2 → glassestools-1.3.4}/src/glassesTools/plane.py +14 -15
  15. {glassestools-1.3.2 → glassestools-1.3.4}/src/glassesTools/version.py +1 -1
  16. {glassestools-1.3.2 → glassestools-1.3.4}/src/glassesTools/video_gui.py +17 -6
  17. {glassestools-1.3.2 → glassestools-1.3.4}/src/glassesTools/video_utils.py +1 -1
  18. {glassestools-1.3.2 → glassestools-1.3.4/src/glassesTools.egg-info}/PKG-INFO +5 -4
  19. glassestools-1.3.4/src/glassesTools.egg-info/requires.txt +10 -0
  20. glassestools-1.3.2/src/glassesTools.egg-info/requires.txt +0 -9
  21. {glassestools-1.3.2 → glassestools-1.3.4}/LICENSE +0 -0
  22. {glassestools-1.3.2 → glassestools-1.3.4}/MANIFEST.in +0 -0
  23. {glassestools-1.3.2 → glassestools-1.3.4}/pyproject.toml +0 -0
  24. {glassestools-1.3.2 → glassestools-1.3.4}/setup.cfg +0 -0
  25. {glassestools-1.3.2 → glassestools-1.3.4}/setup.py +0 -0
  26. {glassestools-1.3.2 → glassestools-1.3.4}/src/glassesTools/__init__.py +0 -0
  27. {glassestools-1.3.2 → glassestools-1.3.4}/src/glassesTools/data_files.py +0 -0
  28. {glassestools-1.3.2 → glassestools-1.3.4}/src/glassesTools/drawing.py +0 -0
  29. {glassestools-1.3.2 → glassestools-1.3.4}/src/glassesTools/eyetracker.py +0 -0
  30. {glassestools-1.3.2 → glassestools-1.3.4}/src/glassesTools/importing/__init__.py +0 -0
  31. {glassestools-1.3.2 → glassestools-1.3.4}/src/glassesTools/intervals.py +0 -0
  32. {glassestools-1.3.2 → glassestools-1.3.4}/src/glassesTools/marker.py +0 -0
  33. {glassestools-1.3.2 → glassestools-1.3.4}/src/glassesTools/mp4analyser/__init__.py +0 -0
  34. {glassestools-1.3.2 → glassestools-1.3.4}/src/glassesTools/mp4analyser/core.py +0 -0
  35. {glassestools-1.3.2 → glassestools-1.3.4}/src/glassesTools/mp4analyser/iso.py +0 -0
  36. {glassestools-1.3.2 → glassestools-1.3.4}/src/glassesTools/mp4analyser/mpeglookups.py +0 -0
  37. {glassestools-1.3.2 → glassestools-1.3.4}/src/glassesTools/mp4analyser/non_iso.py +0 -0
  38. {glassestools-1.3.2 → glassestools-1.3.4}/src/glassesTools/mp4analyser/summary.py +0 -0
  39. {glassestools-1.3.2 → glassestools-1.3.4}/src/glassesTools/mp4analyser/util.py +0 -0
  40. {glassestools-1.3.2 → glassestools-1.3.4}/src/glassesTools/recording.py +0 -0
  41. {glassestools-1.3.2 → glassestools-1.3.4}/src/glassesTools/timestamps.py +0 -0
  42. {glassestools-1.3.2 → glassestools-1.3.4}/src/glassesTools/transforms.py +0 -0
  43. {glassestools-1.3.2 → glassestools-1.3.4}/src/glassesTools/utils.py +0 -0
  44. {glassestools-1.3.2 → glassestools-1.3.4}/src/glassesTools.egg-info/SOURCES.txt +0 -0
  45. {glassestools-1.3.2 → glassestools-1.3.4}/src/glassesTools.egg-info/dependency_links.txt +0 -0
  46. {glassestools-1.3.2 → glassestools-1.3.4}/src/glassesTools.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: glassesTools
3
- Version: 1.3.2
3
+ Version: 1.3.4
4
4
  Summary: Tools for processing wearable eye tracker recordings.
5
5
  Home-page: https://github.com/dcnieho/glassesTools
6
6
  Author: Diederick Niehorster
@@ -38,9 +38,10 @@ License-File: LICENSE
38
38
  Requires-Dist: numpy
39
39
  Requires-Dist: pandas
40
40
  Requires-Dist: msgpack
41
- Requires-Dist: opencv-python-headless==4.9.0.80
41
+ Requires-Dist: imgui_bundle==1.3.0
42
+ Requires-Dist: opencv-python-headless==4.10.0.82
42
43
  Requires-Dist: ffpyplayer
43
- Requires-Dist: scipy==1.11.3
44
+ Requires-Dist: eulerangles
44
45
  Provides-Extra: gui
45
46
  Requires-Dist: imgui_bundle==1.3.0; extra == "gui"
46
47
 
@@ -48,7 +49,7 @@ Requires-Dist: imgui_bundle==1.3.0; extra == "gui"
48
49
  [![PyPI Latest Release](https://img.shields.io/pypi/v/glassesTools.svg)](https://pypi.org/project/glassesTools/)
49
50
  [![image](https://img.shields.io/pypi/pyversions/glassesTools.svg)](https://pypi.org/project/glassesTools/)
50
51
 
51
- # GlassesTools v1.3.2
52
+ # GlassesTools v1.3.4
52
53
  Tools for processing wearable eye tracker recordings.
53
54
 
54
55
  If you use this package or any of the code in this repository, please cite:<br>
@@ -2,7 +2,7 @@
2
2
  [![PyPI Latest Release](https://img.shields.io/pypi/v/glassesTools.svg)](https://pypi.org/project/glassesTools/)
3
3
  [![image](https://img.shields.io/pypi/pyversions/glassesTools.svg)](https://pypi.org/project/glassesTools/)
4
4
 
5
- # GlassesTools v1.3.2
5
+ # GlassesTools v1.3.4
6
6
  Tools for processing wearable eye tracker recordings.
7
7
 
8
8
  If you use this package or any of the code in this repository, please cite:<br>
@@ -1,6 +1,7 @@
1
1
  numpy
2
2
  pandas
3
3
  msgpack
4
- opencv-python-headless==4.9.0.80
4
+ imgui_bundle==1.3.0
5
+ opencv-python-headless==4.10.0.82
5
6
  ffpyplayer # comes with ffmpeg binaries we need
6
- scipy==1.11.3
7
+ eulerangles
@@ -136,10 +136,10 @@ def create_board(board_corner_points: list[np.ndarray], ids: list[int], ArUco_di
136
136
  return cv2.aruco.Board(board_corner_points, ArUco_dict, np.array(ids))
137
137
 
138
138
  def run_pose_estimation(in_video, frame_timestamp_file, camera_calibration_file,
139
- output_dir, out_file,
139
+ output_dir,
140
140
  processing_intervals,
141
141
  ArUco_board, aruco_params, min_num_markers,
142
- gui, arm_length, sub_pixel_fac = 8, show_rejected_markers = False):
142
+ gui, arm_length, sub_pixel_fac = 8, show_rejected_markers = False) -> tuple[bool, list[plane.Pose]]:
143
143
  show_visualization = gui is not None
144
144
 
145
145
  # open video
@@ -193,16 +193,14 @@ def run_pose_estimation(in_video, frame_timestamp_file, camera_calibration_file,
193
193
  # keys is populated above
194
194
  if 's' in keys:
195
195
  # screenshot
196
- cv2.imwrite(str(output_dir / ('detect_frame_%d.png' % frame_idx)), frame)
196
+ cv2.imwrite(output_dir / f'detect_frame_{frame_idx}.png', frame)
197
197
  gui.update_image(frame, frame_ts/1000., frame_idx)
198
198
  closed, = gui.get_state()
199
199
  if closed:
200
200
  stop_all_processing = True
201
201
  break
202
202
 
203
- plane.Pose.writeToFile(poses, output_dir / out_file, skip_failed=True)
204
-
205
203
  if show_visualization:
206
204
  gui.stop()
207
205
 
208
- return stop_all_processing
206
+ return stop_all_processing, poses
@@ -30,11 +30,6 @@ class Gaze:
30
30
  self.gaze_dir_r : np.ndarray = gaze_dir_r
31
31
  self.gaze_ori_r : np.ndarray = gaze_ori_r
32
32
 
33
- @staticmethod
34
- def readFromFile(fileName:str|pathlib.Path) -> tuple[dict[int,list['Gaze']], int]:
35
- return data_files.read_file(fileName,
36
- Gaze, False, False, True)
37
-
38
33
  def draw(self, img:np.ndarray, cameraParams:ocv.CameraParams=None, subPixelFac=1):
39
34
  drawing.openCVCircle(img, self.gaze_pos_vid, 8, (0,255,0), 2, subPixelFac)
40
35
  # draw 3D gaze point as well, usually coincides with 2D gaze point, but not always. E.g. the Adhawk MindLink may
@@ -43,4 +38,9 @@ class Gaze:
43
38
  camRot = np.zeros((1,3)) if cameraParams.rotation_vec is None else cameraParams.rotation_vec
44
39
  camPos = np.zeros((1,3)) if cameraParams.position is None else cameraParams.position
45
40
  a = cv2.projectPoints(np.array(self.gaze_pos_3d).reshape(1,3),camRot,camPos,cameraParams.camera_mtx,cameraParams.distort_coeffs)[0][0][0]
46
- drawing.openCVCircle(img, a, 5, (0,255,255), -1, subPixelFac)
41
+ drawing.openCVCircle(img, a, 5, (0,255,255), -1, subPixelFac)
42
+
43
+
44
+ def read_dict_from_file(fileName:str|pathlib.Path) -> tuple[dict[int,list[Gaze]], int]:
45
+ return data_files.read_file(fileName,
46
+ Gaze, False, False, True)
@@ -50,18 +50,6 @@ class Gaze:
50
50
  self.gazePosPlane2DLeft = gazePosPlane2DLeft # lGaze3D in poster space
51
51
  self.gazePosPlane2DRight = gazePosPlane2DRight # rGaze3D in poster space
52
52
 
53
- @staticmethod
54
- def readFromFile(fileName:str|pathlib.Path, start:int=None, end:int=None) -> dict[int,list['Gaze']]:
55
- return data_files.read_file(fileName,
56
- Gaze, False, False, True,
57
- start=start,end=end)[0]
58
-
59
- @staticmethod
60
- def writeToFile(gazes: list['Gaze'] | dict[int,list['Gaze']], fileName:str|pathlib.Path, skip_missing=False):
61
- data_files.write_array_to_file(gazes, fileName,
62
- Gaze._columns_compressed,
63
- skip_all_nan=skip_missing)
64
-
65
53
  def drawOnWorldVideo(self, img, cameraParams: ocv.CameraParams, subPixelFac=1):
66
54
  # project to camera, display
67
55
  def project_and_draw(img,pos,sz,clr):
@@ -107,14 +95,23 @@ class Gaze:
107
95
  if self.gazePosPlane2D_vidPos_ray is not None:
108
96
  reference.draw(img, *self.gazePosPlane2D_vidPos_ray, subPixelFac, (255,255,0), 3)
109
97
 
98
+ def read_dict_from_file(fileName:str|pathlib.Path, start:int=None, end:int=None) -> dict[int,list[Gaze]]:
99
+ return data_files.read_file(fileName,
100
+ Gaze, False, False, True,
101
+ start=start,end=end)[0]
102
+
103
+ def write_dict_to_file(gazes: list[Gaze] | dict[int,list[Gaze]], fileName:str|pathlib.Path, skip_missing=False):
104
+ data_files.write_array_to_file(gazes, fileName,
105
+ Gaze._columns_compressed,
106
+ skip_all_nan=skip_missing)
110
107
 
111
108
  def gazes_head_to_world(poses: list[plane.Pose], gazes_head: dict[int,list[gaze_headref.Gaze]], cameraParams: ocv.CameraParams) -> dict[int,list[Gaze]]:
112
109
  from . import transforms
113
- planeGazes = {}
110
+ plane_gazes = {}
114
111
  for frame_idx in poses:
115
112
  if frame_idx in gazes_head:
116
- planeGazes[frame_idx] = []
113
+ plane_gazes[frame_idx] = []
117
114
  for gaze in gazes_head[frame_idx]:
118
115
  gazePoster = transforms.gazeToPlane(gaze, poses[frame_idx], cameraParams)
119
- planeGazes[frame_idx].append(gazePoster)
120
- return planeGazes
116
+ plane_gazes[frame_idx].append(gazePoster)
117
+ return plane_gazes
@@ -20,7 +20,7 @@ import numpy as np
20
20
  import math
21
21
  import configparser
22
22
  from io import StringIO
23
- from scipy.spatial.transform import Rotation
23
+ import eulerangles
24
24
 
25
25
  from ..recording import Recording
26
26
  from ..eyetracker import EyeTracker
@@ -187,7 +187,8 @@ def getCameraFromFile(inputDir: str|pathlib.Path, outputDir: str|pathlib.Path):
187
187
  # 2. sensor offsets seem to be relative to center of sensor
188
188
  camera['principalPoint'] = camera['resolution']/2.+camera['sensorOffsets']
189
189
  # 3. turn euler angles into rotation matrix (180-Rz because poster space has positive X rightward and positive Y downward)
190
- camera['rotation'] = Rotation.from_euler('XYZ', [camera['eulerAngles'][0], camera['eulerAngles'][1], 180-camera['eulerAngles'][2]], degrees=True).as_matrix()
190
+ eulers = [camera['eulerAngles'][0], camera['eulerAngles'][1], 180-camera['eulerAngles'][2]]
191
+ camera['rotation'] = eulerangles.euler2matrix(eulers, 'xyz', intrinsic=True, right_handed_rotation=True)
191
192
 
192
193
  # turn into camera matrix and distortion coefficients as used by OpenCV
193
194
  camera['cameraMatrix'] = np.identity(3)
@@ -203,7 +204,7 @@ def getCameraFromFile(inputDir: str|pathlib.Path, outputDir: str|pathlib.Path):
203
204
 
204
205
 
205
206
  # store to file
206
- fs = cv2.FileStorage(str(outputDir / 'calibration.xml'), cv2.FILE_STORAGE_WRITE)
207
+ fs = cv2.FileStorage(outputDir / 'calibration.xml', cv2.FILE_STORAGE_WRITE)
207
208
  for key,value in camera.items():
208
209
  fs.write(name=key,val=value)
209
210
  fs.release()
@@ -127,7 +127,7 @@ def copySeeTrueRecording(inputDir: pathlib.Path, outputDir: pathlib.Path, recInf
127
127
  # get scene video dimensions by interrogating a frame in sceneVidDir
128
128
  sceneVidDir = inputDir / ('ScenePics_' + recInfo.name)
129
129
  frame = next(sceneVidDir.glob('*.jpeg'))
130
- h,w,_ = cv2.imread(str(frame)).shape
130
+ h,w,_ = cv2.imread(frame).shape
131
131
 
132
132
  # prep gaze data and get video frame timestamps from it
133
133
  print(' Prepping gaze data...')
@@ -182,7 +182,7 @@ def copySeeTrueRecording(inputDir: pathlib.Path, outputDir: pathlib.Path, recInf
182
182
  blackIm = np.zeros((h,w,3), np.uint8) # black image
183
183
  for f in blackFrames:
184
184
  # store black frame to file
185
- cv2.imwrite(str(sceneVidDir / 'frame_{:d}.jpeg'.format(f)),blackIm)
185
+ cv2.imwrite(sceneVidDir / f'frame_{f:d}.jpeg',blackIm)
186
186
  frames.append(f)
187
187
  frames = sorted(frames)
188
188
 
@@ -253,7 +253,7 @@ def getCameraHardcoded(outputDir: str|pathlib.Path):
253
253
  camera['resolution'] = np.array([640, 480])
254
254
 
255
255
  # store to file
256
- fs = cv2.FileStorage(str(outputDir / 'calibration.xml'), cv2.FILE_STORAGE_WRITE)
256
+ fs = cv2.FileStorage(outputDir / 'calibration.xml', cv2.FILE_STORAGE_WRITE)
257
257
  for key,value in camera.items():
258
258
  fs.write(name=key,val=value)
259
259
  fs.release()
@@ -168,7 +168,7 @@ def getCameraHardcoded(outputDir: str|pathlib.Path):
168
168
  camera['rotation'] = cv2.Rodrigues(np.radians(np.array([12.000000000000043, 0.0, 0.0])))[0]
169
169
 
170
170
  # store to file
171
- fs = cv2.FileStorage(str(outputDir / 'calibration.xml'), cv2.FILE_STORAGE_WRITE)
171
+ fs = cv2.FileStorage(outputDir / 'calibration.xml', cv2.FILE_STORAGE_WRITE)
172
172
  for key,value in camera.items():
173
173
  fs.write(name=key,val=value)
174
174
  fs.release()
@@ -354,7 +354,7 @@ def getCameraCalFromCloudExport(inputDir: str|pathlib.Path, outputDir: str|pathl
354
354
  return camInfo['resolution']
355
355
 
356
356
  def storeCameraCalibration(camInfo: dict[str, typing.Any], outputDir: str|pathlib.Path):
357
- fs = cv2.FileStorage(str(outputDir / 'calibration.xml'), cv2.FILE_STORAGE_WRITE)
357
+ fs = cv2.FileStorage(outputDir / 'calibration.xml', cv2.FILE_STORAGE_WRITE)
358
358
  for key,value in camInfo.items():
359
359
  fs.write(name=key,val=value)
360
360
  fs.release()
@@ -376,7 +376,7 @@ def getSceneCameraResolution(inputDir: str|pathlib.Path, recInfo: Recording):
376
376
  return np.array(getCamInfo(inputDir / 'world.intrinsics')['resolution'])
377
377
  else:
378
378
  import cv2
379
- cap = cv2.VideoCapture(str(recInfo.get_scene_video_path()))
379
+ cap = cv2.VideoCapture(recInfo.get_scene_video_path())
380
380
  if cap.isOpened():
381
381
  width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
382
382
  height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
@@ -205,7 +205,7 @@ def getCameraFromTSLV(inputDir: str|pathlib.Path):
205
205
 
206
206
 
207
207
  # store to file
208
- fs = cv2.FileStorage(str(inputDir / 'calibration.xml'), cv2.FILE_STORAGE_WRITE)
208
+ fs = cv2.FileStorage(inputDir / 'calibration.xml', cv2.FILE_STORAGE_WRITE)
209
209
  for key,value in camera.items():
210
210
  fs.write(name=key,val=value)
211
211
  fs.release()
@@ -185,7 +185,7 @@ def getCameraFromJson(inputDir: str|pathlib.Path, outputDir: str|pathlib.Path):
185
185
 
186
186
 
187
187
  # store to file
188
- fs = cv2.FileStorage(str(outputDir / 'calibration.xml'), cv2.FILE_STORAGE_WRITE)
188
+ fs = cv2.FileStorage(outputDir / 'calibration.xml', cv2.FILE_STORAGE_WRITE)
189
189
  for key,value in camera.items():
190
190
  fs.write(name=key,val=value)
191
191
  fs.release()
@@ -26,7 +26,7 @@ class CameraParams:
26
26
  if not fileName.is_file():
27
27
  return CameraParams(None,None)
28
28
 
29
- fs = cv2.FileStorage(str(fileName), cv2.FILE_STORAGE_READ)
29
+ fs = cv2.FileStorage(fileName, cv2.FILE_STORAGE_READ)
30
30
  resolution = fs.getNode("resolution").mat()
31
31
  cameraMatrix = fs.getNode("cameraMatrix").mat()
32
32
  distCoeff = fs.getNode("distCoeff").mat()
@@ -53,7 +53,7 @@ class CV2VideoReader:
53
53
  else:
54
54
  self.ts = timestamps
55
55
 
56
- self.cap = cv2.VideoCapture(str(self.file))
56
+ self.cap = cv2.VideoCapture(self.file)
57
57
  if not self.cap.isOpened():
58
58
  raise RuntimeError('the file "{}" could not be opened'.format(str(self.file)))
59
59
  self.nframes= float(self.cap.get(cv2.CAP_PROP_FRAME_COUNT))
@@ -44,7 +44,7 @@ class Plane:
44
44
  img = None
45
45
  # read from file if image exists
46
46
  if ref_image_store_path is not None and ref_image_store_path.is_file():
47
- img = cv2.imread(str(ref_image_store_path), cv2.IMREAD_COLOR)
47
+ img = cv2.imread(ref_image_store_path, cv2.IMREAD_COLOR)
48
48
  # if image doesn't exist or is the wrong size, create
49
49
  if img is None or img.shape[1]!=ref_image_width:
50
50
  img = self._store_reference_image(ref_image_store_path, ref_image_width)
@@ -209,7 +209,7 @@ class Plane:
209
209
  img[idxs[0]:idxs[1], idxs[2]:idxs[3]] = mark
210
210
 
211
211
  if path:
212
- cv2.imwrite(str(path), img)
212
+ cv2.imwrite(path, img)
213
213
 
214
214
  return img
215
215
 
@@ -246,18 +246,6 @@ class Pose:
246
246
  self._RtMatInv = None
247
247
  self._iH = None
248
248
 
249
- @staticmethod
250
- def readFromFile(fileName:str|pathlib.Path, start:int=None, end:int=None) -> dict[int,'Pose']:
251
- return data_files.read_file(fileName,
252
- Pose, True, True, False,
253
- start=start, end=end)[0]
254
-
255
- @staticmethod
256
- def writeToFile(poses: list['Pose'], fileName:str|pathlib.Path, skip_failed=False):
257
- data_files.write_array_to_file(poses, fileName,
258
- Pose._columns_compressed,
259
- skip_all_nan=skip_failed)
260
-
261
249
  def camToWorld(self, point: np.ndarray):
262
250
  if (self.pose_R_vec is None) or (self.pose_T_vec is None) or np.any(np.isnan(point)):
263
251
  return np.full((3,), np.nan)
@@ -335,4 +323,15 @@ class Pose:
335
323
  vector /= np.sqrt((vector**2).sum())
336
324
 
337
325
  # find intersection of 3D gaze with poster
338
- return transforms.intersect_plane_ray(self._planeNormal, self._planePoint, vector.flatten(), origin.flatten())
326
+ return transforms.intersect_plane_ray(self._planeNormal, self._planePoint, vector.flatten(), origin.flatten())
327
+
328
+
329
+ def read_dict_from_file(fileName:str|pathlib.Path, start:int=None, end:int=None) -> dict[int,Pose]:
330
+ return data_files.read_file(fileName,
331
+ Pose, True, True, False,
332
+ start=start, end=end)[0]
333
+
334
+ def write_list_to_file(poses: list[Pose], fileName:str|pathlib.Path, skip_failed=False):
335
+ data_files.write_array_to_file(poses, fileName,
336
+ Pose._columns_compressed,
337
+ skip_all_nan=skip_failed)
@@ -1,4 +1,4 @@
1
- __version__ = "1.3.2"
1
+ __version__ = "1.3.4"
2
2
 
3
3
  __title__ = "glassesTools"
4
4
  __description__ = "Tools for processing wearable eye tracker recordings."
@@ -7,6 +7,7 @@ except ImportError:
7
7
 
8
8
  import time
9
9
  import threading
10
+ import numpy as np
10
11
 
11
12
 
12
13
  # simple GUI provider for viewer and coder windows in glassesValidator.process
@@ -31,6 +32,7 @@ class GUI:
31
32
  imgui.WindowFlags_.always_auto_resize
32
33
  )
33
34
  self._window_visible = {}
35
+ self._window_frame = {}
34
36
 
35
37
  self._interesting_keys = {}
36
38
  self._pressed_keys = {}
@@ -47,6 +49,7 @@ class GUI:
47
49
  self._new_frame[id] = (None, None, -1)
48
50
  self._current_frame[id] = (None, None, -1)
49
51
  self._window_visible[id] = False
52
+ self._window_frame[id] = -1
50
53
 
51
54
  self._next_window_id += 1
52
55
  return id
@@ -139,6 +142,7 @@ class GUI:
139
142
  params = hello_imgui.RunnerParams()
140
143
  params.app_window_params.window_geometry.size_auto = True
141
144
  params.app_window_params.restore_previous_geometry = False
145
+ params.ini_folder_type = hello_imgui.IniFolderType.temp_folder # so we don't have endless ini files in the app folder, since we don't use them anyway (see previous line, restore_previous_geometry = False)
142
146
  params.app_window_params.window_title = self._windows[self._get_main_window_id()]
143
147
  params.app_window_params.hidden = True
144
148
  params.fps_idling.fps_idle = 0
@@ -219,6 +223,8 @@ class GUI:
219
223
  return
220
224
 
221
225
  if need_begin_end:
226
+ if isinstance(self._window_size[w][0], np.ndarray):
227
+ imgui.set_next_window_size()
222
228
  opened, self._window_visible[w] = imgui.begin(self._windows[w], self._window_visible[w], self._window_flags)
223
229
  if not opened:
224
230
  imgui.end()
@@ -226,15 +232,20 @@ class GUI:
226
232
 
227
233
  imgui.set_cursor_pos((0,0))
228
234
  # draw image
229
- imgui.image(self._texID[w], imgui.ImVec2(self._current_frame[w][0].shape[1]*self._dpi_fac, self._current_frame[w][0].shape[0]*self._dpi_fac))
235
+ self._window_frame[w] += 1
236
+ win_sz = np.array([*imgui.get_window_size()])
237
+ img_sz = np.array([self._current_frame[w][0].shape[1]*self._dpi_fac, self._current_frame[w][0].shape[0]*self._dpi_fac])
238
+ if self._window_frame[w]>2: # it takes two frames for autosize to take effect
239
+ sfac = min([np.min(win_sz/img_sz), 1.]) # clamp to 1: don't scale up
240
+ img_sz = (img_sz * sfac).astype('int')
241
+ imgui.image(self._texID[w], img_sz)
230
242
 
231
243
  # draw bottom status overlay
232
- ws = imgui.get_window_size()
233
- ts = imgui.calc_text_size('')
234
- win_bottom = min(self._current_frame[w][0].shape[0]*self._dpi_fac, ws.y+imgui.get_scroll_y())
235
- imgui.set_cursor_pos_y(win_bottom-ts.y)
244
+ txt_sz = imgui.calc_text_size('')
245
+ win_bottom = min(self._current_frame[w][0].shape[0]*self._dpi_fac, win_sz[1]+imgui.get_scroll_y())
246
+ imgui.set_cursor_pos_y(win_bottom-txt_sz.y)
236
247
  imgui.push_style_color(imgui.Col_.child_bg, (0.0, 0.0, 0.0, 0.6))
237
- imgui.begin_child("##status_overlay", size=(-imgui.FLT_MIN,ts.y))
248
+ imgui.begin_child("##status_overlay", size=(-imgui.FLT_MIN,txt_sz.y))
238
249
  if (self._current_frame[w][1]):
239
250
  imgui.text(" %8.3f [%d]" % (self._current_frame[w][1], self._current_frame[w][2]))
240
251
  else:
@@ -118,7 +118,7 @@ def getFrameTimestampsFromVideo(vid_file):
118
118
  frameTs = (dts+empty_duration)/media_time_scale*1000
119
119
  else:
120
120
  # open file with opencv and get timestamps of each frame
121
- vid = cv2.VideoCapture(str(vid_file))
121
+ vid = cv2.VideoCapture(vid_file)
122
122
  nframes = float(vid.get(cv2.CAP_PROP_FRAME_COUNT))
123
123
  frameTs = []
124
124
  frame_idx = 0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: glassesTools
3
- Version: 1.3.2
3
+ Version: 1.3.4
4
4
  Summary: Tools for processing wearable eye tracker recordings.
5
5
  Home-page: https://github.com/dcnieho/glassesTools
6
6
  Author: Diederick Niehorster
@@ -38,9 +38,10 @@ License-File: LICENSE
38
38
  Requires-Dist: numpy
39
39
  Requires-Dist: pandas
40
40
  Requires-Dist: msgpack
41
- Requires-Dist: opencv-python-headless==4.9.0.80
41
+ Requires-Dist: imgui_bundle==1.3.0
42
+ Requires-Dist: opencv-python-headless==4.10.0.82
42
43
  Requires-Dist: ffpyplayer
43
- Requires-Dist: scipy==1.11.3
44
+ Requires-Dist: eulerangles
44
45
  Provides-Extra: gui
45
46
  Requires-Dist: imgui_bundle==1.3.0; extra == "gui"
46
47
 
@@ -48,7 +49,7 @@ Requires-Dist: imgui_bundle==1.3.0; extra == "gui"
48
49
  [![PyPI Latest Release](https://img.shields.io/pypi/v/glassesTools.svg)](https://pypi.org/project/glassesTools/)
49
50
  [![image](https://img.shields.io/pypi/pyversions/glassesTools.svg)](https://pypi.org/project/glassesTools/)
50
51
 
51
- # GlassesTools v1.3.2
52
+ # GlassesTools v1.3.4
52
53
  Tools for processing wearable eye tracker recordings.
53
54
 
54
55
  If you use this package or any of the code in this repository, please cite:<br>
@@ -0,0 +1,10 @@
1
+ numpy
2
+ pandas
3
+ msgpack
4
+ imgui_bundle==1.3.0
5
+ opencv-python-headless==4.10.0.82
6
+ ffpyplayer
7
+ eulerangles
8
+
9
+ [GUI]
10
+ imgui_bundle==1.3.0
@@ -1,9 +0,0 @@
1
- numpy
2
- pandas
3
- msgpack
4
- opencv-python-headless==4.9.0.80
5
- ffpyplayer
6
- scipy==1.11.3
7
-
8
- [GUI]
9
- imgui_bundle==1.3.0
File without changes
File without changes
File without changes
File without changes