Adjustment#

Functions#

kornia.enhance.add_weighted(src1, alpha, src2, beta, gamma)[source]#

Calculate the weighted sum of two Tensors.

_images/add_weighted.png

The function calculates the weighted sum of two Tensors as follows:

\[out = src1 * alpha + src2 * beta + gamma\]
Parameters:
  • src1 (Tensor) – torch.Tensor with an arbitrary shape, equal to shape of src2.

  • alpha (Union[float, Tensor]) – weight of the src1 elements as Union[float, torch.Tensor].

  • src2 (Tensor) – torch.Tensor with an arbitrary shape, equal to shape of src1.

  • beta (Union[float, Tensor]) – weight of the src2 elements as Union[float, torch.Tensor].

  • gamma (Union[float, Tensor]) – scalar added to each sum as Union[float, torch.Tensor].

Return type:

Tensor

Returns:

Weighted torch.Tensor with shape equal to src1 and src2 shapes.

Example

>>> input1 = torch.rand(1, 1, 5, 5)
>>> input2 = torch.rand(1, 1, 5, 5)
>>> output = add_weighted(input1, 0.5, input2, 0.5, 1.0)
>>> output.shape
torch.Size([1, 1, 5, 5])

Notes

torch.Tensor alpha/beta/gamma have to be with shape broadcastable to src1 and src2 shapes.

kornia.enhance.adjust_brightness(image, factor, clip_output=True)[source]#

Adjust the brightness of an image torch.Tensor.

_images/adjust_brightness.png

This implementation follows Szeliski’s book convention, where brightness is defined as an additive operation directly to raw pixel and shift its values according the applied factor and range of the image values. Beware that other framework might use different conventions which can be difficult to reproduce exact results.

The input image and factor is expected to be in the range of [0, 1].

Tip

By applying a large factor might prouce clipping or loss of image detail. We recommenda to apply small factors to avoid the mentioned issues. Ideally one must implement the adjustment of image intensity with other techniques suchs as kornia.enhance.adjust_gamma(). More details in the following link: https://scikit-image.org/docs/dev/auto_examples/color_exposure/plot_log_gamma.html#sphx-glr-auto-examples-color-exposure-plot-log-gamma-py

Parameters:
  • image (Tensor) – Image to be adjusted in the shape of \((*, H, W)\).

  • factor (Union[float, Tensor]) – Brightness adjust factor per element in the batch. It’s recommended to bound the factor by [0, 1]. 0 does not modify the input image while any other number modify the brightness.

  • clip_output (bool, optional) – Whether to clip output to be in [0,1]. Default: True

Return type:

Tensor

Returns:

Adjusted torch.Tensor in the shape of \((*, H, W)\).

Note

See a working example here.

Example

>>> x = torch.ones(1, 1, 2, 2)
>>> adjust_brightness(x, 1.)
tensor([[[[1., 1.],
          [1., 1.]]]])
>>> x = torch.ones(2, 5, 3, 3)
>>> y = torch.tensor([0.25, 0.50])
>>> adjust_brightness(x, y).shape
torch.Size([2, 5, 3, 3])
kornia.enhance.adjust_contrast(image, factor, clip_output=True)[source]#

Adjust the contrast of an image torch.Tensor.

_images/adjust_contrast.png

This implementation follows Szeliski’s book convention, where contrast is defined as a multiplicative operation directly to raw pixel values. Beware that other frameworks might use different conventions which can be difficult to reproduce exact results.

The input image and factor is expected to be in the range of [0, 1].

Tip

This is not the preferred way to adjust the contrast of an image. Ideally one must implement kornia.enhance.adjust_gamma(). More details in the following link: https://scikit-image.org/docs/dev/auto_examples/color_exposure/plot_log_gamma.html#sphx-glr-auto-examples-color-exposure-plot-log-gamma-py

Parameters:
  • image (Tensor) – Image to be adjusted in the shape of \((*, H, W)\).

  • factor (Union[float, Tensor]) – Contrast adjust factor per element in the batch. 0 generates a completely black image, 1 does not modify the input image while any other non-negative number modify the brightness by this factor.

  • clip_output (bool, optional) – whether to clip the output image with range of [0, 1]. Default: True

Return type:

Tensor

Returns:

Adjusted image in the shape of \((*, H, W)\).

Note

See a working example here.

Note

