API Reference

The Python API lives in the top-level eventcv package. Every operation exists both as a method on EventStream / EventFrame and as an OpenCV-style free function (listed under Functional API below); the free functions are generated from the methods, so the two forms stay in sync.

Loading & saving

eventcv.load(path: str, *, sensor_size: tuple[int, int] | None = None, time_unit: str | None = None, order: str = 'txyp', topic: str | None = None, max_events: int | None = None) EventStream[source]

Load events from any supported file, detected by its extension.

Supported today: .npz (N-ImageNet), .txt/.csv (e.g. EV-IMO t x y p), .bag (ROS dvs_msgs/EventArray), .hdf5/.h5, .aedat (AEDAT 2.0, jAER/DAVIS), and .dat (Prophesee CD events).

sensor_size and time_unit are auto-detected when omitted and only act as overrides: rosbags carry both in the message; HDF5/text infer the time unit from the timestamps (a fractional text value means seconds) and the resolution from the coordinate range. Passing sensor_size for HDF5 also skips that scan. time_unit is seconds/milliseconds/microseconds/nanoseconds (or auto); order (txyp/xytp) applies to text. topic selects the rosbag topic (default /davis/left/events). max_events caps how many events are read, handy for previewing very large files.

eventcv.open(path: str, *, dt_ms: float | None = None, repr: str | None = None, sensor_size: tuple[int, int] | None = None, time_unit: str | None = None, order: str = 'txyp', topic: str | None = None) EventReader[source]

Open a file for lazy slicing without loading it whole.

Where load() is OpenCV’s imread (read the entire stream eagerly), open is its VideoCapture: it returns an EventReader that points at the original file and fetches a slice on demand. For HDF5 this binary-searches the on-disk timestamps, so a slice of a multi-gigabyte recording costs a handful of reads — the file is never fully materialised. Other formats are loaded once and sliced in memory.

Pass dt_ms to treat the recording as a sequence of fixed-duration frames: the reader reports n_slices and reader.slice(n) returns the n-th frame (reader[n] works too). Frame n is measured from the recording start, so you never deal with absolute timestamps (which may be epoch-based). Without dt_ms, slice by explicit time/count window instead.

sensor_size and time_unit are auto-detected when omitted (see load()); order/topic match load(). For a multi-GB HDF5, pass sensor_size to skip the one-time coordinate scan resolution inference needs.

Pass repr (a representation name — "count", "voxel", "tsurf", "flow" for optical flow, …) to make the reader a PyTorch-style map dataset: len(reader) == n_slices, reader[i] returns the dense [C, H, W] array for frame i, and reader.batch(indices) stacks a [B, C, H, W] batch — so a DataLoader can collate the reader directly. Use reader.with_repr(name, **opts) to set per-representation options (e.g. bins=5, or window=5 for "flow"). Without repr, reader[i] stays a raw EventStream; to still batch those through a DataLoader pass collate_fn=eventcv.collate (each batch is a list[EventStream], since sparse streams can’t stack into a tensor).

Phase 5 algorithms apply per slice: reader.efast() / reader.harris_corners(thr) return a new reader whose every slice is the corner sub-stream, composing with slice/windows/with_repr. To render an algorithm as a video, map it over windows() and hand the frames to export_png() (then assemble with ffmpeg).

Note repr governs the array/dataset path (reader[i] → NumPy). To view a slice interactively, slice(i) returns the raw EventStream, so name the representation on the stream: data.slice(1000).view("flow") (or .slice(1000).optical_flow().view()).

Example:

r = eventcv.open("rec.hdf5", dt_ms=30)   # resolution + time unit auto-detected
r.n_slices                               # how many 30 ms frames
r.slice(50).mcts().view()                # the 50th 30 ms frame
for frame in r.windows():                # walk every frame (step defaults to dt_ms)
    voxel = frame.voxel()

# As a training dataset:
ds = eventcv.open("rec.hdf5", dt_ms=30, repr="count")
loader = torch.utils.data.DataLoader(ds, batch_size=32, shuffle=True)

# Corner-detection video (one PNG per frame):
corners = eventcv.open("rec.hdf5", dt_ms=30).efast()
eventcv.export_png((w.count() for w in corners.windows()), "corners/", colormap="turbo")
# Optical-flow video:
eventcv.export_png((w.optical_flow() for w in r.windows()), "flow/")
eventcv.save(obj, path: str, *, topic: str | None = None) None[source]

