Skip to content

Image Enhancement

1. Introduction

This module provides a set of algorithms for improving the visual and radiometric quality of satellite images. The purpose of these tools is to increase sharpness, correct contrast, improve brightness, and prepare images for visual analysis or as input to machine learning models.

All classes in this module inherit from BaseTool and HistogramExportMixin (for saving the output histogram).

Existing Classes :

Class NameImage TypeApplication
OriginalCalculatorSingle‑bandExtracts the raw image as float (control baseline)
OriginalRGBCalculatorRGBExtracts the raw RGB composite (natural colour)
FloatCalculatorSingle‑bandConverts the image to float format ([0,1])
EqualizeCalculatorSingle‑bandHistogram equalisation
EqualizeRGBCalculatorRGBHistogram equalisation for each RGB channel
AdaptiveCalculatorSingle‑bandAdaptive histogram equalisation (CLAHE)
AdaptiveRGBCalculatorRGBCLAHE on each RGB channel
GammaCalculatorSingle‑bandGamma correction
GammaRGBCalculatorRGBGamma correction on each RGB channel
LogAdjustCalculatorSingle‑bandLogarithmic adjustment
SigmoidAdjustCalculatorSingle‑bandSigmoid contrast adjustment

2. Detailed Documentation of Classes

2.1. OriginalCalculator and OriginalRGBCalculator – Raw Image Extraction

Purpose
Provide the input image without any changes as a baseline for comparison with other image enhancement methods.

ClassBandsOutput
OriginalCalculatornir_path2D float array
OriginalRGBCalculatorred_path, green_path, blue_path3‑band float array

Full Explanation of the Process
These classes do not apply any enhancement transformation. They merely convert the raw pixel values to floating‑point numbers in the range [0,1][0,1] using skimage.img_as_float. The mapping for an integer image with bit depth bb is :

Ifloat(x,y)=Iint(x,y)2b1I_{\text{float}}(x, y) = \frac{I_{\text{int}}(x, y)}{2^b - 1}

For the RGB version, the normalised Red, Green, and Blue bands are stacked along the third axis to create an (H, W, 3) array. No further calculations are performed.

Example :

python
calc = OriginalCalculator(nir_path="NIR.tif").execute("./output/")

2.2. FloatCalculator – Convert to Float

Purpose
Convert the input image (e.g., uint16) to the range [0,1][0,1] of type float for subsequent processing.

Full Explanation of the Formula
Identical to the mapping used in OriginalCalculator :

Ifloat=IImaxI_{\text{float}} = \frac{I}{I_{\text{max}}}

where Imax=2b1I_{\text{max}} = 2^{b} - 1. This is performed by skimage.img_as_float. The operation is linear and preserves the shape of the histogram.

Parameters : nir_path
Output : float array


2.3. EqualizeCalculator and EqualizeRGBCalculator – Histogram Equalisation

Scientific objective
Improve overall image contrast by uniformly distributing the pixel intensity values. This method is particularly useful for dark or low‑contrast images.

Full Explanation of the Formula

Histogram equalisation transforms the image so that the output histogram is approximately flat (uniform). The theory is based on the cumulative distribution function (CDF) of the pixel values.

Let p(rk)p(r_k​) be the normalised histogram (probability) of intensity level rkr_k​ (with k=0,1,,L1,L=256k=0,1,…,L−1, L=256 in the code). The cumulative probability is :

C(rk)=i=0kp(ri)C(r_k) = \sum_{i=0}^k p(r_i)

The equalised intensity sks_k​ is obtained by scaling the CDF to the full range [0,1][0,1] :

sk=C(rk)=i=0kp(ri)s_k = C(r_k) = \sum_{i=0}^k p(r_i)

In the discrete implementation (256 bins), each pixel's value is replaced by the normalised CDF of its bin. Because the input is already floating in [0,1][0,1], exposure.equalize_hist effectively computes :

Ieq(x,y)=1Nj=1rank(I(x,y))count(j)I_{\text{eq}}(x, y) = \frac{1}{N} \sum_{j=1}^{\text{rank}(I(x,y))} \text{count}(j)

where rank is the index of the pixel value among all sorted values, and NN is the total number of pixels.

The RGB version applies this transform to each of the Red, Green, and Blue channels independently. This can enhance contrast but may alter the colour balance.

ClassParametersNote
EqualizeCalculatornir_pathOn single‑band image
EqualizeRGBCalculatorred_path, green_path, blue_pathEach channel is equalised separately