The non-negativity check on factor runs on CPU and CUDA (via torch._assert_async). On MPS it is skipped: the op has no MPS kernel and its CPU fallback would synchronize the device on every call, so invalid values do not raise there.

Example

>>> import torch
>>> x = torch.ones(1, 1, 2, 2)
>>> adjust_contrast(x, 0.5)
tensor([[[[0.5000, 0.5000],
          [0.5000, 0.5000]]]])
>>> x = torch.ones(2, 5, 3, 3)
>>> y = torch.tensor([0.65, 0.50])
>>> adjust_contrast(x, y).shape
torch.Size([2, 5, 3, 3])
kornia.enhance.adjust_contrast_with_mean_subtraction(image, factor)[source]#

Adjust the contrast of an image torch.Tensor by subtracting the mean over channels.

Note

this is just a convenience function to have compatibility with Pil. For exact definition of image contrast adjustment consider using kornia.enhance.adjust_gamma().

Parameters:
  • image (Tensor) – Image to be adjusted in the shape of \((*, H, W)\).

  • factor (Union[float, Tensor]) – Contrast adjust factor per element in the batch. 0 generates a completely black image, 1 does not modify the input image while any other non-negative number modify the brightness by this factor.

Return type:

Tensor

Returns:

Adjusted image in the shape of \((*, H, W)\).

Example

>>> import torch
>>> x = torch.ones(1, 1, 2, 2)
>>> adjust_contrast_with_mean_subtraction(x, 0.5)
tensor([[[[1., 1.],
          [1., 1.]]]])
>>> x = torch.ones(2, 5, 3, 3)
>>> y = torch.tensor([0.65, 0.50])
>>> adjust_contrast_with_mean_subtraction(x, y).shape
torch.Size([2, 5, 3, 3])
kornia.enhance.adjust_gamma(input, gamma, gain=1.0)[source]#

Perform gamma correction on an image.

_images/adjust_contrast.png

The input image is expected to be in the range of [0, 1].

Parameters:
  • input (Tensor) – Image to be adjusted in the shape of \((*, H, W)\).

  • gamma (Union[float, Tensor]) – Non negative real number, same as ygammay in the equation. gamma larger than 1 make the shadows darker, while gamma smaller than 1 make dark regions lighter.

  • gain (Union[float, Tensor], optional) – The constant multiplier. Default: 1.0

Return type:

Tensor

Returns:

Adjusted image in the shape of \((*, H, W)\).

Note

See a working example here.

Note

The non-negativity check on gamma/gain runs on CPU and CUDA (via torch._assert_async). On MPS it is skipped: the op has no MPS kernel and its CPU fallback would synchronize the device on every call, so invalid values do not raise there.

Example

>>> x = torch.ones(1, 1, 2, 2)
>>> adjust_gamma(x, 1.0, 2.0)
tensor([[[[1., 1.],
          [1., 1.]]]])
>>> x = torch.ones(2, 5, 3, 3)
>>> y1 = torch.ones(2) * 1.0
>>> y2 = torch.ones(2) * 2.0
>>> adjust_gamma(x, y1, y2).shape
torch.Size([2, 5, 3, 3])
kornia.enhance.adjust_hue(image, factor)[source]#

Adjust hue of an image.

_images/adjust_hue.png

The image is expected to be an RGB image in the range of [0, 1].

Parameters:
  • image (Tensor) – Image to be adjusted in the shape of \((*, 3, H, W)\).

  • factor (Union[float, Tensor]) – How much to shift the hue channel. Should be in [-PI, PI]. PI and -PI give complete reversal of hue channel in HSV space in positive and negative direction respectively. 0 means no shift. Therefore, both -PI and PI will give an image with complementary colors while 0 gives the original image.

Return type:

Tensor

Returns:

Adjusted image in the shape of \((*, 3, H, W)\).

Note

See a working example here.

Example

>>> x = torch.ones(1, 3, 2, 2)
>>> adjust_hue(x, 3.141516).shape
torch.Size([1, 3, 2, 2])
>>> x = torch.ones(2, 3, 3, 3)
>>> y = torch.ones(2) * 3.141516
>>> adjust_hue(x, y).shape
torch.Size([2, 3, 3, 3])
kornia.enhance.adjust_saturation(image, factor)[source]#

Adjust color saturation of an image.

