Edge detection#
sobel() returns the gradient magnitude of an image, spatial_gradient() its signed x and y derivatives (or
second derivatives), laplacian() a second-derivative response and canny() a thin binary edge map.
spatial_gradient3d() differentiates volumes.
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 the edges of an image with the Canny detector.
magnitude, edges = canny(input)blurs a grayscale or RGB image, thins the Sobel gradient magnitude by non-maximum suppression, and thresholds it with hysteresis into an edge map.
- 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) – image with shape(B, C, H, W), withCequal 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) – Gaussian blur window(kH, kW)in pixels, or one integer for both. Default:(5, 5)sigma (
tuple[float,float] |Tensor, optional) – Gaussian blur standard deviation(sigma_y, sigma_x)in pixels, as ingaussian_blur2d(). Default:(1, 1)hysteresis (
bool, optional) – ifTrue, keep a weak edge only when it connects to a strong one. IfFalse, the edge map holds 0, 0.5 for weak edges and 1 for strong edges. Default:Trueeps (
float, optional) – added under the square root of the magnitude so that the gradient of a flat pixel is finite. Default:1e-6
- Return type:
- Returns:
the gradient magnitude after non-maximum suppression, with shape
(B, 1, H, W).the edge map, with shape
(B, 1, H, W), holding 0 and 1 withhysteresis=True.
Note
See a working example here.
See also
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]#
Filter an image with a Laplacian kernel, a second-derivative operator.
out = laplacian(input, kernel_size)filters each channel of a(B, C, H, W)image with the Laplacian kernel of that size and returns the response in the same shape.
- 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) – image with shape(B, C, H, W).kernel_size (
tuple[int,int] |int) – kernel(kH, kW)in pixels, or one integer for both; each odd and positive, and at least 3 along one axis.border_type (
str, optional) – padding mode,'constant','reflect','replicate'or'circular', case-insensitive. Default:"reflect"normalized (
bool, optional) – ifTrue, the L1 norm of the kernel is 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.
See also
Laplacian: the module form.get_laplacian_kernel2d(): the kernel this filter applies.spatial_gradient(): withorder=2, the separate derivativesdxx,dxyanddyy.
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 gradient magnitude of each channel.
out = sobel(input)returns the gradient magnitude of each channel of a(B, C, H, W)image as an edge-strength map of the same shape.
- 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 gradient magnitudes, with shape
(B, C, H, W).
Note
See a working example here.
See also
Sobel: the module form.spatial_gradient(): the signed x and y derivatives, on an added axis.canny(): thins the edges by non-maximum suppression and thresholds them.gradient(): a morphological edge strength, the dilation minus the erosion.
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 image derivatives in x and y with Sobel or difference kernels.
out = spatial_gradient(input)returns the x and y derivatives of each channel of a(B, C, H, W)image, stacked on a new axis 2.
- Convention:
The derivatives are the kernels of
get_spatial_gradient_kernel2d(), 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) – image with shape(B, C, H, W).mode (
str, optional) – kernel set,'sobel'or'diff', case-insensitive. Default:"sobel"order (
int, optional) –1for the first derivatives,2for the second. 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)\) fororder=1and(B, C, 3, H, W)holding \((dxx, dxy, dyy)\) fororder=2.
Note
See a working example here.
See also
SpatialGradient: the module form.sobel(): the magnitude of the first derivatives, with no added axis.spatial_gradient3d(): the same for volumes, with'diff'kernels only.laplacian(): one second-derivative response per channel, on its own scale.get_spatial_gradient_kernel2d(): the kernels it applies.
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 or second derivatives of a volume along x, y and depth with difference kernels.
out = spatial_gradient3d(input)returns the derivatives of each channel of a(B, C, D, H, W)volume, stacked on a new axis 2.- Convention:
The derivatives are the kernels of
get_spatial_gradient_kernel3d(), in that function’s order; see its Convention block for their 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 derivatives, with shape
(B, C, 3, D, H, W)holding \((dx, dy, dz)\) fororder=1or(B, C, 6, D, H, W)holding \((dxx, dyy, dzz, dxy, dyz, dxz)\) fororder=2.
See also
SpatialGradient3d: the module form.spatial_gradient(): the same for images, with'sobel'kernels and anormalizedargument.get_spatial_gradient_kernel3d(): the kernels it applies.
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]#
Filter an image with a stored Laplacian kernel size (module form).
lap = Laplacian(kernel_size)stores its arguments and checks the size, andout = lap(input)islaplacian()on a(B, C, H, W)image.- Convention:
See the Convention block on
laplacian().
- Parameters:
kernel_size (
tuple[int,int] |int) – kernel(kH, kW)in pixels, or one integer for both, as inlaplacian().border_type (
str, optional) – padding mode, as inlaplacian(). Default:"reflect"normalized (
bool, optional) – ifTrue, the L1 norm of the kernel is 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)
See also
laplacian(): the one-call form.SpatialGradient: the separate second derivatives, withorder=2.
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 gradient magnitude of each channel (module form).
edges = Sobel(normalized, eps)stores its arguments, andout = edges(input)issobel()on a(B, C, H, W)image.- Convention:
See the Convention block on
sobel().
- Parameters:
- Shape:
Input:
(B, C, H, W)Output:
(B, C, H, W)
See also
sobel(): the one-call form.SpatialGradient: the signed x and y derivatives, on an added axis.Canny: thins the edges by non-maximum suppression and thresholds them.
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]#
Find the edges of an image with stored Canny settings (module form).
detector = Canny(low_threshold, high_threshold, ...)stores its arguments and checks the thresholds, andmagnitude, edges = detector(input)iscanny()on a(B, C, H, W)image.- Convention:
See the Convention block on
canny().
- Parameters:
low_threshold (
float, optional) – lower hysteresis threshold, in the units of the unnormalised Sobel magnitude. It must be positive and at mosthigh_threshold. Default:0.1high_threshold (
float, optional) – upper hysteresis threshold, in the same units. It has no upper bound. Default:0.2kernel_size (
tuple[int,int] |int, optional) – Gaussian blur window(kH, kW)in pixels, or one integer for both. Default:(5, 5)sigma (
tuple[float,float] |Tensor, optional) – Gaussian blur standard deviation(sigma_y, sigma_x)in pixels. Default:(1, 1)hysteresis (
bool, optional) – whether to keep a weak edge only when it connects to a strong one, as incanny(). Default:Trueeps (
float, optional) – added under the square root of the magnitude, as incanny(). Default:1e-6
- Shape:
Input:
(B, C, H, W), withCequal to 1, or to 3 for an RGB image.Output: the magnitude and the edge map, each
(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 image derivatives with a stored kernel set and order (module form).
grad = SpatialGradient(mode, order, normalized)stores its arguments, andout = grad(input)isspatial_gradient()on a(B, C, H, W)image.- Convention:
See the Convention block on
spatial_gradient().
- Parameters:
mode (
str, optional) – kernel set,'sobel'or'diff', case-insensitive. Default:"sobel"order (
int, optional) –1for the first derivatives,2for the second. Default:1normalized (
bool, optional) – whether to scale the kernels to derivative units, as inspatial_gradient(). Default:True
- Shape:
Input:
(B, C, H, W)Output:
(B, C, 2, H, W)fororder=1and(B, C, 3, H, W)fororder=2
See also
spatial_gradient(): the one-call form.SpatialGradient3d: the same for volumes.Sobel: the magnitude of the first derivatives.
Examples
>>> input = torch.rand(1, 3, 4, 4) >>> output = SpatialGradient()(input) # 1x3x2x4x4
- class kornia.filters.SpatialGradient3d(mode='diff', order=1)[source]#
Compute the first or second derivatives of a volume with a stored kernel set and order (module form).
grad = SpatialGradient3d(mode, order)stores its arguments, andout = grad(input)isspatial_gradient3d()on a(B, C, D, H, W)volume.- Convention:
See the Convention block on
spatial_gradient3d().
- Parameters:
- Shape:
Input:
(B, C, D, H, W)Output:
(B, C, 3, D, H, W)fororder=1and(B, C, 6, D, H, W)fororder=2
See also
spatial_gradient3d(): the one-call form.SpatialGradient: the same for images.
Examples
>>> input = torch.rand(1, 4, 2, 4, 4) >>> output = SpatialGradient3d()(input) >>> output.shape torch.Size([1, 4, 3, 2, 4, 4])