Skip to content

Commit

Permalink
Merge pull request #11 from pupil-labs/cleanup
Browse files Browse the repository at this point in the history
move stream loading routines into their respective constructor.
  • Loading branch information
rennis250 authored Mar 27, 2024
2 parents cebb4bb + 5486334 commit ed5b8c9
Show file tree
Hide file tree
Showing 6 changed files with 61 additions and 51 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ test_data/
.vscode/
*.mp4
dev/
guide

# Created by https://www.toptal.com/developers/gitignore/api/python,visualstudiocode,macos,windows,linux,pycharm
# Edit at https://www.toptal.com/developers/gitignore?templates=python,visualstudiocode,macos,windows,linux,pycharm
Expand Down
42 changes: 9 additions & 33 deletions src/pupil_labs/neon_recording/neon_recording.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,16 +129,9 @@ def _load_calib_bin(self):
)

def __init__(self, rec_dir_in: pathlib.Path | str):
self._streams = {
"gaze": GazeStream("gaze", self),
"imu": IMUStream("imu", self),
"scene": VideoStream("scene", self),
"eye": VideoStream("eye", self),
}

self._calib_bin_loaded = False

log.info(f"NeonRecording: Loading recording from: {rec_dir_in}")
log.info(f"NeonRecording: Loading recording from {rec_dir_in}")
if isinstance(rec_dir_in, str):
self._rec_dir = pathlib.Path(rec_dir_in)
else:
Expand Down Expand Up @@ -175,31 +168,6 @@ def __init__(self, rec_dir_in: pathlib.Path | str):
self._wearer["uuid"] = wearer_data["uuid"]
self._wearer["name"] = wearer_data["name"]

# load up raw times, in case useful at some point
log.info("NeonRecording: Loading raw time (ns) files")
self._gaze_ps1_raw_time_ns = np.fromfile(
str(self._rec_dir / "gaze ps1.time"), dtype="<u8"
)
self._gaze_200hz_raw_time_ns = np.fromfile(
str(self._rec_dir / "gaze_200hz.time"), dtype="<u8"
)

log.info("NeonRecording: Loading gaze data")
self._streams["gaze"]._load()

# still not sure what gaze_right is...
# log.info("NeonRecording: Loading 'gaze_right_ps1' data")
# rec._gaze_right_ps1_ts, rec._gaze_right_ps1_raw = _load_ts_and_data(self._rec_dir, 'gaze ps1')

log.info("NeonRecording: Loading IMU data")
self._streams["imu"]._load()

log.info("NeonRecording: Loading scene camera video")
self._streams["scene"]._load("Neon Scene Camera v1 ps1")

log.info("NeonRecording: Loading eye camera video")
self._streams["eye"]._load("Neon Sensor Module v1 ps1")

log.info("NeonRecording: Loading events")
try:
labels = (self._rec_dir / "event.txt").read_text().strip().split("\n")
Expand All @@ -211,6 +179,14 @@ def __init__(self, rec_dir_in: pathlib.Path | str):
self._events = [evt for evt in zip(labels, events_ts)]
self._unique_events = None

log.info("NeonRecording: Loading data streams")
self._streams = {
"gaze": GazeStream("gaze", self),
"imu": IMUStream("imu", self),
"scene": VideoStream("scene", "Neon Scene Camera v1 ps1", self),
"eye": VideoStream("eye", "Neon Sensor Module v1 ps1", self),
}

log.info("NeonRecording: Finished loading recording.")

# TODO: save for the end of development
Expand Down
22 changes: 21 additions & 1 deletion src/pupil_labs/neon_recording/stream/gaze_stream.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ def _convert_gaze_data_to_recarray(gaze_data, ts, ts_rel):


class GazeStream(Stream):
def __init__(self, name, recording):
super().__init__(name, recording)
self._load()

def _sample_linear_interp(self, sorted_ts):
xs = self._data.x
ys = self._data.y
Expand All @@ -54,12 +58,28 @@ def _sample_linear_interp(self, sorted_ts):
else:
yield None

def _load(self, file_name: Optional[str] = None) -> None:
def _load(self) -> None:
log.info("NeonRecording: Loading gaze data")

# we use gaze_200hz from cloud for the rec gaze stream
# ts, raw = self._load_ts_and_data(rec_dir, 'gaze ps1')
gaze_200hz_ts, gaze_200hz_raw = self._load_ts_and_data("gaze_200hz")
gaze_200hz_ts_rel = gaze_200hz_ts - self._recording._start_ts