Save an EventStream or EventFrame to path.

The mirror of load(): the format is chosen by the file extension. Streams go to .npz/.txt/.h5/.bag (npz, HDF5, and rosbag round-trip exactly; txt stores t x y p and recovers the sensor size/unit on load via inference or options). Frames (computed representations) go to .npz or .h5, preserving shape, dtype, kind, and channel_names. topic names the rosbag connection. Equivalent to obj.save(path).

eventcv.load_frame(path: str) EventFrame[source]

Load an EventFrame written by save() (.npz or .h5).

Restores the representation’s shape, dtype, kind, and channel_names.

eventcv.export_png(frames, out_dir: str, *, colormap: str = 'viridis', normalize: bool = True, prefix: str = 'frame_', start: int = 0, digits: int = 5)[source]

Write one or many EventFrame s to numbered .png files — the “frame sequence → video frames” export.

frames is a single EventFrame or any iterable of them (e.g. a generator over a reader’s windows), so a whole recording renders lazily without materialising every frame at once:

r = eventcv.open("rec.hdf5", dt_ms=30)
eventcv.export_png((w.count() for w in r.windows()), "out/", colormap="turbo")

Each frame is colormapped through the same path as frame.save("x.png") (colormap: viridis/turbo/grayscale/redblue; normalize auto-contrasts). Files are named {prefix}{index:0{digits}d}.png counting from start. Returns the list of written paths (assemble a video with, e.g., ffmpeg -i out/frame_%05d.png out.mp4).

eventcv.collate(batch)[source]

collate_fn for torch.utils.data.DataLoader over an EventReader.

A reader opened with a representation (open(repr=…)) yields dense [C, H, W] arrays that torch’s default collate stacks into a [B, C, H, W] tensor with no help — so you only need this for a reader opened without repr, whose reader[i] is a raw EventStream. Those are variable-length and sparse, so they can’t stack into a tensor; this returns the batch as a plain list of streams instead (dense/array batches still defer to torch’s default collate). Pass it explicitly:

loader = torch.utils.data.DataLoader(reader, batch_size=32, collate_fn=eventcv.collate)
for batch in loader:        # batch is a list[EventStream]
    batch[0].view()

Core types

class eventcv.EventStream

Bases: object

atsurf(*, tau_ms=30.0)

Averaged time surface — the per-pixel mean of exp(-age/tau_ms) over all events (two polarity channels, float32). Brighter where activity recurs; see tsurf.

background_activity_filter(dt)

Background-activity (nearest-neighbour) noise filter: keeps an event only if a 3×3 neighbour fired within dt (raw timestamp units, e.g. microseconds).

concat(others)

Concatenates this stream with others (argument order; sensor = element-wise max).

count(*, normalize=True)

Event-count image — one channel of total events per pixel (both polarities). uint64 counts, or uint8 rescaled to the busiest pixel when normalize=True.

crop(x0, y0, w, h)

Keeps events inside the w`×`h window at (x0, y0), shifted to a new origin.

decimate(k)

Keeps every k-th event by index.

efast()

eFAST event corner detector (Mueggler et al., BMVC 2017). Keeps the events sitting on a moving corner, tested on two Bresenham rings over the per-polarity surface of active events.

filter_polarity(polarity)

Keeps only events of the given polarity (nonzero / True = ON, 0 / False = OFF).

flip_x()

Mirrors horizontally (x → width-1-x).

flip_y()

Mirrors vertically (y → height-1-y).

harris_corners(threshold=0.0)

Harris corner score on the Surface of Active Events: keeps events whose Harris response det - k·trace² of the SAE-ramp structure tensor exceeds threshold. The default threshold=0 keeps corners (rank-2, R>0) and rejects straight edges (rank-1, R<0); raise it to be stricter.

hot_pixel_filter(n_std=3.0)

Hot-pixel removal: drops pixels whose event count exceeds mean + n_std·std over the active pixels (default n_std=3.0).

invert_polarity()

Flips every event’s polarity.

mask(mask)

Keeps events where the (H, W) boolean mask is True.

normalize_time()

Shifts timestamps so the earliest event starts at zero.

