Image quality#

kornia.metrics.psnr(image, target, max_val)[source]#

Compute the peak signal-to-noise ratio (PSNR), in dB, between two images.

score = psnr(image, target, max_val) takes two images of the same shape (*) and their data range \(\text{MAX}_I\), and returns the PSNR for the mean squared error over all \(N\) elements:

\[\text{PSNR} = 10 \log_{10} \bigg(\frac{\text{MAX}_I^2}{\text{MSE}}\bigg), \quad \text{MSE} = \frac{1}{N}\sum_{k=1}^{N} (I_k - T_k)^2\]
Convention:
  • One MSE is pooled over every element, batch and channels included, so for a batch the score is the PSNR of the pooled MSE, not the mean of per-image PSNRs: compute per-image values one image at a time. Losses and metrics maps both onto scikit-image and torchmetrics.

  • max_val is the data range of the images (1.0 for [0, 1], 255.0 for [0, 255]), not the maximum of the tensor; pixel values are not rescaled.

  • The shapes must match, without broadcasting, and the value is symmetric in the images. Identical inputs give an MSE of 0 and inf, while a batch with one identical pair stays finite.

  • Integer and bool images are converted to float32 before computing the MSE, so an integer image paired with a half-precision image gives a float32 result. Uint8, int8, int16 and int32 tensor data ranges are widened to int64 before squaring to avoid overflow, except when the promoted image dtype is float16 or bfloat16, which uses float32 range arithmetic.

  • Float16 and bfloat16 inputs are evaluated in float32 and the result keeps their promoted dtype, also promoted with max_val.dtype for a tensor range: a float32 tensor range gives a float32 result for half-precision images.

Parameters:
  • image (Tensor) – the image with shape (*).

  • target (Tensor) – the reference image with the shape of image.

  • max_val (float | int | Tensor) – the data range \(\text{MAX}_I\) of the images, as a float, integer or tensor.

Return type:

Tensor

Returns:

the PSNR in dB, a 0-d tensor for a scalar range or with the shape of a tensor range.

See also

  • psnr_loss(): the negative PSNR, to minimise.

  • PSNRLoss: the module form of that loss.

  • ssim(): a structural measure of the same pair, per pixel and bounded.

Examples

>>> ones = torch.ones(1)
>>> psnr(ones, 1.2 * ones, 2.) # 10 * log(4/((1.2-1)**2)) / log(10)
tensor(20.0000)
Reference:

https://en.wikipedia.org/wiki/Peak_signal-to-noise_ratio#Definition

kornia.metrics.ssim(img1, img2, window_size, max_val=1.0, eps=1e-12, padding='same')[source]#

Compute the per-pixel structural similarity (SSIM) map between two images.

ssim_map = ssim(img1, img2, window_size) takes two (B, C, H, W) images and returns the SSIM index at every pixel, channel and sample; average the map for a score.

\[\text{SSIM}(x, y) = \frac{(2\mu_x\mu_y+c_1)(2\sigma_{xy}+c_2)} {(\mu_x^2+\mu_y^2+c_1)(\sigma_x^2+\sigma_y^2+c_2)}\]
Convention:
  • The window is a sampled Gaussian with \(\sigma = 1.5\) whatever window_size, which sets only the number of taps and must be odd.

  • padding='same' pads with 'reflect', the torch mode that Filtering maps onto OpenCV and scipy, and keeps (H, W); 'valid' drops window_size // 2 pixels on every side and equals the 'same' map cropped. Reflected borders extend across any positive spatial axis length, including a singleton axis.

  • max_val is the data range \(L\), a Python float: \(c_1 = (0.01 L)^2\) and \(c_2 = (0.03 L)^2\). Pixel values are not rescaled, so images in [0, 255] need max_val=255.0. eps is added to the denominator: two identical flat images of value \(\mu\) score \(1 - \text{eps} / ((2\mu^2 + c_1)\, c_2 + \text{eps})\). With the default eps=1e-12, black images score about 0.99998889 at max_val=1.0; the bias grows to 0.1 at max_val=0.1. Use eps=0.0 to omit this denominator term when matching reference implementations.

  • The map is symmetric in img1 and img2, in \([-1, 1]\) in exact arithmetic and negative for anti-correlated content. Losses and metrics maps its mean onto scikit-image, pytorch-msssim and torchmetrics.

  • padding accepts 'same' and 'valid' case-insensitively; unsupported values raise BaseError.