Example :

python
calc = EqualizeCalculator(nir_path="NIR.tif").execute("./", title="Histogram Equalized")

2.4. AdaptiveCalculator and AdaptiveRGBCalculator – Adaptive Equalisation (CLAHE)

Scientific objective
Apply Contrast Limited Adaptive Histogram Equalisation (CLAHE), which improves contrast locally and prevents noise amplification. It is suitable for images with large variations in brightness.

Full Explanation of the Formula

CLAHE partitions the image into small tiles (by default 8×8) and computes the histogram equalisation mapping for each tile independently. To avoid amplifying noise, the contrast enhancement is limited by clipping the histogram at a specified clip limit.

  • For a tile of M×MM×M pixels and Nbins=256N_{\text{bins}} = 256, the average number of pixels per bin is nˉ=M2Nbins\bar{n} = \frac{M^2}{N_{\text{bins}}}​.

  • The clip limit C is defined as a multiple of nˉ\bar{n} :

    actual clip height=Cnˉ\text{actual clip height} = C \cdot \bar{n}

    In the code, the user passes clip_limit which corresponds to this factor CC (a typical value is 0.01 to 0.1). Any histogram bin exceeding this height is clipped, and the excess is redistributed evenly among all bins.

  • The equalisation mapping is then computed from the clipped histogram for that tile.

  • To avoid block artefacts, the mapping for each pixel is bilinearly interpolated from the mappings of the four nearest tiles.

Mathematically, for each tile tt, let ht(k)h_t(k) be the clipped histogram. Then the mapping function is:

Tt(rk)=1Nti=0kht(i)T_t(r_k) = \frac{1}{N_t} \sum_{i=0}^k h_t(i)

where NtN_t​ is the total number of pixels in the tile after clipping and redistribution. For a pixel at location (x,y)(x,y), the final value is :

ICLAHE(x,y)=interpolate(Tt1,Tt2,Tt3,Tt4)I_{\text{CLAHE}}(x, y) = \text{interpolate}(T_{t_1}, T_{t_2}, T_{t_3}, T_{t_4})

where t1..4t_{1..4}​ are the four neighbouring tiles.

The result is an image with enhanced local contrast but with smooth transitions.

Parameters for AdaptiveCalculator :

ParameterTypeDescription
nir_pathPathSingle‑band image
clip_limitfloatClipping limit to prevent noise amplification (typical values: 0.01–0.1)

Parameters for AdaptiveRGBCalculator :

ParameterTypeDescription
red_path, green_path, blue_pathPathRGB bands

Note : In AdaptiveRGBCalculator, the clip_limit is fixed at 0.08.

Example :

python
calc = AdaptiveCalculator(nir_path="NIR.tif", clip_limit=0.05)
calc.execute("./", title="CLAHE Enhanced")

2.5. GammaCalculator and GammaRGBCalculator – Gamma Correction

Scientific objective
Adjust image brightness by applying a power‑law (gamma) function. Brighten dark areas (γ<1γ<1) or darken bright areas (γ>1γ>1).

Full Explanation of the Formula

Gamma correction is a point transformation defined as :

Iout=gainIinγI_{\text{out}} = \text{gain} \cdot I_{\text{in}}^{\gamma}

where IinI_{in}​ is the input pixel value in [0,1][0,1]. The gain factor (default 1) scales the output linearly.

The effect of γγ :

  • γ=1γ=1 : identity.

  • 0<γ<10<γ<1 : lifts the mid‑tones and shadows (dark areas become brighter), compressing highlights.

  • γ>1γ>1 : darkens the image, stretching bright areas and compressing dark areas.

The transformation is applied pixel‑wise. For the RGB version, a fixed γ=0.5γ=0.5 and gain = 1 are used for each channel.

Note on the while loop in GammaCalculator :
The current implementation contains a loop that increases γγ by 0.2 if the mean of the output is greater than the mean of the input. This is a heuristic to ensure the image does not become overly bright, but it can lead to non‑convergent behaviour. The mathematical model is still the standard power‑law.

Parameters for GammaCalculator :

ParameterTypeDefaultDescription
nir_pathPathSingle‑band image
gammafloat0.2Gamma value
gainint1Gain factor

Parameters for GammaRGBCalculator :

ParameterTypeDescription
red_path, green_path, blue_pathPathRGB bands

Example :