optical_flow(*, window=3)

Dense Lucas-Kanade optical flow on the time surface. Returns a two-channel (flow_x, flow_y) frame in pixels/ms; window is the half-width of the least-squares neighbourhood.

refractory_filter(dt)

Refractory-period filter: suppresses a pixel’s events for dt after it fires.

repr

The default representation name carried from open(repr=…) / with_repr (what view()/flatten() render), or None for a raw stream.

resize(width, height)

Event-domain resize to a width`×`height grid (rebinned, not interpolated).

rotate90(k)

Rotates by k * 90° clockwise (quarter turns swap the sensor dims).

save(path, *, topic=None)

Saves the stream to path, format chosen by extension (.npz/.txt/.h5/.bag) — the counterpart of eventcv.load. npz/HDF5/rosbag round-trip exactly; topic names the rosbag connection.

scale(sx, sy)

Scales the sensor by (sx, sy).

sort_by_time()

Returns a copy reordered by ascending timestamp (stable).

time_scale(factor)

Scales every timestamp by factor (rounded).

time_shift(dt)

Shifts every timestamp by dt microseconds.

time_window(t0, t1)

Keeps events whose timestamp lies in the half-open window [t0, t1) (microseconds).

translate(dx, dy)

Translates by (dx, dy); events shifted off the sensor are dropped.

transpose()

Reflects across the main diagonal ((x, y) → (y, x)); swaps the sensor dims.

undistort(camera)

Rectifies events with a Camera’s intrinsics + distortion (lens undistortion).

view(representation=None, *, colormap='viridis', normalize=True)

Opens the interactive viewer on this stream. Pass a representation name to choose what to show — stream.view(“flow”), stream.view(“count”), stream.view(“voxel”), … — or omit it to use the stream’s stored representation (from open(repr=…)), falling back to the polarity image. (Equivalent to stream.<repr>().view().)

warp_affine(matrix)

Applies a 2×3 affine matrix [[a,b,c],[d,e,f]] (rounded, no interpolation).

warp_perspective(matrix)

Applies a 3×3 perspective (homography) matrix.

class eventcv.EventFrame

Bases: object

connected_components(*, connectivity=8)

Connected-component labelling (Phase 5): treats any non-zero pixel as foreground and labels each 4- or 8-connected blob 1..=k, background 0. Returns a single-channel u64 frame.

resize(width, height, *, pooling='average')

Resize spatial dimensions using average or sum pooling on shrinking axes.

save(path, *, colormap='viridis', normalize=True)

Saves the frame to path. .npz/.h5 store the raw array (shape, dtype, kind, channel_names) for eventcv.load_frame; .png writes a colormapped 2-D view (colormap = viridis/turbo/grayscale/redblue; normalize auto-contrasts).

view(*, colormap='viridis', normalize=True)

Opens the interactive GPU viewer. Image reprs are shown colour-mapped (colormap: viridis/turbo/grayscale/redblue; normalize auto-contrasts); volumetric reprs become an orbitable 3-D point cloud (drag to rotate, Esc to close).

class eventcv.EventReader

Bases: object

Lazy, seekable handle over a file’s events — the VideoCapture to load’s imread. Slices are fetched on demand (HDF5 by binary-searching its timestamps on disk), so multi-GB files never need to be fully resident. Opening with dt_ms fixes a frame duration so slice(n) returns the n-th frame (like seeking a video).

batch(indices)

Renders slice indices into one dense [B, C, H, W] array — the explicit-batch path for training. Requires a representation (open(repr=…) / with_repr). indices is any int sequence (list / range / …); each is a dt_ms frame index.

dt_ms

The fixed slice duration set at open, or None if it was not given.

efast()

Returns a new reader whose every slice is passed through [EventStream::efast], so the reader yields corner sub-streams (chain .count() / with_repr to visualise them).

harris_corners(threshold=0.0)

Returns a new reader whose every slice is passed through [EventStream::harris_corners].

n_slices

Number of fixed dt_ms slices spanning the recording (requires open(dt_ms=…)).

repr

The per-slice representation name set at open/with_repr, or None (raw streams).

slice(index=None, *, t0_ms=None, t1_ms=None)

