imgtools.enhance

This module including

  • Basic intensity mapping, such as linear, gamma correction, log transformation, etc.

  • Edge enhancement, e.g., sharpening, unsharp masking.

  • Contrast enhancement

  • High dynamic range, e.g., Durand2002 [1] and Reinhard2002 [2].

  • Low-light enhancement, including MSRCR [3] and MSRCP [3].

  • Style transfer by Reinhard2002 [4].

References



Documents

imgtools.enhance.adjust_gamma(img: Tensor, gamma: int | float | Tensor, scale: int | float | Tensor | None = None) Tensor

Intensity enhencement by gamma correction:

result = scale * (img ** gamma)

Parameters:
imgtorch.Tensor

Image with shape (*, C, H, W).

gammaint | float | torch.Tensor

The exponent. The tensor must have shape (1 or C,) or (B, 1 or C)

scaleint | float | torch.Tensor | None, default=None

Linear scale coefficients. The tensor must have shape (1 or C,) or (B, 1 or C)

Returns:
torch.Tensor

Enhanced image. Shape is broadcasting according to the shape of the arguments.

imgtools.enhance.adjust_inverse(img: Tensor, maxi: int | float | Tensor = 1.0) Tensor

Invert the intensity of the image:

result = maxi - img
Parameters:
imgtorch.Tensor

Image with shape (*, C, H, W).

maxiint | float | torch.Tensor | None, default=1.0

The maximum of the range of the image. The tensor must have shape (1 or C,) or (B, 1 or C)

Returns:
torch.Tensor

Enhanced image. Shape is broadcasting according to the shape of the arguments.

imgtools.enhance.adjust_linear(img: Tensor, slope: int | float | Tensor, center: int | float | Tensor = 0.5) Tensor

Intensity linear enhancement with a specified center point:

result = (img - center) * slope + center

Parameters:
imgtorch.Tensor

Image with shape (*, C, H, W).

slopeint | float | torch.Tensor

Slope of the linear function. The tensor must have shape (1 or C,) or (B, 1 or C).

centerint | float | torch.Tensor, default=0.5

The center of the image. The tensor must have shape (1 or C,) or (B, 1 or C).

Returns:
torch.Tensor

Enhanced image. Shape is broadcasting according to the shape of the arguments.

imgtools.enhance.adjust_log(img: Tensor, scale: int | float | Tensor | None = 0.6931471805599453) Tensor

Intensity enhencement by log transformation:

result = scale * log(base, 1 + img)

Parameters:
imgtorch.Tensor

Image with shape (*, C, H, W).

scaleint | float | torch.Tensor | None, default=log1p(1.0)

Linear scale coefficients. The tensor must have shape (1 or C,) or (B, 1 or C)

Returns:
torch.Tensor

Enhanced image. Shape is broadcasting according to the shape of the arguments.

imgtools.enhance.adjust_sigmoid(img: Tensor, shift: int | float | Tensor = 0.5, gain: int | float | Tensor = 10.0) Tensor

Intensity enhencement by sigmoid function:

result = sigmoid(gain * (img - cutoff))

Parameters:
imgtorch.Tensor

Image with shape (*, C, H, W).

shiftint | float | torch.Tensor | None, default=0.5

Shift of the image intensity. The tensor must have shape (1 or C,) or (B, 1 or C)

gainint | float | torch.Tensor | None, default=10.0

Multipler of the derivative of the sigmoid function The tensor must have shape (1 or C,) or (B, 1 or C)

Returns:
torch.Tensor

Enhanced image. Shape is broadcasting according to the shape of the arguments.

imgtools.enhance.high_frequency_emphasis_filter(lowpass: Tensor, k: float = 1.0, offset: float = 1.0) Tensor

Create a high frequency emphasis filter (HFEF) from a given lowpass filter. hfef = offset + k * (1 - lowpass).

Parameters:
lowpasstorch.Tensor

An lowpass filter.

kfloat, default=1.0

The scale of the high frequency.

offsetfloat, default=1.0

The offset of the filter.

Returns:
torch.Tensor

The high frequency emphasis filter.

Notes

When offset equals 1, the filter is the same as the unsharp masking. When this filter is applied to the Fourier transform of log(image), the HFEF can be regarded as homomorphic filter

Examples

