Skip to content

pixtreme.metrics

metrics

Image quality measurements.

__all__ = ('psnr', 'ssim', 'ssim_map') module-attribute

psnr(reference, candidate, *, data_range=1.0)

Return full-reference peak signal-to-noise ratio on the GPU.

Exact signature: px.metrics.psnr(reference, candidate, *, data_range=1.0). Both inputs must be float32 Frame objects whose height, width, channels, colorspace, gamma, and matrix match literally. data_range is the caller-declared positive finite signal range and defaults to 1.0; it is not inferred from pixels, dtype, or metadata. Across all channels and spatial samples at once, MSE = sum((reference - candidate)**2) / (H * W * C) and PSNR = 10 * log10(data_range**2 / MSE). Exact finite matches return +inf. The float32 calculation does not clamp scene values or scan and replace non-finite inputs.

The result is a private 0D float32 cupy.ndarray with new storage and no Frame metadata. It is GPU-resident and this call does not mutate either input. Choosing float(result) or result.item() performs explicit synchronization to obtain a host scalar. Convert non-float32 storage according to its meaning with px.values.cast_dtype, px.values.recode_dtype, or px.values.dequantize. To measure luma, apply px.color.rgb_to_grayscale to both inputs first; use px.channel.shuffle for explicit channel selection or routing.

ssim(reference, candidate, *, data_range=1.0)

Return the spatial mean of the valid full-reference SSIM map on the GPU.

Exact signature: px.metrics.ssim(reference, candidate, *, data_range=1.0). Both inputs must be float32 Frame objects whose height, width, channels, colorspace, gamma, and matrix match literally. data_range is the caller-declared positive finite signal range and defaults to 1.0; pixels are never used to infer it. The metric uses a normalized 11x11 Gaussian window with sigma=1.5, weighted population variance and covariance, C1 = (0.01 * data_range)**2, and C2 = (0.03 * data_range)**2. It evaluates each channel independently, takes the channel mean at each valid position, then takes the float32 spatial mean over all channels' local contributions. It does not clamp scene values or replace non-finite inputs.

The result is a private 0D float32 cupy.ndarray with new storage and no Frame metadata. It is GPU-resident and this call does not mutate either input. Choosing float(result) or result.item() performs explicit synchronization to obtain a host scalar. Convert non-float32 storage according to its meaning with px.values.cast_dtype, px.values.recode_dtype, or px.values.dequantize. To measure luma, apply px.color.rgb_to_grayscale to both inputs first; use px.channel.shuffle for explicit channel selection or routing.

ssim_map(reference, candidate, *, data_range=1.0)

Return the valid full-reference SSIM response map on the GPU.

Exact signature: px.metrics.ssim_map(reference, candidate, *, data_range=1.0). Both inputs must be float32 Frame objects whose height, width, channels, colorspace, gamma, and matrix match literally. data_range is the caller-declared positive finite signal range and defaults to 1.0; pixels are never used to infer it. Each valid 11x11 Gaussian window uses sigma=1.5, weighted population variance and covariance, C1 = (0.01 * data_range)**2, and C2 = (0.03 * data_range)**2. The expression is evaluated independently for all channels, followed by a channel mean. There is no padding: HWC input produces the 2D shape (H - 10, W - 10). The calculation does not clamp scene values or replace non-finite inputs.

The result is a private C-contiguous 2D float32 cupy.ndarray with new storage and no Frame metadata, and this call does not mutate either input. Convert non-float32 storage according to its meaning with px.values.cast_dtype, px.values.recode_dtype, or px.values.dequantize. For visualization, add a length-one channel dimension and call px.io.from_array with explicit metadata. To measure luma, apply px.color.rgb_to_grayscale to both inputs first; use px.channel.shuffle for explicit channel selection or routing.