One slice as an EventStream. With a positional index n (requires open(dt_ms=…)), returns the n-th fixed dt_ms frame measured from the recording start — [t_min + n·dt, t_min + (n+1)·dt); negative n counts from the end. Otherwise returns the half-open time window [t0_ms, t1_ms), with omitted bounds extending to the recording’s start / end.

slice_count(i0, i1)

Events whose index lies in [i0, i1) (clamped to the file).

windows(*, step_ms=None, span_ms=None)

Lazy iterator of consecutive windows: each is [start, start + span_ms) and start advances by step_ms. step_ms defaults to the dt_ms set at open (so windows() walks every slice(n)), and span_ms defaults to step_ms (non-overlapping). Streams a multi-GB file window-by-window without loading it.

with_repr(repr, *, bins=None, window_ms=None, tau_ms=None, max_window_ms=None, window=None, normalize=True)

Returns a new reader over the same file that renders each slice with repr (unset params take their method defaults). The dataset-mode counterpart of open(repr=…), but with per-representation options: e.g. reader.with_repr(“voxel”, bins=5).

class eventcv.EventPointSet

Bases: object

class eventcv.Camera(fx, fy, cx, cy, *, k1=0.0, k2=0.0, p1=0.0, p2=0.0, k3=0.0)

Bases: object

Pinhole intrinsics + Brown–Conrady distortion, e.g. an EV-IMO calib.txt (fx fy cx cy k1 k2 p1 p2). Pass to stream.undistort(camera).

undistort_point(u, v)

Maps a distorted pixel (u, v) to its undistorted location.

Functional (OpenCV-style) API

Each function below forwards to the identically named method on a stream or frame — e.g. eventcv.voxel(stream, bins=5) is stream.voxel(bins=5). They are generated by introspecting the compiled types, so this list always matches the methods above.

eventcv.atsurf(obj, *args, **kwargs)

Averaged time surface — the per-pixel mean of exp(-age/tau_ms) over all events

Free-function form of obj.atsurf(*args, **kwargs).

eventcv.background_activity_filter(obj, *args, **kwargs)

Background-activity (nearest-neighbour) noise filter: keeps an event only if a 3×3

Free-function form of obj.background_activity_filter(*args, **kwargs).

eventcv.concat(obj, *args, **kwargs)

Concatenates this stream with others (argument order; sensor = element-wise max).

Free-function form of obj.concat(*args, **kwargs).

eventcv.connected_components(obj, *args, **kwargs)

Connected-component labelling (Phase 5): treats any non-zero pixel as foreground and labels

Free-function form of obj.connected_components(*args, **kwargs).

eventcv.count(obj, *args, **kwargs)

Event-count image — one channel of total events per pixel (both polarities). uint64

Free-function form of obj.count(*args, **kwargs).

eventcv.crop(obj, *args, **kwargs)

Keeps events inside the w`×`h window at (x0, y0), shifted to a new origin.

Free-function form of obj.crop(*args, **kwargs).

eventcv.decimate(obj, *args, **kwargs)

Keeps every k-th event by index.

Free-function form of obj.decimate(*args, **kwargs).

eventcv.efast(obj, *args, **kwargs)

eFAST event corner detector (Mueggler et al., BMVC 2017). Keeps the events sitting on a

Free-function form of obj.efast(*args, **kwargs).

eventcv.filter_polarity(obj, *args, **kwargs)

Keeps only events of the given polarity (nonzero / True = ON, 0 / False = OFF).

Free-function form of obj.filter_polarity(*args, **kwargs).

eventcv.flatten(obj, *args, **kwargs)

Calls obj.flatten(...).

Free-function form of obj.flatten(*args, **kwargs).

eventcv.flip_x(obj, *args, **kwargs)

Mirrors horizontally (x → width-1-x).

Free-function form of obj.flip_x(*args, **kwargs).

eventcv.flip_y(obj, *args, **kwargs)

Mirrors vertically (y → height-1-y).

Free-function form of obj.flip_y(*args, **kwargs).

eventcv.harris_corners(obj, *args, **kwargs)

Harris corner score on the Surface of Active Events: keeps events whose Harris response

Free-function form of obj.harris_corners(*args, **kwargs).

eventcv.hot_pixel_filter(obj, *args, **kwargs)

Hot-pixel removal: drops pixels whose event count exceeds mean + n_std·std over the