>>> img_f = torch.fft.rfft2(img)
>>> lowpass = get_gaussian_lowpass(img_f, 2)
>>> unsharp_masking = high_frequency_emphasis_filter(lowpass, 1.2)
>>> enhanced_f = img_f * unsharp_masking
>>> enhanced = torch.fft.irfft2(enhanced_f)
>
>>> hfef = high_frequency_emphasis_filter(lowpass, 1.2, 1.5)
>>> enhanced_f = img_f * hfef
>>> enhanced = torch.fft.irfft2(enhanced_f)
>
>>> log_img = torch.log1p(img)
>>> img_f = torch.fft.rfft2(log_img)
>>> lowpass = get_gaussian_lowpass(img_f, 2)
>>> homomorphic = high_frequency_emphasis_filter(lowpass, 2.6, 3.0)
>>> enhanced_f = img_f * homomorphic
>>> log_enhanced = torch.fft.irfft2(enhanced_f)
>>> enhanced = torch.expm1(log_enhanced)
imgtools.enhance.unsharp_mask(img: Tensor, amount: float = 1, ksize: int | tuple[int, int] = 3, sigma: float | tuple[float, float] = 0.0) Tensor

Applies unsharp masking to an image.

Parameters:
imgtorch.Tensor

An image with shape (*, C, H, W).

amountfloat, default=1

The enhanced amount.

ksizeint | tuple[int, int], default=3

The Gaussian kernel size. If ksize is non-positive, the value will be computed from sigma: ksize = odd(6 * sigma + 1), where odd() returns the closest odd integer.

sigmafloat, default=0

The width of gaussian function. If sigma is non-positive, the value will be computed from ksize: sigma = 0.3 * ((ksize - 1) * 0.5 - 1) + 0.8

Returns:
torch.Tensor

Enhanced image with shape (*, C, H, W).

imgtools.enhance.hist_equalize(img: Tensor, bins: int = 256) Tensor

Apply histogram equalization to the image.

Parameters:
imgtorch.Tensor

An image in the range of [0, 1] with shape (*, *, H, W).

binsint, default=256

The number of groups in data range.

Returns:
torch.Tensor

Enhanced image in the range of [0, 1]. Shape img.shape.

imgtools.enhance.match_historgram(img: Tensor, tar_hist: Tensor, bins: int = 256)

Applies histogram matching to the image with a given histogram.

Parameters:
imgtorch.Tensor

Source image in the range of [0, 1] with shape (*, C or *, H, W).

tar_histtorch.Tensor

Target histogram with shape (*, 1 or C or *, N).

binsint, default=256

The number of groups in data range.

Returns:
torch.Tensor

Transferred image in RGB space.

imgtools.enhance.match_mean_std(src: Tensor, tar: Tensor) Tensor

Match the mean and standard deviation.

Parameters:
srctorch.Tensor

Source image with shape (*, *, H, W).

tartorch.Tensor

Target image with shape (*, *, H, W).

Returns:
torch.Tensor

Enhanced image. Shape=`max(src.shape, tar.dtype)`.

imgtools.enhance.bilateral_hdr(img: Tensor, sigma_c: float = 0.15, sigma_s: float | None = 1.0, contrast: float = 1.5, downsample: float = 1, edge_stopping: str = 'gaussian', tone: str = 'soft')

Applies high dynamic range to an image by using Durand’s work [1]. ( modified fast bilateral filter).

Parameters:
imgtorch.Tensor

An RGB image in the range of [0, 1] with shape (*, C, H, W).

sigma_cfloat

Sigma in the color intensity. A larger value means that the dissimilar intensity will cause more effect.

sigma_sfloat | None, default=1.0

Sigma in the space/coordinate. A larger value means that the farther points will cause more effect. If None, sigma_s is set to be min(H, W) * 0.02.

contrast: float, default=1.5

The contrast factor. When tone == ‘std’, the contrast will be clipped to [1, inf).

downsamplefloat, default=1

Downsample rate. A smaller value means small size in iteration.

edge_stopping{‘huber’, ‘lorentz’, ‘turkey’, ‘gaussian’}, default=’gaussian’

Edge-stopping function. A function for preventing diffusion between dissimilar intensity. The value ‘huber’ is only recommended with tone == ‘std’.

tone{‘soft’, ‘lighter’, ‘linear’, ‘std’}, default=’soft’

Tone mapping strategy. The ‘std’ is closed to the standard strategy. See notes section for details.

Returns:
torch.Tensor

High dynamic image with shape (*, C, H, W).

Notes

The argument tone mainly affects the interpolation of weights when computing fast bilateral filter. The options of tone other than ‘std’ give larger weights, thus, is brighter. And, theese options are faster since the computation of tone mapping is simpler.

References

[1] F. Durand and J. Dorsey, “Fast bilateral filtering for the display of

