Equalization and histograms#
Equalization#
equalize(), equalize_clahe() and equalize3d() expect a floating-point image in [0, 1]
and raise TypeCheckError (a TypeError) for an integer or boolean image,
as the [0, 1] adjustment functions do; convert 8-bit data with image.float() / 255 first.
- kornia.enhance.equalize(input)[source]#
Equalize the histogram of each channel of an image, as PIL’s
ImageOps.equalizedoes.out = equalize(input)equalizes each channel of each image in a(*, C, H, W)batch in \([0, 1]\) on its own.
- Convention:
Each pixel is counted in the lookup-table entry it reads, its 8-bit level
(x * 255).long()in the input dtype, so a float32 or float64 image givesPIL.ImageOps.equalizeof those levels. In float32 and float64 the 255 is raised by four float32 epsilons, relative (2**-21), sok / 255reads levelkeven when its division was rounded a unit low. Dividing by 255 on CUDA leaves 24 of the 256 float64 levels a unit low. A continuous value moves up a level only within that margin below a level boundary.The lookup step is the pixel count minus the count at the highest occupied level, integer-divided by 255. A channel whose step is 0, which includes every channel of up to 255 pixels, is returned unchanged.
A float32 image counts in float32, which is exact while a channel holds at most
2**24pixels (a 4096 by 4096 image).Empty leading dimensions are supported; channels and spatial dimensions must be non-empty.
- Parameters:
input (
Tensor) – image with shape(*, C, H, W).- Return type:
- Returns:
Equalized image with shape
(*, C, H, W).
Note
An integer or boolean image raises
TypeCheckError(aTypeError); convert 8-bit data withimage.float() / 255first. Values the 256-bin lookup cannot index, those whose level before truncation lies outside(-1, 256), raise aRuntimeErrornaming the range, during the call for a CPU image, even when checks are disabled, since the check keeps the lookup in bounds. On CUDA, and on MPS from torch2.13, the check istorch._assert_asyncand raises by the next synchronization; on an older MPS release the condition is read on the host instead, one device sync per call, and is skipped there undertorch.compile.See also
equalize3d(): the volume twin, with one histogram per channel volume.equalize_clahe(): equalizes each tile of a grid with a clipped histogram.RandomEqualize: applies it at random per image.
Example
>>> x = torch.rand(1, 2, 3, 3) >>> equalize(x).shape torch.Size([1, 2, 3, 3])
- kornia.enhance.equalize_clahe(input, clip_limit=40.0, grid_size=(8, 8), slow_and_differentiable=False)[source]#
Equalize an image tile by tile with a clipped histogram (CLAHE).
out = equalize_clahe(input, clip_limit, grid_size)equalizes each channel of an image in \([0, 1]\) in every tile of agrid_sizegrid and blends the tiles’ lookup tables where they meet. Clipping the histogram atclip_limitlimits the local contrast gain.
- Convention:
The tiles are
ceil(H / grid_size[0])byceil(W / grid_size[1])pixels, and an axis the grid does not divide is reflect-padded at its end. OpenCV uses the same tiles when the grid divides both axes or neither; when it divides one, OpenCV also pads that axis by one pixel per tile and Kornia does not.Lookup tables are blended with weights anchored at each tile’s centre,
(p + 0.5) / tile_size - 0.5for pixelp, which keeps flip symmetry on unpadded grids. This is half a pixel from the phase of OpenCV and scikit-image, a blending-weight difference of at most0.5 / tile_sizeper axis, so the output differs fromcv2.createCLAHEeven for the same lookup tables. The output is not rounded to 8-bit levels.The default path rounds the lookup tables to nearest like OpenCV;
slow_and_differentiable=Truedoes not.
- Parameters:
input (
Tensor) – image with values in \([0, 1]\) and shape(*, C, H, W).clip_limit (
float, optional) – caps each bin atmax(clip_limit * tile_pixels // 256, 1)counts and spreads the excess over all bins.0.0disables clipping. Afloat; anintraisesTypeError. Default:40.0grid_size (
Tuple[int,int], optional) – number of tiles(GH, GW)along H and W, a tuple ofint. Each image axis must be larger than its grid size; theValueErrorotherwise names the smallest image the grid admits. Default:(8, 8)slow_and_differentiable (
bool, optional) – count with a soft histogram, so gradients reachinput; the default path has none. It is slower and, without the lookup-table rounding, its values differ from the default path’s. Default:False
- Return type:
- Returns:
Equalized image with the shape of
input.
Note
An integer or boolean image raises
TypeCheckError(aTypeError), and values whose level before truncation lies outside(-1, 256)raise aRuntimeErrornaming the range, as forequalize(). That function also describes the 8-bit level the lookup reads and when the range error surfaces on CUDA and MPS.See also
equalize(): equalizes the whole channel with one histogram.RandomClahe: applies it with random parameters per image.
Examples
>>> img = torch.rand(1, 10, 20) >>> res = equalize_clahe(img) >>> res.shape torch.Size([1, 10, 20])
>>> img = torch.rand(2, 3, 10, 20) >>> res = equalize_clahe(img) >>> res.shape torch.Size([2, 3, 10, 20])
- kornia.enhance.equalize3d(input)[source]#
Equalize the histogram of each channel of a 3D volume.
out = equalize3d(input)equalizes each channel of each volume in a(*, C, D, H, W)batch in \([0, 1]\) from one histogram over its whole(D, H, W)volume.- Convention:
Each voxel is read at its 8-bit level as
equalize()reads a pixel.The lookup step and the unchanged-channel rule are those of
equalize(), counted over the voxels of a channel volume.Empty leading dimensions are supported; channels and spatial dimensions must be non-empty.
- Parameters:
input (
Tensor) – volume with shape(*, C, D, H, W).- Return type:
- Returns:
Equalized volume with the shape of
input.
Note
An integer or boolean volume raises
TypeCheckError, and a value whose level before truncation lies outside(-1, 256)raises aRuntimeError, as forequalize(), with the same device behavior.See also
equalize(): the image twin, with one histogram per channel plane.
Histograms#
The three histograms are kernel estimates and differ in their input:
histogram(): rows of samples(B, D), giving one normalized histogram per row.histogram2d(): two rows of samples, giving their normalized joint histogram.image_histogram2d(): an image, giving one histogram of the pixel values per channel.
- kornia.enhance.histogram(x, bins, bandwidth, epsilon=1e-10)[source]#
Estimate the normalized histogram of each sample row with Gaussian kernels.
hist = histogram(x, bins, bandwidth)spreads every value of a row ofxover the bin centersbinswith a Gaussian kernel and normalizes each row to sum to 1, withepsilonadded to the divisor.- Convention:
Rows are independent samples, and
binsis the one center grid they share.A
bandwidththat is not finite and positive raisesRuntimeError; on CUDA, and on MPS from torch 2.13, it raises by the next synchronization.For float16 and bfloat16 samples and bins, the kernels are evaluated in float32 and the result is cast back to that dtype.
- Parameters:
x (
Tensor) – samples with shape(B, D).bins (
Tensor) – bin centers with shape(N_bins,), in the units ofx.bandwidth (
Tensor) – 0-d tensor, the standard deviation of the Gaussian kernel in the units ofx. A Python float or a(1,)tensor raises.epsilon (
float, optional) – value added to the normalization sum. Default:1e-10
- Return type:
- Returns:
Histogram with shape
(B, N_bins). When all kernel weights underflow to zero, it is zero for a positiveepsilonand NaN forepsilon=0.
See also
histogram2d(): the joint histogram of two sample rows.image_histogram2d(): counts the pixels of each image channel, with a choice of kernel.
Examples
>>> x = torch.rand(1, 10) >>> bins = torch.linspace(0, 1, 128) >>> hist = histogram(x, bins, bandwidth=torch.tensor(0.01)) >>> hist.shape torch.Size([1, 128])
- kornia.enhance.histogram2d(x1, x2, bins, bandwidth, epsilon=1e-10)[source]#
Estimate the normalized joint histogram of two sample rows with Gaussian kernels.
hist = histogram2d(x1, x2, bins, bandwidth)pairsx1[b, n]withx2[b, n]:hist[b, i, j]is the kernel weight ofx1in biniandx2in binj, normalized per batch element to sum to 1.- Convention:
x1andx2must have the same shape.When
x1andbinspromote to float16 or bfloat16, the kernels, joint counts and normalization are evaluated in float32 and the result is cast back to that dtype.
- Parameters:
x1 (
Tensor) – first samples with shape(B, D).x2 (
Tensor) – second samples with shape(B, D).bins (
Tensor) – bin centers with shape(N_bins,), in the units of the samples.bandwidth (
Tensor) – 0-d tensor, the standard deviation of the Gaussian kernel in the units of the samples.epsilon (
float, optional) – value added to the normalization sum. Default:1e-10
- Return type:
- Returns:
Joint histogram with shape
(B, N_bins, N_bins); the first bin axis belongs tox1. All-zero kernel weights give zeros for a positiveepsilonand NaN forepsilon=0.
See also
histogram(): the histogram of one sample row.image_histogram2d(): one histogram per image channel, not a joint one.
Examples
>>> x1 = torch.rand(2, 32) >>> x2 = torch.rand(2, 32) >>> bins = torch.linspace(0, 1, 128) >>> hist = histogram2d(x1, x2, bins, bandwidth=torch.tensor(0.01)) >>> hist.shape torch.Size([2, 128, 128])
- kornia.enhance.image_histogram2d(image, min=0.0, max=255.0, n_bins=256, bandwidth=None, centers=None, return_pdf=False, kernel='triangular', eps=1e-10)[source]#
Estimate the intensity histogram of each channel of an image.
hist, pdf = image_histogram2d(image, min, max, n_bins)weights every pixel overn_binsbin centers with a kernel and returns the summed weights per channel ashist, and their normalization aspdfifreturn_pdf=True. Despite its name it is a one-dimensional histogram per channel; for the joint histogram of two signals usehistogram2d().- Convention:
The spatial axes are the final two. An image
(H, W),(C, H, W)or(B, C, H, W)giveshistwith the same leading axes followed by the bins; another rank raises.A pixel outside the range still adds the kernel’s weight to the centers within reach; it is not clipped into an end bin.
Float16 and bfloat16 images are accumulated and returned in float32, or in the dtype of wider explicit
centers: ordinary bin counts exceed float16’s range (65504) and bfloat16’s precision.
- Parameters:
image (
Tensor) – image with shape(H, W),(C, H, W)or(B, C, H, W).min (
float, optional) – lower end of the range, afloat. It sets the automatic centers and bandwidth. Default:0.0max (
float, optional) – upper end of the range, afloat. It sets the automatic centers and bandwidth. The default255.0puts a \([0, 1]\) image in two bins; pass1.0for that range. It must exceedminwhile the centers are automatic. Default:255.0n_bins (
int, optional) – number of automatic bins. Default:256bandwidth (
Optional[float], optional) – kernel width, a positive finitefloat; it does not move the automatic centers. The default, also-1, is(max - min) / n_bins. Default:Nonecenters (
Optional[Tensor], optional) – bin centers with shape(K,). The default, also an empty tensor, is then_binsequal-width bin centers over[min, max],min + (i + 0.5) * (max - min) / n_bins. With explicit centers, also passbandwidth: the default bandwidth still comes frommin,maxandn_bins(#6662). Default:Nonereturn_pdf (
bool, optional) – whether to also return the normalized histogram. Default:Falsekernel (
str, optional) – weight of a pixel at distancedfrom a center, withu = d / bandwidth:'triangular'(\(1 - u\) for \(u \leq 1\)),'gaussian'(\(e^{-u^2 / 2}\)),'uniform'(1 for \(u \leq 1\)) or'epanechnikov'(\(1 - u^2\) for \(u \leq 1\)). Gradients reachimageexcept with'uniform'. Default:"triangular"eps (
float, optional) – value added to the normalization sum. Default:1e-10
- Return type:
- Returns:
Tuple
(hist, pdf).histhas shape(K,),(C, K)or(B, C, K), where the bin axisKhasn_binsentries, or one per center.pdfhas the same shape and divides the histogram by its bin sum pluseps. Its sum approaches 1 when the bin sum dominateseps; it is zeros when no pixels contribute orreturn_pdfisFalse.
See also
histogram(): the Gaussian histogram of sample rows, normalized.histogram2d(): the joint histogram of two sample rows.
Example
>>> image = torch.rand(2, 3, 8, 8) >>> hist, pdf = image_histogram2d(image, 0.0, 1.0, n_bins=16, return_pdf=True) >>> hist.shape torch.Size([2, 3, 16])