meyelens.offline

class meyelens.offline.ExperimentReader(folder_path)[source]

Bases: object

Read 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.csv with:
    • optional metadata lines starting with # in the form # key: value

    • a header row

    • per-frame rows containing at least a timestamp column

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

  • fps is estimated as the mean of 1 / 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 None if 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 signal value.

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 q to 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 timestamp is a numeric column in seconds.

Potential issue in original code

The previous implementation attempted to iterate over self.frame_info as if it were a list of dicts (entry["timestamp"]). Here we use DataFrame columns directly.

visualize_triggers()[source]

Plot trigger/signal values across frame indices.

Notes

Potential issue in original code: if not self.frame_info: is ambiguous for a DataFrame. Here we use empty. Also, the original code treated frame_info like a list of dicts; this version uses DataFrame columns.

close()[source]

Release the OpenCV video capture handle.

Return type:

None

class meyelens.offline.FastVideoRecorder(name='experiment', dest_folder='.', fps=20.0, frame_size=(640, 480), metadata=None, filename='eye.avi')[source]

Bases: object

Simple video + CSV recorder for experiments.

This class writes:

  • a grayscale video file (MJPG codec)

  • a CSV file named expinfo.csv with 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.csv as # 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_index starts at 0 and increments per call.

release()[source]

Release the video writer and close the CSV file.

Return type:

None

class meyelens.offline.FrameRateManager(fps, duration: float = 10)[source]

Bases: object

Utility 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

start()[source]

Initialize timing variables and reset counters for a new run.

Return type:

None

is_ready() bool[source]

Check if it is time to process/acquire the next frame.

Returns:

True if current time has reached the next scheduled frame time. When True, 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 set time_grab and subtracts it from the nominal inter-frame interval.

Parameters:

overhead (float, optional) – Small constant to compensate for additional overhead (seconds).

Return type:

None

is_finished() bool[source]

Check whether the run duration has elapsed.

Returns:

True if the current time is beyond the configured duration.

Return type:

bool

Notes

When finished, prints the actual duration and number of frames processed.