Parameters:
  • img1 (Tensor) – the first image with shape (B, C, H, W).

  • img2 (Tensor) – the second image with the shape of img1.

  • window_size (int) – size of the Gaussian window in pixels, a positive odd integer.

  • max_val (float, optional) – data range \(L\) of the images, as a Python float. Default: 1.0

  • eps (float, optional) – term added to the denominator. Default: 1e-12

  • padding (str, optional) – 'same' keeps the spatial size; 'valid' keeps only the area where the window fits, as the MATLAB implementation of the SSIM paper does. Default: "same"

Return type:

Tensor

Returns:

the SSIM map with shape (B, C, H, W), or (B, C, H - 2p, W - 2p) with p = window_size // 2 under padding='valid'.

Note

Integer images are converted to float32 before computing the local moments. Half-precision inputs are evaluated in float32 for numerical stability. A float32/float64 pair is filtered in float64, with the Gaussian window built in that dtype. Filtering runs with autocast disabled; the result uses the promoted input dtype. On the CPU with oneDNN, when no gradient is recorded, two contiguous images computed in float32 are filtered in channels-last layout, which oneDNN convolves without first copying the image into blocks of 8 or 16 channels. The map agrees with the NCHW convolutions to rounding and is returned contiguous. Builds without oneDNN, such as the macOS arm64 wheels, oneDNN switched off with torch.backends.mkldnn, torch.func transforms, and exported and traced graphs keep the NCHW convolutions.

See also

  • SSIM: the module form.

  • ssim3d(): the same map for volumes.

  • ssim_loss(): the dissimilarity \((1 - \text{SSIM}) / 2\), clamped to \([0, 1]\).

  • psnr(): a pixel-error measure of the same pair, as one score in dB.

Examples

>>> input1 = torch.rand(1, 4, 5, 5)
>>> input2 = torch.rand(1, 4, 5, 5)
>>> ssim_map = ssim(input1, input2, 5)  # 1x4x5x5
kornia.metrics.ssim3d(img1, img2, window_size, max_val=1.0, eps=1e-12, padding='same')[source]#

Compute the per-voxel structural similarity (SSIM) map between two volumes.

ssim_map = ssim3d(img1, img2, window_size) takes two (B, C, D, H, W) volumes and returns the SSIM index at every voxel, channel and sample; average the map for a score. The formula is that of ssim(), with an isotropic Gaussian window over (D, H, W).

Convention:

See the Convention block of ssim() for the window, reflected border, padding and max_val; 'valid' crops every axis. A volume of identical slices reproduces the 2-D map up to floating-point roundoff.

Parameters:
  • img1 (Tensor) – the first volume with shape (B, C, D, H, W).

  • img2 (Tensor) – the second volume with the shape of img1.

  • window_size (int) – size of the Gaussian window in voxels, a positive odd integer.

  • max_val (float, optional) – data range \(L\) of the volumes, as a Python float. Default: 1.0

  • eps (float, optional) – term added to the denominator. Default: 1e-12

  • padding (str, optional) – 'same' keeps the spatial size; 'valid' keeps only the area where the window fits. Default: "same"

Return type:

Tensor

Returns:

the SSIM map with shape (B, C, D, H, W), or (B, C, D - 2p, H - 2p, W - 2p) with p = window_size // 2 under padding='valid'.

Note