# load up raw timestamps in original ns format,
# in case useful at some point
log.debug("NeonRecording: Loading raw gaze timestamps (ns)")
self._gaze_ps1_raw_time_ns = np.fromfile(
str(self._recording._rec_dir / "gaze ps1.time"), dtype="<u8"
)
self._gaze_200hz_raw_time_ns = np.fromfile(
str(self._recording._rec_dir / "gaze_200hz.time"), dtype="<u8"
)

# still not sure what gaze_right is...
# log.info("NeonRecording: Loading 'gaze_right_ps1' data")
# rec._gaze_right_ps1_ts, rec._gaze_right_ps1_raw = _load_ts_and_data(self._recording._rec_dir, 'gaze ps1')

data = _convert_gaze_data_to_recarray(
gaze_200hz_raw, gaze_200hz_ts, gaze_200hz_ts_rel
)
Expand Down
8 changes: 7 additions & 1 deletion src/pupil_labs/neon_recording/stream/imu/imu_stream.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@


class IMUStream(Stream):
def __init__(self, name, recording):
super().__init__(name, recording)
self._load()

def _sample_linear_interp(self, sorted_ts):
interp_data = np.zeros(len(sorted_ts), dtype=IMURecording.DTYPE_RAW).view(
np.recarray
Expand All @@ -28,7 +32,9 @@ def _sample_linear_interp(self, sorted_ts):
else:
yield None

def _load(self, file_name: Optional[str] = None) -> None:
def _load(self):
log.info("NeonRecording: Loading IMU data")

imu_rec = IMURecording(
self._recording._rec_dir / "extimu ps1.raw", self._recording._start_ts
)
Expand Down
8 changes: 4 additions & 4 deletions src/pupil_labs/neon_recording/stream/stream.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ def ts_rel(self):
return self._ts_rel

@abc.abstractmethod
def _load(self, file_name: Optional[str] = None) -> None:
def _load(self):
pass

@abc.abstractmethod
Expand Down Expand Up @@ -104,11 +104,11 @@ def sample(self, tstamps, method=InterpolationMethod.NEAREST):
return self._sample_linear_interp(sorted_tses)
else:
return ValueError(
"Only LINEAR, NEAREST, and INSERT_ORDER methods are supported."
"Only LINEAR and NEAREST methods are supported."
)

def _sample_nearest_rob(self, sorted_tses):
log.debug("NeonRecording: Sampling nearest timestamps.")
log.debug("NeonRecording: Sampling timestamps with nearest neighbor method.")

closest_idxs = [
np.argmin(np.abs(self._ts - curr_ts)) if not self._ts_oob(curr_ts) else None
Expand All @@ -125,7 +125,7 @@ def _sample_nearest_rob(self, sorted_tses):
# https://stackoverflow.com/questions/2566412/find-nearest-value-in-numpy-array
def _sample_nearest(self, sorted_tses):
# uggcf://jjj.lbhghor.pbz/jngpu?i=FRKKRF5i59b
log.debug("NeonRecording: Sampling nearest timestamps.")
log.debug("NeonRecording: Sampling timestamps with nearest neighbor method.")

closest_idxs = np.searchsorted(self._ts, sorted_tses, side="right")
for i, ts in enumerate(sorted_tses):
Expand Down
31 changes: 19 additions & 12 deletions src/pupil_labs/neon_recording/stream/video_stream.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@


class VideoStream(Stream):
def __init__(self, name, file_name, recording):
super().__init__(name, recording)
self._file_name = file_name
self._width = None
self._height = None

self._load()

@property
def width(self):
return self._width
Expand All @@ -33,20 +41,19 @@ def _sample_linear_interp(self, sorted_ts):
"NeonRecording: Video streams only support nearest neighbor interpolation."
)

def _load(self, file_name: Optional[str] = None) -> None:
if file_name is not None:
container, ts = self._load_video(file_name)
def _load(self):
log.info(f"NeonRecording: Loading video: {self._file_name}.")

container, ts = self._load_video(self._file_name)

self._backing_data = container.streams.video[0]
self._data = self._backing_data.frames
self._ts = ts
setattr(self._data, "ts", self._ts)
self._ts_rel = self._ts - self._recording._start_ts
self._backing_data = container.streams.video[0]
self._data = self._backing_data.frames
self._ts = ts
setattr(self._data, "ts", self._ts)
self._ts_rel = self._ts - self._recording._start_ts

self._width = self._data[0].width
self._height = self._data[0].height
else:
raise ValueError("Filename must be provided when loading a VideoStream.")
self._width = self._data[0].width
self._height = self._data[0].height

def _load_video(self, video_name: str):
log.debug(
Expand Down

0 comments on commit ed5b8c9

Please sign in to comment.