meyelens.offline
- class meyelens.offline.ExperimentReader(folder_path)[source]
Bases:
objectRead back a recorded experiment folder (video + per-frame CSV + metadata).
This class is designed to mirror the output structure produced by
FastVideoRecorder. It expects a folder containing:a video file (default name used here:
pupillometry.avi)- a CSV file named
expinfo.csvwith: optional metadata lines starting with
#in the form# key: valuea header row
per-frame rows containing at least a
timestampcolumn
- a CSV file named
- Parameters:
folder_path (str or pathlib.Path) – Folder containing the recorded video and
expinfo.csv.
- folder_path
Base folder of the recording.
- Type:
str
- video_path
Path to the video file.
- Type:
str
- csv_path
Path to the CSV file with timestamps/signals.
- Type:
str
- metadata
Metadata parsed from comment lines in the CSV.
- Type:
dict
- frame_info
Frame-by-frame table loaded from the CSV (comment lines ignored).
- Type:
pandas.DataFrame
- fps
Estimated FPS computed from timestamp differences.
- Type:
float
- cap
OpenCV video capture handle.
- Type:
cv2.VideoCapture
Notes
fpsis estimated as the mean of1 / diff(timestamp); this assumes timestamps are in seconds and monotonic.This class does not automatically close the capture: call
close().
- get_metadata()[source]
Return parsed metadata.
- Returns:
Metadata dictionary from the CSV comment lines.
- Return type:
dict
- get_frame_count()[source]
Get total number of frames in the video.
- Returns:
Number of frames according to OpenCV.
- Return type:
int
- get_frame(index)[source]
Retrieve a frame by index.
- Parameters:
index (int) – Frame index (0-based).
- Returns:
The frame (as returned by OpenCV), or
Noneif reading fails.- Return type:
numpy.ndarray or None
- play_video(delay: int = 30, repeat: bool = True)[source]
Play the recorded video with an overlay of the per-frame
signalvalue.- Parameters:
delay (int, optional) – Delay passed to
cv2.waitKey()in milliseconds. Smaller values play faster.repeat (bool, optional) – If
True, loop the video when it ends.
Notes
Press
qto quit playback.
- visualize_fps_stability()[source]
Plot instantaneous FPS over time derived from recorded timestamps.
This function computes:
dt = diff(timestamps)instantaneous_fps = 1 / dt
Then plots instantaneous FPS against the mid-time between consecutive frames.
Notes
This method expects that
timestampis a numeric column in seconds.Potential issue in original code
The previous implementation attempted to iterate over
self.frame_infoas if it were a list of dicts (entry["timestamp"]). Here we use DataFrame columns directly.
- class meyelens.offline.FastVideoRecorder(name='experiment', dest_folder='.', fps=20.0, frame_size=(640, 480), metadata=None, filename='eye.avi')[source]
Bases:
objectSimple video + CSV recorder for experiments.
This class writes:
a grayscale video file (MJPG codec)
a CSV file named
expinfo.csvwith optional metadata comment lines and one row per recorded frame.
The output folder is created as:
<dest_folder>/<timestamp>-<name>/
- Parameters:
name (str, optional) – Name appended to the output folder.
dest_folder (str, optional) – Base destination directory.
fps (float, optional) – Target frames per second passed to OpenCV VideoWriter.
frame_size (tuple[int, int], optional) – Frame size (width, height) expected by OpenCV VideoWriter.
metadata (dict or None, optional) – Optional metadata written to the top of
expinfo.csvas# key: value.filename (str, optional) – Video filename inside the output folder.
- output_folder
Created output folder path.
- Type:
str
- video_path
Full path to the recorded video file.
- Type:
str
- timestamp_path
Full path to the per-frame CSV file (
expinfo.csv).- Type:
str
- frame_index
Incremented each time
record_frame()is called.- Type:
int
- record_frame(frame, signal='', trial_n='')[source]
Record a frame to video and append a row to
expinfo.csv.- Parameters:
frame (numpy.ndarray) – Frame to write. If BGR, it is converted to grayscale before writing.
signal (str or int, optional) – Signal/trigger value to store for this frame.
trial_n (str or int, optional) – Trial identifier to store for this frame.
Notes
Timestamp is recorded using
time.time()(seconds since epoch).frame_indexstarts at 0 and increments per call.
- class meyelens.offline.FrameRateManager(fps, duration: float = 10)[source]
Bases:
objectUtility class to help maintain a target frame rate in a polling loop.
Typical usage
>>> frm = FrameRateManager(fps=30, duration=5) >>> frm.start() >>> while not frm.is_finished(): ... if frm.is_ready(): ... # acquire frame / do work here ... frm.set_frame_time()
- param fps:
Target frames per second.
- type fps:
float
- param duration:
Maximum loop duration in seconds for
is_finished().- type duration:
float, optional
- fps
Target FPS.
- Type:
float
- interframe
Target inter-frame interval (seconds).
- Type:
float
- time_grab
Timestamp saved when a new frame cycle begins (set in
is_ready()).- Type:
float
- duration
Duration used to determine loop end.
- Type:
float
- framecount
Counts how many times the loop was “ready” (i.e., frames acquired).
- Type:
int
- is_ready() bool[source]
Check if it is time to process/acquire the next frame.
- Returns:
Trueif current time has reached the next scheduled frame time. WhenTrue, also updates internal counters.- Return type:
bool
- set_frame_time(overhead: float = 0.0005)[source]
Schedule the next frame time based on processing overhead.
This method measures time elapsed since
is_ready()last settime_graband subtracts it from the nominal inter-frame interval.- Parameters:
overhead (float, optional) – Small constant to compensate for additional overhead (seconds).
- Return type:
None