pixtreme.filter
filter
Blur, derivative, sharpening, and convolution filters.
__all__ = ('gaussian_blur', 'box_blur', 'median_blur', 'bilateral_blur', 'directional_blur', 'zoom_blur', 'spin_blur', 'vector_blur', 'lens_blur', 'sobel', 'laplacian', 'difference_of_gaussians', 'canny', 'sharpen', 'unsharp_mask', 'convolve_box')
module-attribute
bilateral_blur(frame, *, sigma_space, sigma_value, border='mirror', border_value=None)
Apply a bilateral blur using one all-channel value distance per neighbor.
Kernel radius is fixed as radius = ceil(3 * sigma_space). Border defaults
to mirror (edge-excluding reflection); replicate clamps to the edge
and wrap uses periodic indices. sigma_value is measured in the
Frame's working-value scale: changing scene-linear exposure changes its
meaning, and this function does not normalize values automatically.
constant uses border_value for every virtual pixel outside the image;
border_value is required with constant and forbidden for every other
border. The fp32 calculation does not clamp negative values or values above
1 and returns new storage with unchanged metadata.
box_blur(frame, *, size, border='mirror', border_value=None)
Replace each channel value with its square-window mean.
size is a positive odd integer. Border defaults to mirror
(edge-excluding reflection); replicate clamps to the edge and wrap
uses periodic indices. constant uses border_value for every virtual
pixel outside the image; border_value is required with constant and
forbidden for every other border. Calculation is fp32 per channel.
It does not clamp scene values; negative values and values above 1 pass through.
Size 1 is an identity in new storage.
canny(frame, *, threshold_low, threshold_high, border='mirror', border_value=None)
Detect binary edges in a float32 Frame with a deterministic Canny pipeline.
threshold_low and threshold_high are required nonnegative absolute
scene-gradient strengths on the non-normalized 3x3 Sobel scale. The
pipeline applies Sobel L2 magnitude, four-sector NMS, double thresholding,
and 8-connected hysteresis with complete convergence and no iteration cap.
NMS retains a sample exactly when current > magnitude(-v) and
current >= magnitude(+v); equal thresholds select a single-threshold
mode with no weak edge set. No Gaussian smoothing, normalization, or
grayscale conversion is implicit.
Border defaults to mirror; replicate clamps to the edge, wrap
is periodic, and constant requires a finite border_value. The same
border rule applies to Sobel source samples and NMS magnitude samples, but
hysteresis never connects through virtual pixels. Processing is per channel
without using channel labels. The result is a private C-contiguous float32
Frame containing only 0.0 and 1.0, with metadata preserved and the input
storage unchanged.
Convert non-float32 storage according to its value meaning with
px.values.cast_dtype, px.values.recode_dtype, or
px.values.dequantize before calling this operation.
convolve_box(frame, *, size, normalize, border='mirror', border_value=None)
Apply a rectangular moving sum or moving mean independently per channel.
size is one positive odd integer or (height, width). normalize
must be passed explicitly: true returns the window mean and false returns the
window sum. Border defaults to mirror (edge-excluding reflection);
replicate clamps to the edge and wrap uses periodic indices.
constant uses border_value for every virtual pixel outside the image;
border_value is required with constant and forbidden for every other
border. The fp32 calculation does not clamp negative values or values above
1 and always returns new storage, including size 1.
difference_of_gaussians(frame, *, sigma1, sigma2, border='mirror', border_value=None)
Subtract gaussian_blur(sigma2) from gaussian_blur(sigma1).
Each Gaussian uses the public gaussian_blur contract, including
radius = ceil(3 * sigma). sigma1 and sigma2 must be positive
finite real values. Their order is unrestricted and determines the sign;
equal sigmas produce a zero Frame without error.
Border defaults to mirror; replicate clamps to the edge, wrap
is periodic, and constant requires a finite border_value. The
float32 calculation applies independently and uniformly to all channels,
preserves Frame metadata and input storage, and does not clamp negative
values or values above 1. Convert non-float32 storage with
px.values.cast_dtype, px.values.recode_dtype, or px.values.dequantize.
laplacian(frame, *, border='mirror', border_value=None)
Apply the fixed non-normalized 3x3 Laplacian to a float32 Frame.
The kernel is [[0, 1, 0], [1, -4, 1], [0, 1, 0]]. No Gaussian
smoothing or LoG behavior is built in. Border defaults to mirror;
replicate clamps to the edge, wrap is periodic, and constant
requires a finite border_value. A uniform image is zero at every pixel
when a constant border uses the same uniform value.
The calculation applies independently and uniformly to all channels,
preserves Frame metadata and input storage, and does not clamp negative
values or values above 1. Convert non-float32 storage with
px.values.cast_dtype, px.values.recode_dtype, or px.values.dequantize.
sobel(frame, *, direction='magnitude', border='mirror', border_value=None)
Apply the standard non-normalized 3x3 Sobel derivative to a float32 Frame.
x uses derivative [-1, 0, 1] horizontally and smoothing
[1, 2, 1] vertically; it responds to vertical edges. y is the
transpose and responds to horizontal edges. magnitude is the default
and equals sqrt(x**2 + y**2) per channel. The scale is not normalized:
a unit horizontal ramp has an interior x response of 8.
Border defaults to mirror; replicate clamps to the edge, wrap
is periodic, and constant requires a finite border_value. The
calculation applies independently and uniformly to all channels, preserves
Frame metadata and input storage, and does not clamp negative values or
values above 1. Convert non-float32 storage with px.values.cast_dtype,
px.values.recode_dtype, or px.values.dequantize according to its meaning.
directional_blur(frame, *, angle, length, border='mirror', border_value=None)
Average a symmetric straight path through each pixel.
The path is p + t * (cos(angle), -sin(angle)) for t in
[-length / 2, +length / 2]. Angles use degrees: 0 degrees is +x and
positive is visually counterclockwise. Sampling uses
max(2, ceil(path length) + 1) uniformly weighted points and fixed
bicubic interpolation with Keys a = -0.5.
Border defaults to mirror; replicate and wrap are also
accepted and apply independently to every bicubic tap. constant uses
border_value for taps outside the image; border_value is required
with constant and forbidden for every other border. Calculation is fp32
per channel, does not clamp scene values, and returns new storage.
spin_blur(frame, *, angle, center=None, border='mirror', border_value=None)
Average a symmetric circular arc around center through each pixel.
The circular arc rotates p from -angle / 2 through +angle / 2.
Angles use degrees: 0 degrees is +x and positive is visually
counterclockwise. Center defaults to the geometric center and may lie
outside the image. Sampling uses max(2, ceil(path length) + 1)
uniformly weighted points with fixed bicubic interpolation using
Keys a = -0.5. Path length is center distance times angle in radians, so
cost grows with center distance.
Border defaults to mirror; replicate and wrap are also
accepted and apply independently to every bicubic tap. constant uses
border_value for taps outside the image; border_value is required
with constant and forbidden for every other border. Calculation is fp32
per channel, does not clamp scene values, and returns new storage.
zoom_blur(frame, *, amount, center=None, border='mirror', border_value=None)
Average a symmetric radial scale path through each pixel.
The path is center + (p - center) * s for s from 1 - amount / 2
through 1 + amount / 2. Center defaults to the geometric center and
may lie outside the image. Sampling uses
max(2, ceil(path length) + 1) uniformly weighted points with fixed
bicubic interpolation using Keys a = -0.5. Path length is center distance
times amount, so cost grows with center distance.
Border defaults to mirror; replicate and wrap are also
accepted and apply independently to every bicubic tap. constant uses
border_value for taps outside the image; border_value is required
with constant and forbidden for every other border. Calculation is fp32
per channel, does not clamp scene values, and returns new storage.
gaussian_blur(frame, *, sigma, border='mirror', border_value=None)
Apply an isotropic Gaussian blur without changing Frame metadata.
Kernel radius is fixed as radius = ceil(3 * sigma); discrete 2D
Gaussian weights are normalized by their sum. Border defaults to mirror
(edge-excluding reflection); replicate clamps to the edge and wrap
uses periodic indices. constant uses border_value for every virtual
pixel outside the image; border_value is required with constant and
forbidden for every other border. Calculation is fp32 per channel.
It does not clamp scene values; negative values and values above 1 pass through.
The result always owns a new allocation.
lens_blur(frame, *, radius, blades=None, rotation=None, border='mirror', border_value=None)
Convolve with a flat uniform aperture for spatially invariant bokeh.
This is the optical flat-aperture counterpart of lens blur: with
scene-linear input, highlights above 1.0 open into bokeh shaped like the
aperture. radius is the circle radius or a regular polygon's
circumradius. At the same radius, changing blades changes aperture area.
blades=None selects a circle; an integer of at least 3 selects a regular
polygon.
rotation is available only with blades. A vertex is at +x at
0 degrees, and positive rotation is visually counterclockwise. Every kernel
pixel uses partial coverage from a fixed 16 x 16 center-subsample grid, then
all nonzero coverage weights are normalized for convolution.
Border defaults to mirror; replicate clamps to the edge and wrap
uses periodic indexing. constant uses border_value outside the image.
border_value is required with constant and forbidden for every other
border. Calculation is fp32 independently per channel and does not clamp
negative scene values or values above 1. The result has new storage and
unchanged Frame metadata.
radius = 0 is an exact identity in new storage. A positive radius whose
fixed grid has zero aperture coverage follows the same exact identity rule.
Small apertures use direct convolution, whose cost grows in proportion to
radius squared; larger apertures use equivalent FFT convolution.
median_blur(frame, *, size, border='mirror', border_value=None)
Replace each channel value with its square-window median.
size is a positive odd integer from 1 through 7. Border defaults to
mirror (edge-excluding reflection); replicate clamps to the edge and
wrap uses periodic indices. constant uses border_value for every
virtual pixel outside the image; border_value is required with
constant and forbidden for every other border. Median selection is
independent per channel, uses fp32 values, and does not clamp negative
values or values above 1. The result always owns new storage, including
size 1.
sharpen(frame, *, amount, border='mirror', border_value=None)
Sharpen a float32 Frame with input - amount * laplacian(input).
The basis is the fixed non-normalized 3x3 Laplacian
[[0, 1, 0], [1, -4, 1], [0, 1, 0]] with no Gaussian smoothing.
amount is required, accepts any finite real except bool, and may be
negative. Zero returns a private bit-exact copy. Border defaults to
mirror; replicate clamps to the edge, wrap is periodic, and
constant requires a finite border_value. Other borders forbid
border_value.
The float32 calculation applies independently and uniformly to all channels
and does not clamp negative values, values above 1, or sharpening halos.
Frame metadata passes through and the input remains unchanged. Convert
non-float32 storage with px.values.cast_dtype, px.values.recode_dtype,
or px.values.dequantize according to its value meaning.
unsharp_mask(frame, *, sigma, amount, border='mirror', border_value=None)
Sharpen a float32 Frame with input + amount * (input - G(input)).
G is the same isotropic Gaussian as :func:gaussian_blur: its kernel
radius is fixed as radius = ceil(3 * sigma) and its discrete weights are
normalized by their sum. amount may be negative; zero returns a private
bit-exact copy. Border defaults to mirror (edge-excluding reflection),
replicate clamps to the edge, and wrap uses periodic indices.
constant uses border_value outside the image; border_value is
required with constant and forbidden for every other border.
The fp32 calculation applies independently and uniformly to all channels,
including alpha, and does not clamp negative values, values above 1, or
sharpening halos. Frame metadata passes through and the input remains
unchanged. Convert float16 literal values first with
px.values.cast_dtype(frame, dtype="float32"); use px.values.recode_dtype or
px.values.dequantize for integer storage according to its value meaning.
vector_blur(frame, *, vector, shutter='centered', border='mirror', border_value=None)
Average a per-pixel straight line selected by one gather vector.
For output pixel p, the path is p + t * v(p): v(p) is read once at p,
and the vector field is not followed again along the path. This gather
contract cannot create the scatter-style contribution of a moving object
across a motion boundary; that visual limitation is intentional.
Vector channel 0 = x and channel 1 = y by position, independent of labels.
Coordinates are measured in pixels without y inversion: +x is right; +y is down.
centered integrates t in [-1/2, +1/2], forward uses
[0, 1], and backward uses [-1, 0]. Every interval has length 1.
The uniformly weighted endpoint-inclusive sample count is
max(2, ceil(|v(p)|) + 1). Sampling uses fixed bicubic interpolation with
Keys a = -0.5. mirror is the default border; replicate and wrap
use edge clamp and periodic indexing. constant uses border_value for
every out-of-image bicubic tap. border_value is required with
constant and forbidden for every other border.
Geometry, samples, and accumulation use fp32 independently per channel and the result does not clamp negative values or values above 1. Vector values are assumed finite and are not checked; output for non-finite vectors is undefined. The result owns new storage with frame metadata unchanged, and computational cost grows in proportion to |v|.