Image quality#

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

Create a function that calculates the PSNR between 2 images.

PSNR is the Peak Signal to Noise Ratio. For one m x n image, the PSNR is:

\[\text{PSNR} = 10 \log_{10} \bigg(\frac{\text{MAX}_I^2}{MSE(I,T)}\bigg)\]

where

\[\text{MSE}(I,T) = \frac{1}{mn}\sum_{i=0}^{m-1}\sum_{j=0}^{n-1} [I(i,j) - T(i,j)]^2\]

and \(\text{MAX}_I\) is the maximum possible input value (e.g for floating point images \(\text{MAX}_I=1\)).

Convention:
  • One MSE is pooled over every element, batch and channels included, and the result is a single value: for a batch it is the PSNR of the pooled MSE, not the mean of per-image PSNRs, so compute per-image values one image at a time. Losses and metrics maps both onto scikit-image and torchmetrics.

  • max_val is \(\text{MAX}_I\), 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.

  • image and target must have the same shape, without broadcasting; the value is symmetric in them. 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; pixel values are not rescaled.

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

  • target (Tensor) – the labels image with arbitrary shape \((*)\).

  • max_val (float) – the data range of the images, \(\text{MAX}_I\).

Return type:

Tensor

Returns:

the PSNR as a scalar.

Note

Integer and bool images are converted to float32, as in ssim(), and the two images are compared in their promoted dtype. An integer image paired with a float16 or bfloat16 image therefore gives a float32 result. Pixel values are not rescaled.

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 Structural Similarity (SSIM) index map between two images.

Measures the (SSIM) index between each element in the input x and target y.

The index can be described as:

\[\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)}\]
where:
  • \(c_1=(k_1 L)^2\) and \(c_2=(k_2 L)^2\) are two variables to stabilize the division with weak denominator.

  • \(L\) is the dynamic range of the pixel-values (typically this is \(2^{\#\text{bits per pixel}}-1\)).

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. Sizes are not checked: 'same' needs H and W larger than window_size // 2.

  • 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 not reduced: one value per pixel, channel and sample, 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 input image with shape \((B, C, H, W)\).

  • img2 (Tensor) – the second input image with shape \((B, C, H, W)\).

  • window_size (int) – the size of the gaussian kernel to smooth the images.

  • max_val (float, optional) – the dynamic range of the images. Default: 1.0

  • eps (float, optional) – Small value for numerically stability when dividing. Default: 1e-12

  • padding (str, optional) – 'same' | 'valid'. Whether to only use the “valid” convolution area to compute SSIM to match the MATLAB implementation of original SSIM paper. Default: "same"

Return type:

Tensor

Returns:

The ssim index 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.

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 Structural Similarity (SSIM) index map between two images.

Measures the (SSIM) index between each element in the input x and target y.

The index can be described as:

\[\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)}\]
where:
  • \(c_1=(k_1 L)^2\) and \(c_2=(k_2 L)^2\) are two variables to stabilize the division with weak denominator.

  • \(L\) is the dynamic range of the pixel-values (typically this is \(2^{\#\text{bits per pixel}}-1\)).

Convention:
  • See the Convention block of ssim() for the window, reflected border, padding and max_val. ssim3d applies them to \((D, H, W)\) with an isotropic Gaussian window, and 'valid' crops every axis. A volume of identical slices reproduces the 2-D map up to floating-point roundoff.

  • The Gaussian window uses the computation dtype of the inputs; integer and half-precision inputs are evaluated in float32.

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

  • img2 (Tensor) – the second input image with shape \((B, C, D, H, W)\).

  • window_size (int) – the size of the gaussian kernel to smooth the images.

  • max_val (float, optional) – the dynamic range of the images. Default: 1.0

  • eps (float, optional) – Small value for numerically stability when dividing. Default: 1e-12

  • padding (str, optional) – 'same' | 'valid'. Whether to only use the “valid” convolution area to compute SSIM to match the MATLAB implementation of original SSIM paper. Default: "same"

Return type:

Tensor

Returns:

The ssim index 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, so every spatial size must be larger than window_size // 2. The Gaussian window is built in the device and dtype of the inputs. 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.

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]#

Create a module that computes the Structural Similarity (SSIM) index between two images.

Measures the (SSIM) index between each element in the input x and target y.

The index can be described as:

\[\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)}\]
where:
  • \(c_1=(k_1 L)^2\) and \(c_2=(k_2 L)^2\) are two variables to stabilize the division with weak denominator.

  • \(L\) is the dynamic range of the pixel-values (typically this is \(2^{\#\text{bits per pixel}}-1\)).

Convention:

See the Convention block of ssim().

Parameters:
  • window_size (int) – the size of the gaussian kernel to smooth the images.

  • max_val (float, optional) – the dynamic range of the images. Default: 1.0

  • eps (float, optional) – Small value for numerically stability when dividing. Default: 1e-12

  • padding (str, optional) – 'same' | 'valid'. Whether to only use the “valid” convolution area to compute SSIM to match the MATLAB implementation of original SSIM paper. Default: "same"

Shape:
  • Input: \((B, C, H, W)\).

  • Target \((B, C, H, W)\).

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

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]#

Create a module that computes the Structural Similarity (SSIM) index between two 3D images.

Measures the (SSIM) index between each element in the input x and target y.

The index can be described as:

\[\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)}\]
where:
  • \(c_1=(k_1 L)^2\) and \(c_2=(k_2 L)^2\) are two variables to stabilize the division with weak denominator.

  • \(L\) is the dynamic range of the pixel-values (typically this is \(2^{\#\text{bits per pixel}}-1\)).

Convention:

See the Convention block of ssim3d().

Parameters:
  • window_size (int) – the size of the gaussian kernel to smooth the images.

  • max_val (float, optional) – the dynamic range of the images. Default: 1.0

  • eps (float, optional) – Small value for numerically stability when dividing. Default: 1e-12

  • padding (str, optional) – 'same' | 'valid'. Whether to only use the “valid” convolution area to compute SSIM to match the MATLAB implementation of original SSIM paper. Default: "same"

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

  • Target \((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'.

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