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_valis \(\text{MAX}_I\), the data range of the images (1.0for[0, 1],255.0for[0, 255]), not the maximum of the tensor; pixel values are not rescaled.imageandtargetmust have the same shape, without broadcasting; the value is symmetric in them. Identical inputs give an MSE of 0 andinf, 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:
- Return type:
- 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)
- 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'dropswindow_size // 2pixels on every side and equals the'same'map cropped. Sizes are not checked:'same'needsHandWlarger thanwindow_size // 2.max_valis the data range \(L\), a Pythonfloat: \(c_1 = (0.01 L)^2\) and \(c_2 = (0.03 L)^2\). Pixel values are not rescaled, so images in[0, 255]needmax_val=255.0.epsis 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 defaulteps=1e-12, black images score about0.99998889atmax_val=1.0; the bias grows to0.1atmax_val=0.1. Useeps=0.0to omit this denominator term when matching reference implementations.The map is not reduced: one value per pixel, channel and sample, symmetric in
img1andimg2, 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.paddingaccepts'same'and'valid'case-insensitively; unsupported values raiseBaseError.
- 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.0eps (
float, optional) – Small value for numerically stability when dividing. Default:1e-12padding (
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:
- Returns:
The ssim index map with shape \((B, C, H, W)\), or \((B, C, H - 2p, W - 2p)\) with
p = window_size // 2underpadding='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.functransforms, 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,paddingandmax_val.ssim3dapplies 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.0eps (
float, optional) – Small value for numerically stability when dividing. Default:1e-12padding (
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:
- 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 // 2underpadding='valid'.
Note
The volume is reflected at its faces for
padding='same', askornia.metrics.ssim()does for images, so every spatial size must be larger thanwindow_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 followstorch.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 than1e-2. Settorch.backends.cudnn.allow_tf32 = Falsewhen 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.0eps (
float, optional) – Small value for numerically stability when dividing. Default:1e-12padding (
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 // 2underpadding='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.0eps (
float, optional) – Small value for numerically stability when dividing. Default:1e-12padding (
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 // 2underpadding='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