high-dynamic-range images,” SIGGRAPH ‘02’, pp. 257-266, Jul. 2002 doi: 10.1145/566570.566574.

Examples

>>> from imgtools.enhance import bilateral_hdr
>>>
>>> hdr = bilateral_hdr(rgb, 0.25, 0.1)
>>> hdr2 = bilateral_hdr(rgb, 0.25, None, tone='std')
>>> hdr3 = bilateral_hdr(dark_rgb, 0.25, None, contrast=0.5)
imgtools.enhance.reinhard2002(img: Tensor, exposure: float = 1.7, l_white: float | None = None, num_scale: int = 4, alpha: float = 0.35355, ratio: float = 1.6, phi: float = 8.0, thresh: float = 0.05, tone: str = 'local')

Applies high dynamic range to an image by using the modified version of E. Reinhard’s work [1].

Parameters:
imgtorch.Tensor

An RGB or grayscale image in the range of [0, 1] with shape (*, C, H, W).

exposurefloat, default=1.7

An mutiplier for scaling the luminance. Affects significantly the luminance of output. The relation between exposure and mid gray (a in equation (2) of [1]) is exposure = a / geometric_mean(lum)

l_whitefloat | None, default=None

Maximum luminance. If None, the value will be set to the mean of luminance.

num_scaleint, default=4

The number of scales.

alphafloat, default=0.35355

Basic blurring strength.

ratiofloat, default=1.6

The ratio between two blurring strength.

phifloat, default=8.0

Sharpening parameter

threshfloat, default=0.05

Threshold value for scale selection.

tone{‘local’, ‘global’}, default=’local’

Tone mapping strategy.

Returns:
torch.Tensor

High dynamic image in the range of [0, 1] with shape (*, C, H, W).

Notes

When tone == ‘global’, only the arguments exposure and l_white. When tone == ‘local’, all arguments affect the result.

References

[1] Erik Reinhard, Michael Stark, Peter Shirley, and James Ferwerda. 2002.

Photographic tone reproduction for digital images. ACM Trans. Graph. 21, 3 (July 2002), 267-276. https://doi.org/10.1145/566654.566575

Examples

>>> from imgtools.enhance import reinhard2002
>>>
>>> hdr = reinhard2002(rgb)
>>> hdr2 = reinhard2002(dark_rgb, 20)
>>> hdr3 = reinhard2002(rgb, tone='global')
imgtools.enhance.light_compensation_htchen(rgb: Tensor, scaler: int | float = 1.0, power: int | float = 0.1, space: str = 'LAB', overflow: str = 'norm') Tensor

Light compensation by H. T. Chen’s method [1]. This method can be found in [2] and [3].

Enhance the luminance channel by

1lum_brighter = scaler * lum * (1 + log(2 - lum))
2lum_dark = (blurred_sat + 1) / (2 * (1 + blurred_lum) ** power)
3new_lum = lum_brighter * lum_dark
Parameters:
rgbtorch.Tensor

An RGB image in range of [0, 1] with shape (*, C, H, W).

scalerint | float, default=1.0

The strength of the enhancement.

powerint | float, default=0.1

The strength of overexpose suppression.

space{‘LAB’, ‘LUV’, ‘YUV’, ‘HSV’, ‘HSL’, ‘HSI’}, default=’LAB’

The color space to get luminance and saturation.

overflow{‘clip’, ‘norm’, ‘both’}, default=’norm’

Handle the result luminance: clip, normalize (to [0, 1]), or clip then normalize. Other value means ignoring.

Returns:
torch.Tensor

Balanced RGB image in range of [0, 1] with shape (*, C, H, W).

Raises:
ValueError

When argument sapce is not valid.

References

[1] H. T. Chen, “An Algorithm for Light Compensation,” Master Thesis,

Department of Computer Science and Information Engineering, National Taiwan University, 2008.

[2] C. F. Chang, C. S. Fuh, “Light Compensation,” Proceedings of IPPR

Conference on Computer Vision, Graphics, and Image Processing, Shitou, Taiwan, B3-9, p. 87, 2009.

[3] PDF from C. S. Fuh’s personal webpsite

https://www.csie.ntu.edu.tw/~fuh/personal/LightCompensation.pdf

Examples

>>> from imgtools.balance import light_compensation_htchen
>>>
>>> rgb = torch.rand((3, 512, 512))
>>> balanced = light_compensation_htchen(rgb)
imgtools.enhance.msrcp(rgb: Tensor, scales: list[float] = [100, 500, 1000], weights: list[float] | None = None, dark_percent: float = 0.04, light_percent: float = 0.04)

Low-light enhance by using multi-scale retinex with color preservation [1].