python
calc = GammaCalculator(nir_path="NIR.tif", gamma=0.5, gain=1)
calc.execute("./", title="Gamma Corrected")

2.6. LogAdjustCalculator – Logarithmic Adjustment

Scientific objective
Increase contrast in dark areas of the image using a logarithmic transformation.

Full Explanation of the Formula

The logarithmic transformation implemented by exposure.adjust_log is :

Iout=gainlog(1+Iin)I_{\text{out}} = \text{gain} \cdot \log(1 + I_{\text{in}})

where IinI_{in}​ is in [0,1][0,1]. Because log(1+0)=0log⁡(1+0)=0 and log(1+1)=log20.693log⁡(1+1)=log⁡2≈0.693, the output range with default gain = 1 is [0,0.693][0,0.693]. The transformation stretches the lower values and compresses higher values, thereby enhancing details in shadows.

If inverse = True, the inverse transformation is applied :

Iout=gain(eIin1)I_{\text{out}} = \text{gain} \cdot (e^{I_{\text{in}}} - 1)

This does the opposite : it stretches bright regions and compresses dark ones.

Parameters :

ParameterTypeDefaultDescription
nir_pathPathSingle‑band image
gainint1Scaling factor
inverseboolFalseIf True, applies the inverse exponential transform

Example :

python
calc = LogAdjustCalculator(nir_path="NIR.tif", gain=2, inverse=False)
calc.execute("./", title="Log Adjusted")

2.7. SigmoidAdjustCalculator – Sigmoid Adjustment

Scientific objective
Compress mid‑range values and stretch dark and bright areas using a sigmoid (logistic) function. This enhances local contrast without losing details in mid‑tones.

Full Explanation of the Formula

The sigmoid adjustment in skimage.exposure.adjust_sigmoid is given by :

Iout=11+exp(gain(cutoffIin))I_{\text{out}} = \frac{1}{1 + \exp(\text{gain} \cdot (\text{cutoff} - I_{\text{in}}))}

  • cutoff (in [0,1][0,1]) is the inflection point. Pixels with intensity equal to cutoff map to 0.5.

  • gain controls the steepness of the curve. A larger gain produces a steeper transition, resulting in higher contrast near the cutoff.

  • The function squashes the input into [0,1][0,1]. If inverse = True, the transformation is reversed :

    Iout=cutoff1gainln(1Iin1)I_{\text{out}} = \text{cutoff} - \frac{1}{\text{gain}} \ln \left( \frac{1}{I_{\text{in}}} - 1 \right)

    which stretches the mid‑tones and compresses the extremes.

Parameters :

ParameterTypeDefaultDescription
nir_pathPathSingle‑band image
gainint1Steepness of the sigmoid curve
cutofffloat0.5Inflection point (range 0 to 1)
inverseboolFalseIf True, applies the inverse sigmoid

Example :

python
calc = SigmoidAdjustCalculator(nir_path="NIR.tif", gain=10, cutoff=0.5)
calc.execute("./", title="Sigmoid Contrast")

3. Common Feature: Histogram Output

All classes in this module (except LogAdjustCalculator) have a histogram_export() method that saves the histogram of the processed image as a plot. This method automatically adds the FEZrs watermark to the plot.

Parameters for histogram_export :

ParameterTypeDescription
output_pathPathSave path
titlestrPlot title
figsizetupleFigure size
filename_prefixstrFile name prefix
dpiintOutput quality

Example :

python
calc = EqualizeCalculator(nir_path="NIR.tif")
calc.histogram_export("./histograms/", title="Equalized Histogram")

4. Technical Notes and Development Suggestions

  • Unexpected behaviour in GammaCalculator : The while loop that changes the gamma value if the mean increases may cause an infinite loop or unpredictable results. It is recommended to remove this logic or replace it with a controlled condition.

  • Fixed values in RGB versions : In AdaptiveRGBCalculator and GammaRGBCalculator, parameters clip_limit and gamma are hard‑coded. Exposing them as constructor arguments would increase flexibility.

  • LogAdjustCalculator inheritance : This class has a histogram_export method but does not inherit from HistogramExportMixin. This inconsistency should be addressed in a future update.

  • Automatic watermark : The _add_watermark method (from HistogramExportMixin) adds the FEZrs logo to all histograms, which is excellent for professional publications.

  • Performance of RGB processing : Processing each channel separately and then stacking with np.stack may consume significant memory for very large images. Using chunked or Dask‑based processing is recommended for future versions.

Built with VitePress