_images/adjust_saturation.png

The image is expected to be an RGB image in the range of [0, 1].

Parameters:
  • image (Tensor) – Image/torch.Tensor to be adjusted in the shape of \((*, 3, H, W)\).

  • factor (Union[float, Tensor]) – How much to adjust the saturation. 0 will give a black and white image, 1 will give the original image while 2 will enhance the saturation by a factor of 2.

Return type:

Tensor

Returns:

Adjusted image in the shape of \((*, 3, H, W)\).

Note

See a working example here.

Example

>>> x = torch.ones(1, 3, 3, 3)
>>> adjust_saturation(x, 2.).shape
torch.Size([1, 3, 3, 3])
>>> x = torch.ones(2, 3, 3, 3)
>>> y = torch.tensor([1., 2.])
>>> adjust_saturation(x, y).shape
torch.Size([2, 3, 3, 3])
kornia.enhance.adjust_sigmoid(image, cutoff=0.5, gain=10, inv=False)[source]#

Adjust sigmoid correction on the input image torch.Tensor.

The input image is expected to be in the range of [0, 1].

Reference:
[1]: Gustav J. Braun, “Image Lightness Rescaling Using Sigmoidal Contrast Enhancement Functions”,

http://markfairchild.org/PDFs/PAP07.pdf

Parameters:
  • image (Tensor) – Image to be adjusted in the shape of \((*, H, W)\).

  • cutoff (float, optional) – The cutoff of sigmoid function. Default: 0.5

  • gain (float, optional) – The multiplier of sigmoid function. Default: 10

  • inv (bool, optional) – If is set to True the function will return the inverse sigmoid correction. Default: False

Return type:

Tensor

Returns:

Adjusted torch.Tensor in the shape of \((*, H, W)\).

Example

>>> x = torch.ones(1, 1, 2, 2)
>>> adjust_sigmoid(x, gain=0)
tensor([[[[0.5000, 0.5000],
          [0.5000, 0.5000]]]])
kornia.enhance.adjust_log(image, gain=1, inv=False, clip_output=True)[source]#

Adjust log correction on the input image torch.Tensor.

The input image is expected to be in the range of [0, 1].

Reference: [1]: http://www.ece.ucsb.edu/Faculty/Manjunath/courses/ece178W03/EnhancePart1.pdf

Parameters:
  • image (Tensor) – Image to be adjusted in the shape of \((*, H, W)\).

  • gain (float, optional) – The multiplier of logarithmic function. Default: 1

  • inv (bool, optional) – If is set to True the function will return the inverse logarithmic correction. Default: False

  • clip_output (bool, optional) – Whether to clip the output image with range of [0, 1]. Default: True

Return type:

Tensor

Returns:

Adjusted torch.Tensor in the shape of \((*, H, W)\).

Example

>>> x = torch.zeros(1, 1, 2, 2)
>>> adjust_log(x, inv=True)
tensor([[[[0., 0.],
          [0., 0.]]]])
kornia.enhance.invert(image, max_val=None)[source]#

Invert the values of an input image torch.Tensor by its maximum value.

_images/invert.png
Parameters:
  • image (Tensor) – The input torch.Tensor to invert with an arbitatry shape.

  • max_val (Optional[Tensor], optional) – The expected maximum value in the input torch.Tensor. The shape has to according to the input torch.Tensor shape, or at least has to work with broadcasting. Default: None

Return type:

Tensor

Example

>>> img = torch.rand(1, 2, 4, 4)
>>> invert(img).shape
torch.Size([1, 2, 4, 4])
>>> img = 255. * torch.rand(1, 2, 3, 4, 4)
>>> invert(img, torch.as_tensor(255.)).shape
torch.Size([1, 2, 3, 4, 4])
>>> img = torch.rand(1, 3, 4, 4)
>>> invert(img, torch.as_tensor([[[[1.]]]])).shape
torch.Size([1, 3, 4, 4])
kornia.enhance.posterize(input, bits)[source]#

Reduce the number of bits for each color channel.

_images/posterize.png

Non-differentiable function, torch.uint8 involved.

Parameters:
  • input (Tensor) – image torch.Tensor with shape \((*, C, H, W)\) to posterize.

  • bits (Union[int, Tensor]) – number of high bits. Must be in range [0, 8]. If int or one element torch.Tensor, input will be posterized by this bits. If 1-d torch.Tensor, input will be posterized element-wisely, len(bits) == input.shape[-3]. If n-d torch.Tensor, input will be posterized element-channel-wisely, bits.shape == input.shape[:len(bits.shape)]