Parameters:
rgbtorch.Tensor

An RGB image with shape (*, C, H, W).

scaleslist[float], default=[100, 500, 1000]

The strength of the blurriness. The sigma of the Gaussian filter is 1 / scale.

weightslist[float] | None, default=None

Weights of the scales. If None, the weight is 1 / len(scales) for each scale.

dark_percentfloat, default=0.02

The percentage of clipped darkest intensities.

light_percentfloat, default=0.02

The percentage of clipped brightest intensities.

Returns:
torch.Tensor

Low-light enhanced image with shape (*, C, H, W).

Notes

The blurring is performed on frequency domain. And the relation of the sigma for a Gaussian filter between spatial domain and frequency domain is sigma_s * sigma_f = 1 / 2 * pi.

References

[1] Ana Belén Petro, Catalina Sbert, and Jean-Michel Morel,

Multiscale Retinex, Image Processing On Line, (2014), pp. 71-88. https://doi.org/10.5201/ipol.2014.107

Examples

>>> from imgtools import enhance
>>> res = enhance.msrcp(img_rgb)
imgtools.enhance.msrcr(img: Tensor, scales: list[float] = [100, 500, 1000], weights: list[float] | None = None, dark_percent: float = 0.02, light_percent: float = 0.02)

Low-light enhance by using multi-scale retinex with color restoration [1].

Parameters:
imgtorch.Tensor

An image with shape (*, C, H, W).

scaleslist[float], default=[100, 500, 1000]

The strength of the blurriness. The sigma of the Gaussian filter is 1 / scale.

weightslist[float] | None, default=None

Weights of the scales. If None, the weight is 1 / len(scales) for each scale.

dark_percentfloat, default=0.02

The percentage of clipped darkest intensities.

light_percentfloat, default=0.02

The percentage of clipped brightest intensities.

Returns:
torch.Tensor

Low-light enhanced image with shape (*, C, H, W).

Notes

The blurring is performed on frequency domain. And the relation of the sigma for a Gaussian filter between spatial domain and frequency domain is sigma_s * sigma_f = 1 / 2 * pi.

References

[1] Ana Belén Petro, Catalina Sbert, and Jean-Michel Morel,

Multiscale Retinex, Image Processing On Line, (2014), pp. 71-88. https://doi.org/10.5201/ipol.2014.107

Examples

>>> from imgtools import enhance
>>> res = enhance.msrcr(img)
imgtools.enhance.retinex(img: Tensor, scales: list[float] = [100, 500, 1000], weights: list[float] | None = None, normalize: bool = True) Tensor

Low-light enhance by using multi-scale retinex.

Parameters:
imgtorch.Tensor

An image with shape (*, C, H, W).

scaleslist[float], default=[100, 500, 1000]

The strength of the blurriness. The sigma of the Gaussian filter is 1 / scale.

weightslist[float] | None, default=None

Weights of the scales. If None, the weight is 1 / len(scales) for each scale.

normalizebool, default=True

Normalize the result to [0, 1].

Returns:
torch.Tensor

Low-light enhanced image with shape (*, C, H, W).

Notes

The blurring is performed on frequency domain. And the relation of the sigma for a Gaussian filter between spatial domain and frequency domain is sigma_s * sigma_f = 1 / 2 * pi.

Examples

>>> from imgtools import enhance
>>> res = enhance.msr(img)
imgtools.enhance.transfer_reinhard(src: Tensor, tar: Tensor, rgb_spec: str = 'srgb', white: str = 'D65', obs: str | int = 10, adap_method: str = 'bradford')

Color transfer by E. Reinhard’s work [1]. Match the mean and standard deviation in the color space L-α-β (Si)

Parameters:
srctorch.Tensor

Source image in RGB space with shape (*, C, H, W).

tartorch.Tensor

Target image in RGB space with shape (*, C, H, W).

rgb_specRGBSpec, default=’srgb’

The name of RGB specification. The argument is case-insensitive.

whiteStandardIlluminants, default=’D65’

White point. The input is case-insensitive.

obs{2, ‘2’, 10, ‘10’}, default=10

The degree of oberver.

methodCATMethod, default=’bradford’

Chromatic adaptation method.

Returns:
torch.Tensor

Transferred image in RGB space. The shape will broadcast by src and tar.

References

[1] E. Reinhard, M. Adhikhmin, B. Gooch and P. Shirley, “Color

transfer between images,” in IEEE Computer Graphics and Applications, vol. 21, no. 5, pp. 34-41, July-Aug. 2001, doi: 10.1109/38.946629