an.media.shutter#
The temporal half of the frame stage: average several instants into one frame.
supersample.py resolves a frame SPATIALLY — k x k pixels into one. This module
resolves it TEMPORALLY — the screenshots taken at each of a frame’s sample
instants (RenderContext.frame_samples, built by
an.frame_clock.FrameClock) into the one frame a camera with an open
shutter would have recorded. Same place, same rules: the resolve runs in the
frame stage, so everything downstream still sees PNGs at the declared size, and
the rounding is spelled out rather than inherited.
One sample is free. A frame with a single instant keeps the bytes the
spatial path produces (Chromium’s own, at supersample == 1), so a render
without an open shutter is byte-identical to one from before this module.
Engine-independent, like the spatial half: moved from
an/adapters/cutout/shutter.py (an#247), which re-exports it.
Functions
|
Validate |
|
Spatially resolve each screenshot by |
|
|
Exceptions
Frame samples a render cannot honour. |
- exception an.media.shutter.ShutterError[source]#
Bases:
ValueErrorFrame samples a render cannot honour.
- an.media.shutter.check_frame_samples(frame_samples, *, total_frames, duration)[source]#
Validate
frame_samplesagainst the render it is for; normalise to tuples.Checked before a browser launches, for
check_factor’s reason: the render costs minutes and this costs microseconds.>>> check_frame_samples(None, total_frames=3, duration=0.1) is None True >>> check_frame_samples([[0.0], [0.5, 0.6]], total_frames=2, duration=1.0) ((0.0,), (0.5, 0.6)) >>> check_frame_samples([[0.0]], total_frames=2, duration=1.0) Traceback (most recent call last): ... an.media.shutter.ShutterError: frame_samples has 1 frame(s) but this render has 2; a frame clock must describe every frame, and only those
- an.media.shutter.mean_png_bytes(shots, *, factor)[source]#
Spatially resolve each screenshot by
factor, then average them in time.One screenshot takes exactly the spatial path — the same bytes a render without a shutter writes.
- Return type:
- an.media.shutter.temporal_mean(frames)[source]#
kequal-shape uint8 frames -> their exact per-pixel mean, uint8.Rounded half-to-even, the rule
block_mean_resolvespells out, so the temporal and spatial resolves agree about every tie. The mean is of the ENCODED (sRGB) values, as the spatial resolve’s is — not of linear light, so a smear’s profile is not exactly a physical sensor’s. The centroid of what is drawn is still the average of the sampled positions, which is the property the impact ground truth relies on.- Return type:
>>> import numpy as np >>> a, b = np.full((1, 2, 3), 1, np.uint8), np.full((1, 2, 3), 2, np.uint8) >>> temporal_mean([a, b])[0, 0].tolist() # 1.5 -> 2 (even) [2, 2, 2] >>> temporal_mean([a, a + 2])[0, 0].tolist() # 2.0 exactly [2, 2, 2] >>> temporal_mean([a]) is a True