Return type:

Tensor

Returns:

Image with reduced color channels with shape \((*, C, H, W)\).

Example

>>> x = torch.rand(1, 6, 3, 3)
>>> out = posterize(x, bits=8)
>>> torch.testing.assert_close(x, out)
>>> x = torch.rand(2, 6, 3, 3)
>>> bits = torch.tensor([4, 2])
>>> posterize(x, bits).shape
torch.Size([2, 6, 3, 3])
kornia.enhance.sharpness(input, factor)[source]#

Apply sharpness to the input torch.Tensor.

_images/sharpness.png

Implemented Sharpness function from PIL using torch ops. This implementation refers to: tensorflow/tpu

Parameters:
  • input (Tensor) – image torch.Tensor with shape \((*, C, H, W)\) to sharpen.

  • factor (Union[float, Tensor]) – factor of sharpness strength. Must be above 0. If float or one element torch.Tensor, input will be sharpened by the same factor across the whole batch. If 1-d torch.Tensor, input will be sharpened element-wisely, len(factor) == len(input).

Return type:

Tensor

Returns:

Sharpened image or images with shape \((*, C, H, W)\).

Example

>>> x = torch.rand(1, 1, 5, 5)
>>> sharpness(x, 0.5).shape
torch.Size([1, 1, 5, 5])
kornia.enhance.solarize(input, thresholds=0.5, additions=None)[source]#

For each pixel in the image less than threshold.

_images/solarize.png

We add ‘addition’ amount to it and then clip the pixel value to be between 0 and 1.0. The value of ‘addition’ is between -0.5 and 0.5.

Parameters:
  • input (Tensor) – image torch.Tensor with shapes like \((*, C, H, W)\) to solarize.

  • thresholds (Union[float, Tensor], optional) – solarize thresholds. If int or one element torch.Tensor, input will be solarized across the whole batch. If 1-d torch.Tensor, input will be solarized element-wise, len(thresholds) == len(input). Default: 0.5

  • additions (Union[float, Tensor, None], optional) – between -0.5 and 0.5. If None, no addition will be performed. If int or one element torch.Tensor, same addition will be added across the whole batch. If 1-d torch.Tensor, additions will be added element-wisely, len(additions) == len(input). Default: None

Return type:

Tensor

Returns:

The solarized images with shape \((*, C, H, W)\).

Note

The range check on additions runs on CPU and CUDA (via torch._assert_async). On MPS it is skipped: the op has no MPS kernel and its CPU fallback would synchronize the device on every call, so invalid values do not raise there.

Example

>>> x = torch.rand(1, 4, 3, 3)
>>> out = solarize(x, thresholds=0.5, additions=0.)
>>> out.shape
torch.Size([1, 4, 3, 3])
>>> x = torch.rand(2, 4, 3, 3)
>>> thresholds = torch.tensor([0.8, 0.5])
>>> additions = torch.tensor([-0.25, 0.25])
>>> solarize(x, thresholds, additions).shape
torch.Size([2, 4, 3, 3])

Modules#

class kornia.enhance.AdjustBrightness(brightness_factor)[source]#

Adjust Brightness of an image.

This implementation aligns OpenCV, not PIL. Hence, the output differs from TorchVision. The input image is expected to be in the range of [0, 1].

Parameters:

brightness_factor (Union[float, Tensor]) – Brightness adjust factor per element in the batch. 0 does not modify the input image while any other number modify the brightness.

Shape:
  • Input: Image/Input to be adjusted in the shape of \((*, N)\).

  • Output: Adjusted image in the shape of \((*, N)\).

Example

>>> x = torch.ones(1, 1, 3, 3)
>>> AdjustBrightness(1.)(x)
tensor([[[[1., 1., 1.],
          [1., 1., 1.],
          [1., 1., 1.]]]])
>>> x = torch.ones(2, 5, 3, 3)
>>> y = torch.ones(2)
>>> AdjustBrightness(y)(x).shape
torch.Size([2, 5, 3, 3])
class kornia.enhance.AdjustContrast(contrast_factor)[source]#

Adjust Contrast of an image.