The volume is reflected at its faces for padding='same', as kornia.metrics.ssim() does for images, across any positive spatial size, including D = 1. The Gaussian window is built on the device of the inputs, in the dtype they are filtered in. Integer images are converted to float32 before computing the local moments. Half-precision inputs are evaluated in float32 for numerical stability. Filtering runs with autocast disabled; the result uses the promoted input dtype. On CUDA the float32 filtering follows torch.backends.cudnn.allow_tf32, which PyTorch enables by default. cuDNN can then filter a single-channel volume with a TF32 kernel, which rounds the inputs of the local moments to 10 mantissa bits. The variances are differences of those moments, so in flat regions the map can be off by more than 1e-2. Set torch.backends.cudnn.allow_tf32 = False when float32 accuracy matters.

See also

  • SSIM3D: the module form.

  • ssim(): the same map for images.

  • ssim3d_loss(): the dissimilarity \((1 - \text{SSIM}) / 2\), clamped to \([0, 1]\).

Examples

>>> input1 = torch.rand(1, 4, 5, 5, 5)
>>> input2 = torch.rand(1, 4, 5, 5, 5)
>>> ssim_map = ssim3d(input1, input2, 5)  # 1x4x5x5x5
class kornia.metrics.SSIM(window_size, max_val=1.0, eps=1e-12, padding='same')[source]#

Compute the per-pixel structural similarity (SSIM) map between two images (module form).

criterion = SSIM(window_size, ...) stores its arguments, and ssim_map = criterion(img1, img2) is ssim() on two (B, C, H, W) images.

Convention:

See the Convention block of ssim().

Parameters:
  • window_size (int) – size of the Gaussian window in pixels, a positive odd integer.

  • max_val (float, optional) – data range \(L\) of the images, as a Python float. Default: 1.0

  • eps (float, optional) – term added to the denominator. Default: 1e-12

  • padding (str, optional) – 'same' or 'valid', as in ssim(). Default: "same"

Shape:
  • img1: (B, C, H, W).

  • img2: (B, C, H, W).

  • Output: (B, C, H, W), or (B, C, H - 2p, W - 2p) with p = window_size // 2 under padding='valid'.

See also

  • ssim(): the one-call form.

  • SSIM3D: the same map for volumes.

  • SSIMLoss: the dissimilarity loss built on this map.

Examples

>>> input1 = torch.rand(1, 4, 5, 5)
>>> input2 = torch.rand(1, 4, 5, 5)
>>> ssim = SSIM(5)
>>> ssim_map = ssim(input1, input2)  # 1x4x5x5
class kornia.metrics.SSIM3D(window_size, max_val=1.0, eps=1e-12, padding='same')[source]#

Compute the per-voxel structural similarity (SSIM) map between two volumes (module form).

criterion = SSIM3D(window_size, ...) stores its arguments, and ssim_map = criterion(img1, img2) is ssim3d() on two (B, C, D, H, W) volumes.

Convention:

See the Convention block of ssim3d().

Parameters:
  • window_size (int) – size of the Gaussian window in voxels, a positive odd integer.

  • max_val (float, optional) – data range \(L\) of the volumes, as a Python float. Default: 1.0

  • eps (float, optional) – term added to the denominator. Default: 1e-12

  • padding (str, optional) – 'same' or 'valid', as in ssim3d(). Default: "same"

Shape:
  • img1: (B, C, D, H, W).

  • img2: (B, C, D, H, W).

  • Output: (B, C, D, H, W), or (B, C, D - 2p, H - 2p, W - 2p) with p = window_size // 2 under padding='valid'.

See also

  • ssim3d(): the one-call form.

  • SSIM: the same map for images.

  • SSIM3DLoss: the dissimilarity loss built on this map.

Examples

>>> input1 = torch.rand(1, 4, 5, 5, 5)
>>> input2 = torch.rand(1, 4, 5, 5, 5)
>>> ssim = SSIM3D(5)
>>> ssim_map = ssim(input1, input2)  # 1x4x5x5x5