xpark.dataset.VideoOpticalFlow#
- class xpark.dataset.VideoOpticalFlow(*, output_dir: str | None = None, fps: float = 4.0, num_frames: int | None = 12, window_size: int = 8, max_pixels: int | None = None, min_pixels: int | None = None, backend: type[~xpark.dataset.processors.video_optical_flow.OpticalFlowBackend] = <class 'xpark.dataset.processors.video_optical_flow.FarnebackBackend'>, backend_kwargs: dict[str, ~typing.Any] | None = None, score_fn: ~typing.Callable[[~numpy.ndarray], ~numpy.ndarray] = <function flow_map_magnitude_norm>)#
Dense optical flow for a video: a per-pair score, plus the persisted field.
Samples frames, feeds each adjacent pair through a backend, and emits a
{uri, score}struct — onescoreper adjacent pair, produced byscore_fn. Withoutput_dirthe field is also persisted as{output_dir}/{basename}-{digest}/flow.npy, wheredigestis over the whole source string so same-named sources in different directories stay apart.score_fnreceives the whole(P, 2, H, W)field — everything it needs (field width, pair count) is derivable from the field’s shape — and returns one score per pair. The built-inflow_map_magnitude_norm()(default) returns the mean vector length divided by the field width: motion as a fraction of frame width, roughly resolution-independent, so one threshold covers several resolutions / backends.All backends are
OpticalFlowBackendsubclasses, instantiated on the worker:FarnebackBackend(default, cv2 Farneback),RaftBackend(torchvision RAFT),MemfofBackend(multi-frame RAFT-family model), or a custom subclass.The operator only measures — keep/drop is left to
Dataset.filter(); reduce the per-pair list (e.g.max) before comparing to a threshold:ds = ds.with_column( "flow", VideoOpticalFlow().options(num_workers={"CPU": 8}).with_column(col("video")), )
Input accepts a local path, a remote URI (
cos:///s3:///http(s)://) or raw bytes;output_dirtakes the same protocols. An undecodable video returns an emptyscorelist instead of failing the batch.Parity with ffmpeg-sampled pipelines: frames are decoded by timestamp (
pts <= ts, floor semantics), while ffmpeg’sfpsfilter picks the nearest frame — expect a ±1-frame sampling difference. Compare thresholds on the default normalizedscore. The resize kernel is not this operator’s concern — feed frames through a shared resizer operator when the sampling must match another pipeline’s resize exactly.- Parameters:
output_dir – Directory the flow fields are written to (field mode).
None(default) keeps the operator scalar-only.fps – Sampling rate in frames per second. Defaults to
4.0.num_frames – Upper bound on sampled frames. Defaults to
12;Nonesamples the whole clip.window_size – Frames decoded per pass; consecutive windows share their boundary frame, so pairs stay continuous. Defaults to
8.max_pixels – Upper bound on each frame’s pixel count; larger frames are downscaled.
None(default) applies the smart_resize budget default of 65536 (~256x256).min_pixels – Lower bound on each frame’s pixel count; smaller frames are upscaled.
None(default) applies the smart_resize budget default of 16.backend – An
OpticalFlowBackendsubclass, instantiated on the worker withbackend_kwargs. Defaults toFarnebackBackend.backend_kwargs – Keyword arguments for the
backendclass constructor.score_fn – Field-to-score function,
score_fn(flow field) -> float, applied to each(P, 2, H, W)flow field; Defaults toflow_map_magnitude_norm().
Methods
__call__(videos)Process a batch of videos, returning one
{uri, score}struct per row.options(**kwargs)with_column(videos)Process a batch of videos, returning one
{uri, score}struct per row.- __call__(videos: pa.ChunkedArray) pa.Array#
Process a batch of videos, returning one
{uri, score}struct per row.
- options(**kwargs: Unpack[ExprUDFOptions]) Self#
- with_column(videos: pa.ChunkedArray) pa.Array#
Process a batch of videos, returning one
{uri, score}struct per row.