This implementation aligns OpenCV, not PIL. Hence, the output differs from TorchVision. The input image is expected to be in the range of [0, 1].

Parameters:

contrast_factor (Union[float, Tensor]) – Contrast adjust factor per element in the batch. 0 generates a completely black image, 1 does not modify the input image while any other non-negative number modify the brightness by this factor.

Shape:
  • Input: Image/Input to be adjusted in the shape of \((*, N)\).

  • Output: Adjusted image in the shape of \((*, N)\).

Example

>>> x = torch.ones(1, 1, 3, 3)
>>> AdjustContrast(0.5)(x)
tensor([[[[0.5000, 0.5000, 0.5000],
          [0.5000, 0.5000, 0.5000],
          [0.5000, 0.5000, 0.5000]]]])
>>> x = torch.ones(2, 5, 3, 3)
>>> y = torch.ones(2)
>>> AdjustContrast(y)(x).shape
torch.Size([2, 5, 3, 3])
class kornia.enhance.AdjustSaturation(saturation_factor)[source]#

Adjust color saturation of an image.

The input image is expected to be an RGB image in the range of [0, 1].

Parameters:

saturation_factor (Union[float, Tensor]) – How much to adjust the saturation. 0 will give a black and white image, 1 will give the original image while 2 will enhance the saturation by a factor of 2.

Shape:
  • Input: Image/torch.Tensor to be adjusted in the shape of \((*, 3, H, W)\).

  • Output: Adjusted image in the shape of \((*, 3, H, W)\).

Example

>>> x = torch.ones(1, 3, 3, 3)
>>> AdjustSaturation(2.)(x)
tensor([[[[1., 1., 1.],
          [1., 1., 1.],
          [1., 1., 1.]],

         [[1., 1., 1.],
          [1., 1., 1.],
          [1., 1., 1.]],

         [[1., 1., 1.],
          [1., 1., 1.],
          [1., 1., 1.]]]])
>>> x = torch.ones(2, 3, 3, 3)
>>> y = torch.ones(2)
>>> out = AdjustSaturation(y)(x)
>>> torch.nn.functional.mse_loss(x, out)
tensor(0.)
class kornia.enhance.AdjustHue(hue_factor)[source]#

Adjust hue of an image.

This implementation aligns PIL. Hence, the output is close to TorchVision. The input image is expected to be in the range of [0, 1].

The input image is expected to be an RGB image in the range of [0, 1].

Parameters:

hue_factor (Union[float, Tensor]) – How much to shift the hue channel. Should be in [-PI, PI]. PI and -PI give complete reversal of hue channel in HSV space in positive and negative direction respectively. 0 means no shift. Therefore, both -PI and PI will give an image with complementary colors while 0 gives the original image.

Shape:
  • Input: Image/torch.Tensor to be adjusted in the shape of \((*, 3, H, W)\).

  • Output: Adjusted image in the shape of \((*, 3, H, W)\).

Example

>>> x = torch.ones(1, 3, 3, 3)
>>> AdjustHue(3.141516)(x)
tensor([[[[1., 1., 1.],
          [1., 1., 1.],
          [1., 1., 1.]],

         [[1., 1., 1.],
          [1., 1., 1.],
          [1., 1., 1.]],

         [[1., 1., 1.],
          [1., 1., 1.],
          [1., 1., 1.]]]])
>>> x = torch.ones(2, 3, 3, 3)
>>> y = torch.ones(2) * 3.141516
>>> AdjustHue(y)(x).shape
torch.Size([2, 3, 3, 3])
class kornia.enhance.AdjustGamma(gamma, gain=1.0)[source]#

Perform gamma correction on an image.

The input image is expected to be in the range of [0, 1].

Parameters:
  • gamma (Union[float, Tensor]) – Non negative real number, same as ygammay in the equation. gamma larger than 1 make the shadows darker, while gamma smaller than 1 make dark regions lighter.

  • gain (Union[float, Tensor], optional) – The constant multiplier. Default: 1.0

Shape:
  • Input: Image to be adjusted in the shape of \((*, N)\).

  • Output: Adjusted image in the shape of \((*, N)\).

Example

>>> x = torch.ones(1, 1, 3, 3)
>>> AdjustGamma(1.0, 2.0)(x)
tensor([[[[1., 1., 1.],
          [1., 1., 1.],
          [1., 1., 1.]]]])
