Thresholding#
in_range() keeps the pixels whose channels lie between bounds you give. otsu_threshold() picks one
threshold per image plane from its histogram and keeps the pixels above it.
- kornia.filters.in_range(input, lower, upper, return_mask=False)[source]#
Keep the pixels whose channels all lie in an inclusive range.
out = in_range(input, lower, upper)multipliesinputby a mask that is 1 where every channel lies between itslowerandupperbounds, and 0 elsewhere. Withreturn_mask=Trueit returns the mask instead.
For an input with
Cchannels the mask at pixel \(I\) is:\[\text{mask}(I) = \bigwedge_{c=0}^{C-1} \left( \text{lower}_c(I) \leq \text{input}_c(I) \leq \text{upper}_c(I) \right)\]- Convention:
A NaN channel fails its pixel. The mask has the input’s dtype, 1 for a pass. For floating input, bounds are cast to the input dtype before comparison, so only an interval still reversed after that conversion selects nothing.
return_mask=Falsereturnsinput * mask: the channels of a failing pixel become 0, except a NaN or infinite one, which becomes NaN.For integer inputs, fractional lower bounds round up and fractional upper bounds round down. Bounds outside the input dtype’s range do not wrap or overflow; a range containing no representable input value produces an empty mask.
- Parameters:
input (
Tensor) – image with shape(*, C, H, W).lower (
Union[tuple[Any,...],Tensor]) – inclusive lower bounds, a tuple with one entry per channel or a tensor; see the note.upper (
Union[tuple[Any,...],Tensor]) – inclusive upper bounds, in the same form aslower.return_mask (
bool, optional) – ifTrue, return the mask; otherwise return the masked image. Default:False
- Return type:
- Returns:
the mask with shape
(*, 1, H, W)ifreturn_maskisTrue, otherwise the masked image with the shape ofinput.- Raises:
TypeError – If
lowerorupperis neither a tuple nor a torch.Tensor, if one is a tuple and the other a torch.Tensor, or ifreturn_maskis not a bool.ValueError – If a tuple bound does not have one element per channel, or a torch.Tensor bound does not fit the input as described in the note.
Note
The forms of
lowerandupper:A tuple has one entry per channel and applies to every sample.
A tensor of shape
(B, C, 1, 1)gives each sample its own bounds.A 1-D tensor is read per channel, never per column: its shape is
(C,), or one element for the same bound in every channel, and it applies to every sample. Any other 1-D length, such as(W,)whenWis neitherCnor 1, raises. WhenW == C, a(W,)bound is the(C,)bound, not a per-column one.Any other tensor with at most four dimensions is aligned with the input
(B, C, H, W)from the last dimension, and every dimension must be 1 or the input’s. For example(1, C, 1, 1)and(C, 1, 1)apply the same per-channel bound to all samples,(B, C, H, W),(C, H, W)and(H, W)give a different bound at each pixel, and a 0-d tensor applies one bound everywhere.Each tensor bound is checked on its own, so a mis-shaped one raises whatever the other bound is. The input is read as
(B, C, H, W): a 3-D input is(1, C, H, W), a 2-D input is(1, 1, H, W)and gives a 2-D output, and for more than four dimensions the leading dimensions are flattened intoB.
See also
InRange: the module form.otsu_threshold(): picks the threshold from the image histogram instead of taking bounds.
Examples
>>> rng = torch.manual_seed(1) >>> input = torch.rand(1, 3, 3, 3) >>> lower = (0.2, 0.3, 0.4) >>> upper = (0.8, 0.9, 1.0) >>> mask = in_range(input, lower, upper, return_mask=True) >>> mask tensor([[[[1., 1., 0.], [0., 0., 0.], [0., 1., 1.]]]]) >>> mask.shape torch.Size([1, 1, 3, 3])
Apply different bounds (
lowerandupper) for each batch:>>> rng = torch.manual_seed(1) >>> input_tensor = torch.rand((2, 3, 3, 3)) >>> input_shape = input_tensor.shape >>> lower = torch.tensor([[0.2, 0.2, 0.2], [0.2, 0.2, 0.2]]).reshape(input_shape[0], input_shape[1], 1, 1) >>> upper = torch.tensor([[0.6, 0.6, 0.6], [0.8, 0.8, 0.8]]).reshape(input_shape[0], input_shape[1], 1, 1) >>> mask = in_range(input_tensor, lower, upper, return_mask=True) >>> mask tensor([[[[0., 0., 1.], [0., 0., 0.], [1., 0., 0.]]], [[[0., 0., 0.], [1., 0., 0.], [0., 0., 1.]]]])
- class kornia.filters.InRange(lower, upper, return_mask=False)[source]#
Keep the pixels whose channels all lie in stored inclusive bounds (module form).
keep = InRange(lower, upper, return_mask)stores its arguments, andout = keep(input)isin_range()on an image with shape(*, C, H, W).- Convention:
See the Convention block on
in_range().
- Parameters:
- Shape:
Input:
(*, C, H, W)Output:
(*, 1, H, W)withreturn_mask=True, otherwise the shape of the input.
See also
in_range(): the one-call form, with the forms the bounds can take.OtsuThreshold: picks the threshold from the image histogram.
Examples
>>> rng = torch.manual_seed(1) >>> input = torch.rand(1, 3, 3, 3) >>> lower = (0.2, 0.3, 0.4) >>> upper = (0.8, 0.9, 1.0) >>> mask = InRange(lower, upper, return_mask=True)(input) >>> mask tensor([[[[1., 1., 0.], [0., 0., 0.], [0., 1., 1.]]]])
- kornia.filters.otsu_threshold(x, nbins=256, slow_and_differentiable=False, return_mask=False)[source]#
Threshold an image at the level Otsu’s method picks, one threshold per image plane.
thresholded, threshold = otsu_threshold(x)finds the threshold that best splits the histogram of each image plane ofxinto two classes and keeps the pixels above it. Withreturn_mask=Truethe first output is the boolean maskx > thresholdinstead.- Convention:
One threshold is returned per plane over the last two axes: a
(B, C, H, W)input givesB * Cthresholds, flattened, and a tensor of at most two dimensions is one plane.Each plane is histogrammed on its own range,
nbinsbins between its minimum and its maximum, not over a fixed \([0, 1]\) or \([0, 255]\). The threshold is the upper edge of the selected histogram bin, in input units and in the input’s dtype. For an integer input it is the largest integer below that value, sox > thresholdkeeps every pixel on or above it. For floating input, rounding is corrected when necessary to keep the threshold at or above the largest background pixel and below the smallest foreground pixel, sox > thresholdmatches the histogram split. On MPS, a zero foreground boundary in float32 or bfloat16 uses the smallest normal negative value because comparisons flush subnormal values to zero.Histogram and bin-edge arithmetic uses float64 only for float64 input, and float32 for every other input dtype, including integers and half precision. Large or narrowly spaced integer values can therefore lose distinctions and select a different split; when that precision is required, pass float64 input whose values are representable there, on a device that supports float64 (not MPS).
Empty bins do not introduce candidate splits, so the lowest split across a run of empty bins wins on every device. A constant plane uses its constant value as the threshold.
The foreground is
x > threshold, strictly. The first output isx * (x > threshold), not a binary image, and its gradient is that mask.The threshold of the default path has no gradient. With
slow_and_differentiable=Trueit has a straight-through gradient with respect tox; see the note. Both paths supporttorch.exportand full-graphtorch.compile.
- Parameters:
x (
Tensor) – image or batch of images with at most five dimensions, such as(B, C, H, W).nbins (
int, optional) – number of histogram bins. Default:256slow_and_differentiable (
bool, optional) – ifTrue, build the histogram from a Gaussian kernel density estimate and give the threshold a gradient with respect tox; see the note. Default:Falsereturn_mask (
bool, optional) – ifTrue, the first output is the mask, with each pixel compared against the threshold of its own image and channel. Default:False
- Return type:
- Returns:
the first output, with the shape of
x, and the thresholds. The thresholded tensor cannot tell a kept pixel of value 0 from a dropped one; use the mask for that.- Raises:
ValueError – If the input tensor has more than five dimensions.
BaseError – If the input dtype is not supported.
Note
You can find more information about the Otsu algorithm here: https://en.wikipedia.org/wiki/Otsu’s_method
Note
With
slow_and_differentiable=True, the threshold is the upper edge of the bin selected by the best split of the smoothed histogram, as on the default path, and is a hard split. Its first-order gradient is a straight-through surrogate, the gradient of a soft-argmax over the between-class variance of a wider estimate. It does not match finite differences of the hard threshold, and its higher-order derivatives are not those of a soft threshold.See also
OtsuThreshold: the module form, withoutreturn_mask.in_range(): thresholds with bounds you give instead of a histogram.threshold(): thresholds at a level you give, with OpenCV’s modes.
Example
>>> import torch >>> from kornia.filters.otsu_thresholding import otsu_threshold >>> x = torch.tensor([[10, 20, 30], [40, 50, 60], [70, 80, 90]]) >>> x tensor([[10, 20, 30], [40, 50, 60], [70, 80, 90]]) >>> otsu_threshold(x) (tensor([[ 0, 0, 0], [ 0, 50, 60], [70, 80, 90]]), tensor([40]))
- class kornia.filters.OtsuThreshold[source]#
Threshold an image at the level Otsu’s method picks (module form).
otsu = OtsuThreshold()stores no settings, andthresholded, threshold = otsu(x, nbins, slow_and_differentiable)isotsu_threshold()withoutreturn_mask.- Convention:
See the Convention block on
otsu_threshold().
See also
otsu_threshold(): the one-call form.InRange: thresholds with bounds you give instead of a histogram.