Edge detection#

Functions#

kornia.filters.canny(input, low_threshold=0.1, high_threshold=0.2, kernel_size=(5, 5), sigma=(1, 1), hysteresis=True, eps=1e-6)[source]#

Find edges of the input image and filters them using the Canny algorithm.

_images/canny.png
Convention:
  • A 3-channel input is converted with rgb_to_grayscale(), which reads channel 0 as red. Both outputs are \((B, 1, H, W)\), in the input’s dtype for a floating input and in float32 for an integer one, which is processed in float32 on its own scale.

  • The image is blurred with gaussian_blur2d(input, kernel_size, sigma); the Convention block on gaussian_blur2d() gives the order of both pairs, and kernel_size=1 skips the blur. The magnitude is \(\sqrt{g_x^2 + g_y^2 + \epsilon}\) of the unnormalised Sobel gradient spatial_gradient(blurred, normalized=False): an axis-aligned ramp of signed slope s gives \(\sqrt{(8 s)^2 + \epsilon}\) at an interior pixel, about 8 * abs(s). This is about eight times what sobel() returns by default, up to the eps inside the square root. On an image in \([0, 1]\) it is not bounded by 1: a unit step reaches 4 without the blur and about 2.59 with the default one. Float16 and bfloat16 inputs are computed in float32, with enclosing autocast disabled; only the final magnitude and edges are rounded to the input dtype.

  • The thresholds compare against that magnitude and are strict: a pixel is weak above low_threshold and strong above high_threshold. Filtering maps them onto OpenCV and scikit-image.

  • Non-maximum suppression compares each pixel with its two neighbours along the gradient direction, rounded to a multiple of 45 degrees. As in OpenCV’s cv2.Canny, along a horizontal (vertical) gradient a pixel must be strictly greater than its left (upper) neighbour and greater than or equal to its right (lower) one, so of two pixels of equal magnitude across a step edge the left (upper) one is kept. Along a diagonal it must be strictly greater than both. A pixel with zero gradient is never kept. The returned magnitude is taken after this step, so it is zero off the edge ridges; it is differentiable with respect to the input, and the edge map is not.

  • Hysteresis keeps a weak pixel connected to a strong one through any of its 8 neighbours, repeated until nothing changes, and returns edges of 0 and 1. Under torch.export the loop is a torch.while_loop, so the exported graph also repeats until nothing changes, for any input; the dynamo ONNX exporter writes it as an ONNX Loop from torch 2.11 and cannot export it before. Under torch.jit.trace, and so the legacy TorchScript ONNX exporter (torch.onnx.export(..., dynamo=False)), the loop is a scripted function that the trace calls, so the traced graph also repeats until nothing changes, for any input, and the exporter writes it as an ONNX Loop. A trace cannot record a loop whose condition depends on the data on its own: if TorchScript cannot compile the function, a RuntimeWarning says so and the traced graph repeats the rounds the traced image needed on every input, which cuts a longer edge chain short without an error.

  • An integer image is promoted to float32 before the grayscale conversion, so a 3-channel integer image is converted with the floating weights rather than rounded to an integer grey.

Parameters:
  • input (Tensor) – input image torch.Tensor with shape \((B,C,H,W)\), with \(C\) equal to 1, or to 3 for an RGB image, which is converted to grayscale.

  • low_threshold (float, optional) – lower threshold for the hysteresis procedure, in the units of the magnitude above. It must be positive and at most high_threshold. Default: 0.1

  • high_threshold (float, optional) – upper threshold for the hysteresis procedure, in the same units. It has no upper bound. Default: 0.2

  • kernel_size (tuple[int, int] | int, optional) – the size of the kernel for the gaussian blur. Default: (5, 5)

  • sigma (tuple[float, float] | Tensor, optional) – the standard deviation of the kernel for the gaussian blur. Default: (1, 1)

  • hysteresis (bool, optional) – if True, applies the hysteresis edge tracking. Otherwise, the edges are divided between weak (0.5) and strong (1) edges. Default: True

  • eps (float, optional) – regularization number to avoid NaN during backprop. Default: 1e-6