>>> x = torch.ones(2, 5, 3, 3)
>>> y1 = torch.ones(2) * 1.0
>>> y2 = torch.ones(2) * 2.0
>>> AdjustGamma(y1, y2)(x).shape
torch.Size([2, 5, 3, 3])
class kornia.enhance.AdjustSigmoid(cutoff=0.5, gain=10, inv=False)[source]#

Adjust the contrast of an image torch.Tensor or performs sigmoid correction on the input image torch.Tensor.

The input image is expected to be in the range of [0, 1].

Reference:
[1]: Gustav J. Braun, “Image Lightness Rescaling Using Sigmoidal Contrast Enhancement Functions”,

http://markfairchild.org/PDFs/PAP07.pdf

Parameters:
  • image – Image to be adjusted in the shape of \((*, H, W)\).

  • cutoff (float, optional) – The cutoff of sigmoid function. Default: 0.5

  • gain (float, optional) – The multiplier of sigmoid function. Default: 10

  • inv (bool, optional) – If is set to True the function will return the negative sigmoid correction. Default: False

Example

>>> x = torch.ones(1, 1, 2, 2)
>>> AdjustSigmoid(gain=0)(x)
tensor([[[[0.5000, 0.5000],
          [0.5000, 0.5000]]]])
class kornia.enhance.AdjustLog(gain=1, inv=False, clip_output=True)[source]#

Adjust log correction on the input image torch.Tensor.

The input image is expected to be in the range of [0, 1].

Reference: [1]: http://www.ece.ucsb.edu/Faculty/Manjunath/courses/ece178W03/EnhancePart1.pdf

Parameters:
  • image – Image to be adjusted in the shape of \((*, H, W)\).

  • gain (float, optional) – The multiplier of logarithmic function. Default: 1

  • inv (bool, optional) – If is set to True the function will return the inverse logarithmic correction. Default: False

  • clip_output (bool, optional) – Whether to clip the output image with range of [0, 1]. Default: True

Example

>>> x = torch.zeros(1, 1, 2, 2)
>>> AdjustLog(inv=True)(x)
tensor([[[[0., 0.],
          [0., 0.]]]])
class kornia.enhance.AddWeighted(alpha, beta, gamma)[source]#

Calculate the weighted sum of two Tensors.

The function calculates the weighted sum of two Tensors as follows:

\[out = src1 * alpha + src2 * beta + gamma\]
Parameters:
  • alpha (Union[float, Tensor]) – weight of the src1 elements as Union[float, torch.Tensor].

  • beta (Union[float, Tensor]) – weight of the src2 elements as Union[float, torch.Tensor].

  • gamma (Union[float, Tensor]) – scalar added to each sum as Union[float, torch.Tensor].

Shape:
  • Input1: torch.Tensor with an arbitrary shape, equal to shape of Input2.

  • Input2: torch.Tensor with an arbitrary shape, equal to shape of Input1.

  • Output: Weighted torch.Tensor with shape equal to src1 and src2 shapes.

Example

>>> input1 = torch.rand(1, 1, 5, 5)
>>> input2 = torch.rand(1, 1, 5, 5)
>>> output = AddWeighted(0.5, 0.5, 1.0)(input1, input2)
>>> output.shape
torch.Size([1, 1, 5, 5])

Notes

torch.Tensor alpha/beta/gamma have to be with shape broadcastable to src1 and src2 shapes.

class kornia.enhance.Invert(max_val=None)[source]#

Invert the values of an input torch.Tensor by its maximum value.

Parameters:
  • input – The input torch.Tensor to invert with an arbitatry shape.

  • max_val (Optional[Tensor], optional) – The expected maximum value in the input torch.Tensor. The shape has to according to the input torch.Tensor shape, or at least has to work with broadcasting. Default: 1.0.

Example

>>> img = torch.rand(1, 2, 4, 4)
>>> Invert()(img).shape
torch.Size([1, 2, 4, 4])
>>> img = 255. * torch.rand(1, 2, 3, 4, 4)
>>> Invert(torch.as_tensor(255.))(img).shape
torch.Size([1, 2, 3, 4, 4])
>>> img = torch.rand(1, 3, 4, 4)
>>> Invert(torch.as_tensor([[[[1.]]]]))(img).shape
torch.Size([1, 3, 4, 4])