Entry point¶
vidmag.magnify(video, *, preset=None, backend='auto', precision='fp32', fps=None, out=None, drop_last=0, **overrides)
¶
Magnify a clip with a named preset, on the best available backend.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
video
|
str | PathLike[str] | ndarray | Iterable[ndarray]
|
a path to a video file, a |
required |
preset
|
str | None
|
which preset to run; see :data: |
None
|
backend
|
str
|
|
'auto'
|
precision
|
str
|
|
'fp32'
|
fps
|
float | None
|
the clip's frame rate. Read from the file for path input (pass it
to override); required for array input whenever the pipeline's
temporal band is in Hz, or whenever |
None
|
out
|
str | PathLike[str] | None
|
write the result to this path as H.264 as well as returning it. |
None
|
drop_last
|
int
|
drop this many frames from the end before magnifying.
Defaults to 0 — see the module docstring, plan decision D8. Pass 10
to reproduce the MATLAB reference and the |
0
|
**overrides
|
Any
|
individual preset parameters to replace, e.g.
|
{}
|
Returns:
| Type | Description |
|---|---|
ndarray
|
The magnified clip, |
ndarray
|
the input frames. |
Raises:
| Type | Description |
|---|---|
ValueError
|
no preset, an unusable precision, or a missing frame rate. |
KeyError
|
an unknown preset name (the message lists the known ones). |
BackendError
|
the named backend is unknown or unavailable. |
Source code in src/vidmag/api.py
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 | |
Presets¶
vidmag.presets
¶
Named parameter sets for the four magnification pipelines.
One frozen table, :data:PRESETS, is the single source of truth for every
"just magnify it" entry point — the facade, the CLI and the docs all read it,
so a preset's numbers exist in exactly one place.
Each row records three things: which pipeline it selects, the parameters, and
what it is for. A fourth field, source, names the place in this repository
the numbers were taken from; nothing is in this table that cannot be traced to
a call the project already makes and checks.
Preset.pipeline is a pipeline stem. It resolves two ways, and both are
the same pipeline:
stem "motion_lpyr_iir" -> vidmag.cpu.magnify.motion_lpyr_iir_core(frames, fps, **params)
-> vidmag.magnify_motion_lpyr_iir(in_path, out_path, **params)
fl / fh are in Hz and are interpreted against the clip's own frame
rate. No preset pins sampling_rate: the reference calls pass it explicitly
only because their clips happen to be 30 fps, and hard-coding 30 into a preset
would silently mis-filter every clip that is not (see pulse below, where
that difference is a no-op on the reference clip and a correctness fix on any
other).
PRESETS = MappingProxyType({'pulse': Preset(pipeline='color_gdown_ideal', params=MappingProxyType({'alpha': 50.0, 'level': 4, 'fl': 50 / 60, 'fh': 60 / 60, 'chrom_attenuation': 1.0}), description='Human pulse: the colour change blood flow makes in skin, banded to 50-60 bpm. Faces, wrists, babies.', source="tests/test_against_mit_reference.py::test_face_color_matches_mit — reproduceResults.m's face.mp4 call, checked against MIT's own render face-ideal-from-0.83333-to-1-alpha-50-level-4-chromAtn-1.mp4. That call also passes sampling_rate=30.0; this preset omits it because face.mp4 is exactly 30.0 fps, so the core's default (the clip's own fps) reproduces the call byte for byte while staying correct on clips at other frame rates."), 'motion': Preset(pipeline='motion_lpyr_iir', params=MappingProxyType({'alpha': 10.0, 'lambda_c': 16.0, 'r1': 0.4, 'r2': 0.05, 'chrom_attenuation': 0.1}), description="Sub-pixel motion at everyday speeds: an infant's breathing, a chest rising, a swaying structure. The r1/r2 IIR band is sampling-rate free, so this preset needs no fps assumption.", source="tests/test_against_mit_reference.py::test_baby_iir_matches_mit — reproduceResults.m's baby.mp4 call, checked against MIT's own render baby-iir-r1-0.4-r2-0.05-alpha-10-lambda_c-16-chromAtn-0.1.mp4."), 'motion_phase': Preset(pipeline='phase', params=MappingProxyType({'alpha': 15.0, 'fl': 0.5, 'fh': 1.5, 'scales': 3, 'orientations': 4, 'sigma': 0.0}), description="The same sub-pixel motion as 'motion', but amplified by changing phase rather than by scaling image detail. Slower, and it holds together at amplifications where the other method tears into ripples at edges. Use it when 'motion' produces artefacts before it produces a visible movement.", source="Wadhwa, Rubinstein, Durand and Freeman, 'Phase-Based Video Motion Processing', SIGGRAPH 2013. The parameters here are a starting point rather than a reproduction of a published call: unlike the other presets, this one is NOT checked against the authors' own rendered output, because that output is not among the files this project can fetch. What is checked, in tests/test_phase_based.py, is that a clip built with a known sub-pixel movement comes out moved by the predicted amount."), 'vibration': Preset(pipeline='motion_lpyr_ideal', params=MappingProxyType({'alpha': 50.0, 'lambda_c': 10.0, 'fl': 72.0, 'fh': 92.0, 'chrom_attenuation': 0.0}), description='Mechanical vibration in a narrow band — the guitar low-E string at 72-92 Hz. REQUIRES A HIGH-SPEED CLIP: those cutoffs are above Nyquist for anything under ~184 fps, where the ideal bandpass passes nothing and the output is the input.', source='scripts/run_evm.py module docstring, the guitar.mp4 E-string example (--mode motion --alpha 50 --lambda-c 10 --fl 72 --fh 92 --chromatt 0). Weaker provenance than the two above: this repository downloads guitar.mp4 (scripts/download_samples.py) but holds no MIT render of it, so nothing here checks the result — unlike pulse and motion, which the MIT-reference tests measure.')})
module-attribute
¶
Preset
¶
Bases: NamedTuple
One row of :data:PRESETS.
pipeline is the stem shared by the array core
(<stem>_core in :mod:vidmag.cpu.magnify) and the path function
(magnify_<stem>); params are keyword arguments for either.
Source code in src/vidmag/presets.py
get(name)
¶
Look up a preset by name, naming the alternatives when there is no match.
Source code in src/vidmag/presets.py
Choosing a backend¶
vidmag.backend.registry
¶
The backend registry — names to implementations, with capability flags.
docs/dev/PLAN.md section 3c, step 3.5. Three properties matter more than the
code:
Registration is data. :func:register stores two callables and a capability
record; neither is called. The implementation module is imported the first time
somebody selects that backend, so import vidmag on a machine with no GPU never
touches the CUDA extension.
Nothing fails quietly. An unknown name lists what is registered, an
unavailable backend repeats the reason its probe gave (no driver, no device,
extra not installed), and "auto" with nothing usable reports every candidate
it tried and why each failed. Falling back from GPU to CPU by accident would cost
roughly 700x, so it never happens implicitly — "auto" reports its choice
through the returned name and an INFO log line, and an explicitly named backend
that is unavailable raises rather than substituting another.
The order is fixed and documented: :data:PREFERENCE_ORDER.
Capabilities
dataclass
¶
What a backend can do, readable without importing it.
Source code in src/vidmag/backend/registry.py
select(name='auto')
¶
Resolve a backend name to (resolved_name, implementation).
The resolved name is returned so the caller can show it — the choice is
never silent. "auto" walks :data:PREFERENCE_ORDER and takes the first
registered backend whose probe says it can run.
Raises:
| Type | Description |
|---|---|
UnknownBackendError
|
the name was never registered. |
BackendUnavailableError
|
the named backend cannot run here, or
|
Source code in src/vidmag/backend/registry.py
list_backends()
¶
Every registered backend, in preference order, with its availability.
Probes each backend, so the reasons are current. Does not load any implementation.
Source code in src/vidmag/backend/registry.py
register(name, *, load, probe, capabilities)
¶
Record a backend without importing it.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
selection name, e.g. |
required |
load
|
Callable[[], Any]
|
called at most once, on first selection; returns the object
implementing :class: |
required |
probe
|
Callable[[], str | None]
|
called on every selection attempt; returns |
required |
capabilities
|
Capabilities
|
advertised without loading anything. |
required |
Raises:
| Type | Description |
|---|---|
ValueError
|
if the name is already registered. |