Return type:

tuple[Tensor, Tensor]

Returns:

  • the gradient magnitude after non-maximum suppression, shape of \((B,1,H,W)\).

  • the canny edge detection filtered by thresholds and hysteresis, shape of \((B,1,H,W)\).

Note

See a working example here.

Example

>>> input = torch.rand(5, 3, 4, 4)
>>> magnitude, edges = canny(input)  # 5x3x4x4
>>> magnitude.shape
torch.Size([5, 1, 4, 4])
>>> edges.shape
torch.Size([5, 1, 4, 4])
kornia.filters.laplacian(input, kernel_size, border_type='reflect', normalized=True)[source]#

Create an operator that returns a tensor using a Laplacian filter.

_images/laplacian.png

The operator filters each channel of the given tensor with a Laplacian kernel. It supports batched operation.

Convention:
  • The kernel is get_laplacian_kernel2d(kernel_size), correlated with each channel as by filter2d(); see the Convention blocks on get_laplacian_kernel2d() for the stencil, its sign and kernel_size, and on filter2d() for the border modes.

  • For floating inputs, normalized=True, the default, divides the kernel by its absolute sum \(2 (kH \cdot kW - 1)\), 16 for size 3. Unlike normalized in spatial_gradient(), this does not give derivative units: size 3 returns \(3 \nabla^2 / 16\). Filtering compares both scales with scipy and OpenCV.

  • An integer or bool input is filtered in float32 and the output is float32, as in filter2d().

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

  • kernel_size (tuple[int, int] | int) – the size of the kernel. It should be odd and positive, and at least 3 along one axis.

  • border_type (str, optional) – the padding mode to be applied before convolving. The expected modes are: 'constant', 'reflect', 'replicate' or 'circular', case-insensitive. Default: "reflect"

  • normalized (bool, optional) – if True, L1 norm of the kernel is set to 1. Default: True

Note

Ordinary eager CPU execution uses convolution for extreme input ranges. Captured graphs and function transforms retain their selected arithmetic, so with normalized=False an input near its dtype’s maximum can overflow to NaN under torch.compile or torch.vmap where eager CPU execution returns a finite response.

Return type:

Tensor

Returns:

the Laplacian response with shape \((B, C, H, W)\).

Raises:

BaseError – if a size is even or not positive, if kernel_size is a sequence of other than 2 sizes, or if it is 1 or (1, 1): a \(1 \times 1\) kernel is all zeros, and its normalized form is 0 / 0.

Note

See a working example here.

Examples

>>> input = torch.rand(2, 4, 5, 5)
>>> output = laplacian(input, 3)
>>> output.shape
torch.Size([2, 4, 5, 5])
kornia.filters.sobel(input, normalized=True, eps=1e-6)[source]#

Compute the Sobel operator and returns the magnitude per channel.

_images/sobel.png
Convention:
  • The output is \(\sqrt{g_x^2 + g_y^2 + \epsilon}\) per channel, where \((g_x, g_y)\) is spatial_gradient(input, 'sobel', normalized=normalized); see the Convention block on spatial_gradient(). Away from the replicated border, an axis-aligned ramp of slope s gives \(\sqrt{s^2 + \epsilon}\), about \(|s|\), with the default normalized=True; normalized=False gives about \(8 |s|\), the scale canny() thresholds.

  • eps sits inside the square root, so a flat region returns \(\sqrt{\epsilon}\), 1e-3 by default, not 0.

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

  • normalized (bool, optional) – if True, L1 norm of the kernel is set to 1. Default: True

  • eps (float, optional) – regularization number to avoid NaN during backprop. Default: 1e-6

Return type:

Tensor

Returns:

the sobel edge gradient magnitudes map with shape \((B,C,H,W)\).

Note

See a working example here.

Example

>>> input = torch.rand(1, 3, 4, 4)
>>> output = sobel(input)  # 1x3x4x4
>>> output.shape
torch.Size([1, 3, 4, 4])
kornia.filters.spatial_gradient(input, mode='sobel', order=1, normalized=True)[source]#