Free-function form of obj.hot_pixel_filter(*args, **kwargs).

eventcv.invert_polarity(obj, *args, **kwargs)

Flips every event’s polarity.

Free-function form of obj.invert_polarity(*args, **kwargs).

eventcv.mask(obj, *args, **kwargs)

Keeps events where the (H, W) boolean mask is True.

Free-function form of obj.mask(*args, **kwargs).

eventcv.mcts(obj, *args, **kwargs)

Calls obj.mcts(...).

Free-function form of obj.mcts(*args, **kwargs).

eventcv.normalize_time(obj, *args, **kwargs)

Shifts timestamps so the earliest event starts at zero.

Free-function form of obj.normalize_time(*args, **kwargs).

eventcv.numpy(obj, *args, **kwargs)

Calls obj.numpy(...).

Free-function form of obj.numpy(*args, **kwargs).

eventcv.optical_flow(obj, *args, **kwargs)

Dense Lucas-Kanade optical flow on the time surface. Returns a two-channel `(flow_x,

Free-function form of obj.optical_flow(*args, **kwargs).

eventcv.pset(obj, *args, **kwargs)

Calls obj.pset(...).

Free-function form of obj.pset(*args, **kwargs).

eventcv.refractory_filter(obj, *args, **kwargs)

Refractory-period filter: suppresses a pixel’s events for dt after it fires.

Free-function form of obj.refractory_filter(*args, **kwargs).

eventcv.resize(obj, *args, **kwargs)

Event-domain resize to a width`×`height grid (rebinned, not interpolated).

Free-function form of obj.resize(*args, **kwargs).

eventcv.rotate90(obj, *args, **kwargs)

Rotates by k * 90° clockwise (quarter turns swap the sensor dims).

Free-function form of obj.rotate90(*args, **kwargs).

eventcv.scale(obj, *args, **kwargs)

Scales the sensor by (sx, sy).

Free-function form of obj.scale(*args, **kwargs).

eventcv.sort_by_time(obj, *args, **kwargs)

Returns a copy reordered by ascending timestamp (stable).

Free-function form of obj.sort_by_time(*args, **kwargs).

eventcv.tencode(obj, *args, **kwargs)

Calls obj.tencode(...).

Free-function form of obj.tencode(*args, **kwargs).

eventcv.time_scale(obj, *args, **kwargs)

Scales every timestamp by factor (rounded).

Free-function form of obj.time_scale(*args, **kwargs).

eventcv.time_shift(obj, *args, **kwargs)

Shifts every timestamp by dt microseconds.

Free-function form of obj.time_shift(*args, **kwargs).

eventcv.time_window(obj, *args, **kwargs)

Keeps events whose timestamp lies in the half-open window [t0, t1) (microseconds).

Free-function form of obj.time_window(*args, **kwargs).

eventcv.translate(obj, *args, **kwargs)

Translates by (dx, dy); events shifted off the sensor are dropped.

Free-function form of obj.translate(*args, **kwargs).

eventcv.transpose(obj, *args, **kwargs)

Reflects across the main diagonal ((x, y) → (y, x)); swaps the sensor dims.

Free-function form of obj.transpose(*args, **kwargs).

eventcv.tsurf(obj, *args, **kwargs)

Calls obj.tsurf(...).

Free-function form of obj.tsurf(*args, **kwargs).

eventcv.undistort(obj, *args, **kwargs)

Rectifies events with a Camera’s intrinsics + distortion (lens undistortion).

Free-function form of obj.undistort(*args, **kwargs).

eventcv.view(obj, *args, **kwargs)

Opens the interactive viewer on this stream. Pass a representation name to choose what

Free-function form of obj.view(*args, **kwargs).

eventcv.voxel(obj, *args, **kwargs)

Calls obj.voxel(...).

Free-function form of obj.voxel(*args, **kwargs).

eventcv.warp_affine(obj, *args, **kwargs)

Applies a 2×3 affine matrix [[a,b,c],[d,e,f]] (rounded, no interpolation).

Free-function form of obj.warp_affine(*args, **kwargs).

eventcv.warp_perspective(obj, *args, **kwargs)

Applies a 3×3 perspective (homography) matrix.

Free-function form of obj.warp_perspective(*args, **kwargs).