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.
- 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 ongaussian_blur2d()gives the order of both pairs, andkernel_size=1skips the blur. The magnitude is \(\sqrt{g_x^2 + g_y^2 + \epsilon}\) of the unnormalised Sobel gradientspatial_gradient(blurred, normalized=False): an axis-aligned ramp of signed slopesgives \(\sqrt{(8 s)^2 + \epsilon}\) at an interior pixel, about8 * abs(s). This is about eight times whatsobel()returns by default, up to theepsinside 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_thresholdand strong abovehigh_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.exportthe loop is atorch.while_loop, so the exported graph also repeats until nothing changes, for any input; the dynamo ONNX exporter writes it as an ONNXLoopfrom torch 2.11 and cannot export it before. Undertorch.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 ONNXLoop. A trace cannot record a loop whose condition depends on the data on its own: if TorchScript cannot compile the function, aRuntimeWarningsays 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 mosthigh_threshold. Default:0.1high_threshold (
float, optional) – upper threshold for the hysteresis procedure, in the same units. It has no upper bound. Default:0.2kernel_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:Trueeps (
float, optional) – regularization number to avoid NaN during backprop. Default:1e-6
- Return type:
- 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.
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 byfilter2d(); see the Convention blocks onget_laplacian_kernel2d()for the stencil, its sign andkernel_size, and onfilter2d()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. Unlikenormalizedinspatial_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=Falsean input near its dtype’s maximum can overflow to NaN undertorch.compileortorch.vmapwhere eager CPU execution returns a finite response.- Return type:
- Returns:
the Laplacian response with shape \((B, C, H, W)\).
- Raises:
BaseError – if a size is even or not positive, if
kernel_sizeis a sequence of other than 2 sizes, or if it is1or(1, 1): a \(1 \times 1\) kernel is all zeros, and its normalized form is0 / 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.
- 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 onspatial_gradient(). Away from the replicated border, an axis-aligned ramp of slopesgives \(\sqrt{s^2 + \epsilon}\), about \(|s|\), with the defaultnormalized=True;normalized=Falsegives about \(8 |s|\), the scalecanny()thresholds.epssits inside the square root, so a flat region returns \(\sqrt{\epsilon}\),1e-3by default, not 0.
- Parameters:
- Return type:
- 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.
- 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=1with the defaultnormalized=True, an axis-aligned linear ramp with slopeshas responsesin the corresponding channel away from the replicated border. Withnormalized=False, the Sobel response is8 s. Filtering maps both scales onto OpenCV, scipy and scikit-image.The border is always replicated, so for
order=1withnormalized=True, a linear ramp’s derivative is half its slope on the first and last pixel along that axis. There is noborder_type, unlikefilter2d()andlaplacian(), 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:1normalized (
bool, optional) – ifTrue, scale the kernels so that every output channel estimates the derivative itself away from the replicated border: exact on linear surfaces fororder=1and on quadratic surfaces fororder=2. IfFalse, return the raw kernel responses. Default:True
- Return type:
- Returns:
the derivatives of the input feature map, with shape \((B, C, 2, H, W)\) holding \((dx, dy)\) for
order=1and \((B, C, 3, H, W)\) holding \((dxx, dxy, dyy)\) fororder=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 nonormalizedargument: 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:
- Return type:
- Returns:
the spatial gradients of the input feature map with shape \((B, C, 3, D, H, W)\) holding \((dx, dy, dz)\) for
order=1or \((B, C, 6, D, H, W)\) holding \((dxx, dyy, dzz, dxy, dyz, dxz)\) fororder=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_sizeis a sequence of other than 2 sizes, or if it is1or(1, 1). The size is checked when the module is built, aslaplacian()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:
- 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 mosthigh_threshold. Default:0.1high_threshold (
float, optional) – upper threshold for the hysteresis procedure, in the same units. It has no upper bound. Default:0.2kernel_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:Trueeps (
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:
- Returns:
the derivatives of the input feature map.
- Shape:
Input: \((B, C, H, W)\)
Output: \((B, C, 2, H, W)\) for
order=1and \((B, C, 3, H, W)\) fororder=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:
- 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])