Compute the first or second order image derivative in x and y using a Sobel or diff operator.

_images/spatial_gradient.png
Convention:
  • The derivatives are the kernels of get_spatial_gradient_kernel2d(), stacked on a new axis 2 in that function’s order and with its sign; see its Convention block.

  • For order=1 with the default normalized=True, an axis-aligned linear ramp with slope s has response s in the corresponding channel away from the replicated border. With normalized=False, the Sobel response is 8 s. Filtering maps both scales onto OpenCV, scipy and scikit-image.

  • The border is always replicated, so for order=1 with normalized=True, a linear ramp’s derivative is half its slope on the first and last pixel along that axis. There is no border_type, unlike filter2d() and laplacian(), whose default is 'reflect'.

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

  • mode (str, optional) – derivatives modality, can be: sobel or diff, case-insensitive. Default: "sobel"

  • order (int, optional) – the order of the derivatives. Default: 1

  • normalized (bool, optional) – if True, scale the kernels so that every output channel estimates the derivative itself away from the replicated border: exact on linear surfaces for order=1 and on quadratic surfaces for order=2. If False, return the raw kernel responses. Default: True

Return type:

Tensor

Returns:

the derivatives of the input feature map, with shape \((B, C, 2, H, W)\) holding \((dx, dy)\) for order=1 and \((B, C, 3, H, W)\) holding \((dxx, dxy, dyy)\) for order=2.

Note

See a working example here.

Examples

>>> input = torch.rand(1, 3, 4, 4)
>>> output = spatial_gradient(input)  # 1x3x2x4x4
>>> output.shape
torch.Size([1, 3, 2, 4, 4])
kornia.filters.spatial_gradient3d(input, mode='diff', order=1)[source]#

Compute the first and second order volume derivative in x, y and d using a diff operator.

Convention:
  • The derivatives are the kernels of get_spatial_gradient_kernel3d(), stacked on a new axis 2; see its Convention block for their order and units. There is no normalized argument: a floating input gives derivative units.

  • The border is always replicated, as in spatial_gradient().

  • An integer or bool input is differentiated in float32 and the output is float32, on the input’s scale, as filter3d() does (#5155).

Parameters:
  • input (Tensor) – input features torch.Tensor with shape \((B, C, D, H, W)\).

  • mode (str, optional) – derivatives modality, case-insensitive; only 'diff' is implemented. Default: "diff"

  • order (int, optional) – the order of the derivatives. Default: 1

Return type:

Tensor

Returns:

the spatial gradients of the input feature map with shape \((B, C, 3, D, H, W)\) holding \((dx, dy, dz)\) for order=1 or \((B, C, 6, D, H, W)\) holding \((dxx, dyy, dzz, dxy, dyz, dxz)\) for order=2.

Examples

>>> input = torch.rand(1, 4, 2, 4, 4)
>>> output = spatial_gradient3d(input)
>>> output.shape
torch.Size([1, 4, 3, 2, 4, 4])

Modules#

class kornia.filters.Laplacian(kernel_size, border_type='reflect', normalized=True)[source]#

Create an operator that returns a tensor using a Laplacian filter.

The operator filters each channel of the given tensor with a Laplacian kernel. It supports batched operation.

Convention:

See the Convention block on laplacian().

Parameters:
  • kernel_size (tuple[int, int] | int) – the size of the kernel. It should be odd and positive, and at least 3 along one axis.

  • border_type (str, optional) – the padding mode to be applied before convolving. The expected modes are: 'constant', 'reflect', 'replicate' or 'circular', case-insensitive. Default: "reflect"

  • normalized (bool, optional) – if True, L1 norm of the kernel is set to 1. Default: True

Raises:

BaseError – if a size is even or not positive, if kernel_size is a sequence of other than 2 sizes, or if it is 1 or (1, 1). The size is checked when the module is built, as laplacian() checks it when called.

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

  • Output: \((B, C, H, W)\)

Examples

>>> input = torch.rand(2, 4, 5, 5)
>>> laplace = Laplacian(5)
>>> output = laplace(input)
>>> output.shape
torch.Size([2, 4, 5, 5])
class kornia.filters.Sobel(normalized=True, eps=1e-6)[source]#

Compute the Sobel operator and returns the magnitude per channel.

Convention:

See the Convention block on sobel().

Parameters:
  • normalized (bool, optional) – if True, L1 norm of the kernel is set to 1. Default: True

  • eps (float, optional) – regularization number to avoid NaN during backprop. Default: 1e-6

Returns:

the sobel edge gradient magnitudes map.

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

  • Output: \((B, C, H, W)\)

Examples

>>> input = torch.rand(1, 3, 4, 4)
>>> output = Sobel()(input)  # 1x3x4x4
class kornia.filters.Canny(low_threshold=0.1, high_threshold=0.2, kernel_size=(5, 5), sigma=(1, 1), hysteresis=True, eps=1e-6)[source]#

nn.Module that finds edges of the input image and filters them using the Canny algorithm.

Convention:

See the Convention block on canny(). The thresholds are validated at construction.

Parameters:
  • low_threshold (float, optional) – lower threshold for the hysteresis procedure, in the units of the unnormalised Sobel magnitude. It must be positive and at most high_threshold. Default: 0.1

  • high_threshold (float, optional) – upper threshold for the hysteresis procedure, in the same units. It has no upper bound. Default: 0.2

  • kernel_size (tuple[int, int] | int, optional) – the size of the kernel for the gaussian blur. Default: (5, 5)

  • sigma (tuple[float, float] | Tensor, optional) – the standard deviation of the kernel for the gaussian blur. Default: (1, 1)

  • hysteresis (bool, optional) – if True, applies the hysteresis edge tracking. Otherwise, the edges are divided between weak (0.5) and strong (1) edges. Default: True

  • eps (float, optional) – regularization number to avoid NaN during backprop. Default: 1e-6

Returns:

  • the gradient magnitude after non-maximum suppression, shape of \((B,1,H,W)\).

  • the canny edge detection filtered by thresholds and hysteresis, shape of \((B,1,H,W)\).

Example

>>> input = torch.rand(5, 3, 4, 4)
>>> magnitude, edges = Canny()(input)  # 5x3x4x4
>>> magnitude.shape
torch.Size([5, 1, 4, 4])
>>> edges.shape
torch.Size([5, 1, 4, 4])
class kornia.filters.SpatialGradient(mode='sobel', order=1, normalized=True)[source]#

Compute the first or second order image derivative in x and y using a Sobel or diff operator.

Convention:

See the Convention block on spatial_gradient().

Parameters:
  • mode (str, optional) – derivatives modality, can be: sobel or diff, case-insensitive. Default: "sobel"

  • order (int, optional) – the order of the derivatives. Default: 1

  • normalized (bool, optional) – whether the output is normalized. Default: True

Returns:

the derivatives of the input feature map.

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

  • Output: \((B, C, 2, H, W)\) for order=1 and \((B, C, 3, H, W)\) for order=2

Examples

>>> input = torch.rand(1, 3, 4, 4)
>>> output = SpatialGradient()(input)  # 1x3x2x4x4
class kornia.filters.SpatialGradient3d(mode='diff', order=1)[source]#

Compute the first and second order volume derivative in x, y and d using a diff operator.

Convention:

See the Convention block on spatial_gradient3d().

Parameters:
  • mode (str, optional) – derivatives modality, case-insensitive; only 'diff' is implemented. Default: "diff"

  • order (int, optional) – the order of the derivatives. Default: 1

Returns:

the spatial gradients of the input feature map.

Shape:
  • Input: \((B, C, D, H, W)\). D, H, W are spatial dimensions, gradient is calculated w.r.t to them.

  • Output: \((B, C, 3, D, H, W)\) or \((B, C, 6, D, H, W)\)

Examples

>>> input = torch.rand(1, 4, 2, 4, 4)
>>> output = SpatialGradient3d()(input)
>>> output.shape
torch.Size([1, 4, 3, 2, 4, 4])