Skip to content

Transforms API

Auto-generated from source — a multi-backend Keras port of torchgeo.transforms. Image transforms expect channels-last (... x H x W x C) input, matching the rest of keras_climate (torchgeo itself uses channels-first). See Data for a narrative guide.

Band indices

keras_climate.transforms.indices.AppendNormalizedDifferenceIndex

AppendNormalizedDifferenceIndex(index_a, index_b)

Append normalized difference index as channel to image tensor.

Computes the following index:

.. math::

\text{NDI} = \frac{A - B}{A + B}

Initialize a new transform instance.

Args: index_a: reference band channel index index_b: difference band channel index

Source code in keras_climate/transforms/indices.py
26
27
28
29
30
31
32
33
34
def __init__(self, index_a, index_b):
    """Initialize a new transform instance.

    Args:
        index_a: reference band channel index
        index_b: difference band channel index
    """
    self.index_a = index_a
    self.index_b = index_b

keras_climate.transforms.indices.AppendBNDVI

AppendBNDVI(index_nir, index_blue)

Bases: AppendNormalizedDifferenceIndex

Blue Normalized Difference Vegetation Index (BNDVI).

.. math::

\text{BNDVI} = \frac{\text{NIR} - \text{B}}{\text{NIR} + \text{B}}

https://doi.org/10.1016/S1672-6308(07)60027-4

Source code in keras_climate/transforms/indices.py
167
168
def __init__(self, index_nir, index_blue):
    super().__init__(index_a=index_nir, index_b=index_blue)

keras_climate.transforms.indices.AppendEVI

AppendEVI(index_nir, index_red, index_blue)

Enhanced Vegetation Index (EVI).

.. math::

\text{EVI} = \frac{2.5 \times (\text{NIR} - \text{R})} {\text{NIR} + 6 \times \text{R} - 7.5 \times \text{B} + 1}

https://doi.org/10.1016/S0034-4257(96)00112-5

Initialize a new transform instance.

Args: index_nir: index of the Near Infrared (NIR) band in the image index_red: index of the Red band in the image index_blue: index of the Blue band in the image

Source code in keras_climate/transforms/indices.py
302
303
304
305
306
307
308
309
310
311
312
def __init__(self, index_nir, index_red, index_blue):
    """Initialize a new transform instance.

    Args:
        index_nir: index of the Near Infrared (NIR) band in the image
        index_red: index of the Red band in the image
        index_blue: index of the Blue band in the image
    """
    self.index_nir = index_nir
    self.index_red = index_red
    self.index_blue = index_blue

keras_climate.transforms.indices.AppendGBNDVI

AppendGBNDVI(index_nir, index_green, index_blue)

Bases: AppendTriBandNormalizedDifferenceIndex

Green-Blue Normalized Difference Vegetation Index (GBNDVI).

.. math::

\text{GBNDVI} = \frac{\text{NIR} - (\text{G} + \text{B})}{\text{NIR} + (\text{G} + \text{B})}

https://doi.org/10.1016/S1672-6308(07)60027-4

Source code in keras_climate/transforms/indices.py
242
243
def __init__(self, index_nir, index_green, index_blue):
    super().__init__(index_a=index_nir, index_b=index_green, index_c=index_blue)

keras_climate.transforms.indices.AppendGNDVI

AppendGNDVI(index_nir, index_green)

Bases: AppendNormalizedDifferenceIndex

Green Normalized Difference Vegetation Index (GNDVI).

.. math::

\text{GNDVI} = \frac{\text{NIR} - \text{G}}{\text{NIR} + \text{G}}

https://doi.org/10.2134/agronj2001.933583x

Source code in keras_climate/transforms/indices.py
153
154
def __init__(self, index_nir, index_green):
    super().__init__(index_a=index_nir, index_b=index_green)

keras_climate.transforms.indices.AppendGRNDVI

AppendGRNDVI(index_nir, index_green, index_red)

Bases: AppendTriBandNormalizedDifferenceIndex

Green-Red Normalized Difference Vegetation Index (GRNDVI).

.. math::

\text{GRNDVI} = \frac{\text{NIR} - (\text{G} + \text{R})}{\text{NIR} + (\text{G} + \text{R})}

https://doi.org/10.1016/S1672-6308(07)60027-4

Source code in keras_climate/transforms/indices.py
227
228
def __init__(self, index_nir, index_green, index_red):
    super().__init__(index_a=index_nir, index_b=index_green, index_c=index_red)

keras_climate.transforms.indices.AppendMNDWI

AppendMNDWI(index_green, index_swir)

Bases: AppendNormalizedDifferenceIndex

Modified Normalized Difference Water Index (MNDWI).

.. math::

\text{MNDWI} = \frac{\text{G} - \text{SWIR}}{\text{G} + \text{SWIR}}

https://doi.org/10.1080/01431160600589179

Source code in keras_climate/transforms/indices.py
125
126
def __init__(self, index_green, index_swir):
    super().__init__(index_a=index_green, index_b=index_swir)

keras_climate.transforms.indices.AppendNBR

AppendNBR(index_nir, index_swir)

Bases: AppendNormalizedDifferenceIndex

Normalized Burn Ratio (NBR).

.. math::

\text{NBR} = \frac{\text{NIR} - \text{SWIR}}{\text{NIR} + \text{SWIR}}

https://www.yumpu.com/en/document/view/24226870/the-normalized-burn-ratio-and-relationships-to-burn-severity-/7

Source code in keras_climate/transforms/indices.py
55
56
def __init__(self, index_nir, index_swir):
    super().__init__(index_a=index_nir, index_b=index_swir)

keras_climate.transforms.indices.AppendNDBI

AppendNDBI(index_swir, index_nir)

Bases: AppendNormalizedDifferenceIndex

Normalized Difference Built-up Index (NDBI).

.. math::

\text{NDBI} = \frac{\text{SWIR} - \text{NIR}}{\text{SWIR} + \text{NIR}}

https://doi.org/10.1080/01431160304987

Source code in keras_climate/transforms/indices.py
69
70
def __init__(self, index_swir, index_nir):
    super().__init__(index_a=index_swir, index_b=index_nir)

keras_climate.transforms.indices.AppendNDRE

AppendNDRE(index_nir, index_vre1)

Bases: AppendNormalizedDifferenceIndex

Normalized Difference Red Edge Vegetation Index (NDRE).

.. math::

\text{NDRE} = \frac{\text{NIR} - \text{VRE1}}{\text{NIR} + \text{VRE1}}

https://agris.fao.org/agris-search/search.do?recordID=US201300795763

Source code in keras_climate/transforms/indices.py
181
182
def __init__(self, index_nir, index_vre1):
    super().__init__(index_a=index_nir, index_b=index_vre1)

keras_climate.transforms.indices.AppendNDSI

AppendNDSI(index_green, index_swir)

Bases: AppendNormalizedDifferenceIndex

Normalized Difference Snow Index (NDSI).

.. math::

\text{NDSI} = \frac{\text{G} - \text{SWIR}}{\text{G} + \text{SWIR}}

https://doi.org/10.1109/IGARSS.1994.399618

Source code in keras_climate/transforms/indices.py
83
84
def __init__(self, index_green, index_swir):
    super().__init__(index_a=index_green, index_b=index_swir)

keras_climate.transforms.indices.AppendNDVI

AppendNDVI(index_nir, index_red)

Bases: AppendNormalizedDifferenceIndex

Normalized Difference Vegetation Index (NDVI).

.. math::

\text{NDVI} = \frac{\text{NIR} - \text{R}}{\text{NIR} + \text{R}}

https://doi.org/10.1016/0034-4257(79)90013-0

Source code in keras_climate/transforms/indices.py
97
98
def __init__(self, index_nir, index_red):
    super().__init__(index_a=index_nir, index_b=index_red)

keras_climate.transforms.indices.AppendNDWI

AppendNDWI(index_green, index_nir)

Bases: AppendNormalizedDifferenceIndex

Normalized Difference Water Index (NDWI).

.. math::

\text{NDWI} = \frac{\text{G} - \text{NIR}}{\text{G} + \text{NIR}}

https://doi.org/10.1080/01431169608948714

Source code in keras_climate/transforms/indices.py
111
112
def __init__(self, index_green, index_nir):
    super().__init__(index_a=index_green, index_b=index_nir)

keras_climate.transforms.indices.AppendRBNDVI

AppendRBNDVI(index_nir, index_red, index_blue)

Bases: AppendTriBandNormalizedDifferenceIndex

Red-Blue Normalized Difference Vegetation Index (RBNDVI).

.. math::

\text{RBNDVI} = \frac{\text{NIR} - (\text{R} + \text{B})}{\text{NIR} + (\text{R} + \text{B})}

https://doi.org/10.1016/S1672-6308(07)60027-4

Source code in keras_climate/transforms/indices.py
257
258
def __init__(self, index_nir, index_red, index_blue):
    super().__init__(index_a=index_nir, index_b=index_red, index_c=index_blue)

keras_climate.transforms.indices.AppendSAVI

AppendSAVI(index_nir, index_red)

Soil-Adjusted Vegetation Index (SAVI).

.. math::

\text{SAVI} = \frac{1.5 \times (\text{NIR} - \text{R})} {\text{NIR} + \text{R} + 0.5}

https://doi.org/10.1016/0034-4257(88)90106-X

Initialize a new transform instance.

Args: index_nir: index of the Near Infrared (NIR) band in the image index_red: index of the Red band in the image

Source code in keras_climate/transforms/indices.py
272
273
274
275
276
277
278
279
280
def __init__(self, index_nir, index_red):
    """Initialize a new transform instance.

    Args:
        index_nir: index of the Near Infrared (NIR) band in the image
        index_red: index of the Red band in the image
    """
    self.index_nir = index_nir
    self.index_red = index_red

keras_climate.transforms.indices.AppendSWI

AppendSWI(index_vre1, index_swir2)

Bases: AppendNormalizedDifferenceIndex

Standardized Water-Level Index (SWI).

.. math::

\text{SWI} = \frac{\text{VRE1} - \text{SWIR2}}{\text{VRE1} + \text{SWIR2}}

https://doi.org/10.3390/w13121647

Source code in keras_climate/transforms/indices.py
139
140
def __init__(self, index_vre1, index_swir2):
    super().__init__(index_a=index_vre1, index_b=index_swir2)

keras_climate.transforms.indices.AppendTriBandNormalizedDifferenceIndex

AppendTriBandNormalizedDifferenceIndex(index_a, index_b, index_c)

Append normalized difference index involving 3 bands as channel to image tensor.

.. math::

\text{TBNDI} = \frac{A - (B + C)}{A + (B + C)}

Initialize a new transform instance.

Args: index_a: reference band channel index index_b: difference band channel index of component 1 index_c: difference band channel index of component 2

Source code in keras_climate/transforms/indices.py
193
194
195
196
197
198
199
200
201
202
203
def __init__(self, index_a, index_b, index_c):
    """Initialize a new transform instance.

    Args:
        index_a: reference band channel index
        index_b: difference band channel index of component 1
        index_c: difference band channel index of component 2
    """
    self.index_a = index_a
    self.index_b = index_b
    self.index_c = index_c

Color

keras_climate.transforms.color.RandomGrayscale

RandomGrayscale(weights, p=0.1, same_on_batch=False)

Apply random transformation to grayscale according to a probability p value.

There is no single agreed upon definition of grayscale for MSI. Some possibilities include:

  • Average of all bands: :math:\frac{1}{C} where :math:C is the number of spectral channels.
  • RGB-only bands: :math:[0.299, 0.587, 0.114] for the RGB channels, 0 for all other channels.
  • PCA: the first principal component across the spectral axis.

The weight vector you provide will be automatically rescaled to sum to 1 in order to avoid changing the intensity of the image.

Expects channels-last (... x H x W x C) input.

Initialize a new RandomGrayscale instance.

Args: weights: Weights applied to each channel to compute a grayscale representation. Should be the same length as the number of channels. p: Probability of the image to be transformed to grayscale. same_on_batch: Apply the same transformation across the batch.

Source code in keras_climate/transforms/color.py
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
def __init__(self, weights, p=0.1, same_on_batch=False):
    """Initialize a new RandomGrayscale instance.

    Args:
        weights: Weights applied to each channel to compute a grayscale
            representation. Should be the same length as the number of
            channels.
        p: Probability of the image to be transformed to grayscale.
        same_on_batch: Apply the same transformation across the batch.
    """
    weights = ops.convert_to_tensor(weights)
    # Rescale to sum to 1
    self.weights = weights / ops.sum(weights)
    self.p = p
    self.same_on_batch = same_on_batch

SAR

keras_climate.transforms.sar.LeeFilter

LeeFilter(window_size=7, num_looks=1.0, p=1.0, same_on_batch=False)

Lee speckle reduction filter for SAR imagery.

Applies the classic Lee (1980) adaptive filter to reduce multiplicative speckle noise while preserving edges and structural detail. Operates on SAR intensity imagery with non-negative values; amplitude and dB inputs should be converted to intensity beforehand.

If you use this method in your research, please cite: https://doi.org/10.1109/TPAMI.1980.4766994

Initialize a new LeeFilter instance.

Args: window_size: Odd integer size of the local statistics window. num_looks: Equivalent number of looks (ENL) of the input SAR data. p: Probability of applying the filter to each sample. same_on_batch: Apply the same transformation across the batch.

Raises: ValueError: If window_size is not a positive odd integer. ValueError: If num_looks is not strictly positive.

Source code in keras_climate/transforms/sar.py
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
def __init__(self, window_size=7, num_looks=1.0, p=1.0, same_on_batch=False):
    """Initialize a new LeeFilter instance.

    Args:
        window_size: Odd integer size of the local statistics window.
        num_looks: Equivalent number of looks (ENL) of the input SAR data.
        p: Probability of applying the filter to each sample.
        same_on_batch: Apply the same transformation across the batch.

    Raises:
        ValueError: If ``window_size`` is not a positive odd integer.
        ValueError: If ``num_looks`` is not strictly positive.
    """
    if window_size < 1 or window_size % 2 == 0:
        raise ValueError(
            f"window_size must be a positive odd integer, got {window_size}"
        )
    if num_looks <= 0:
        raise ValueError(f"num_looks must be > 0, got {num_looks}")
    self.window_size = window_size
    self.num_looks = num_looks
    self.p = p
    self.same_on_batch = same_on_batch

keras_climate.transforms.sar.lee_filter

lee_filter(image, window_size=7, num_looks=1.0, eps=1e-08)

Apply the Lee filter to a SAR intensity image.

The Lee (1980) filter assumes a multiplicative speckle model :math:x = s \cdot v where :math:s is the underlying signal and :math:v is unit-mean speckle with variance :math:\sigma_v^2 = 1 / L for an :math:L-look intensity image. The local linear minimum mean square error (LMMSE) estimator is

.. math::

\hat{s} = \mu + k \cdot (x - \mu),
\quad
k = \frac{\sigma_s^2}{\sigma_s^2 + \sigma_v^2 \mu^2}

In homogeneous regions the filter behaves like a mean filter; near edges it preserves detail by giving the local mean less weight.

If you use this method in your research, please cite: https://doi.org/10.1109/TPAMI.1980.4766994

Args: image: SAR intensity tensor of shape (B, H, W, C) (or (H, W, C)). Values are assumed non-negative intensities, not amplitudes or dB. window_size: Odd integer size of the local statistics window. Larger values produce more smoothing at the cost of detail. num_looks: Equivalent number of looks (ENL) of the input image. Single-look complex (SLC) intensity has num_looks=1. Sentinel-1 GRDH typically has num_looks near 5. eps: Numerical floor to avoid division by zero in flat regions.

Returns: Filtered tensor of the same shape and dtype as image.

Raises: ValueError: If window_size is not a positive odd integer. ValueError: If num_looks is not strictly positive.

Source code in keras_climate/transforms/sar.py
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
def lee_filter(image, window_size=7, num_looks=1.0, eps=1e-8):
    r"""Apply the Lee filter to a SAR intensity image.

    The Lee (1980) filter assumes a multiplicative speckle model
    :math:`x = s \cdot v` where :math:`s` is the underlying signal and
    :math:`v` is unit-mean speckle with variance
    :math:`\sigma_v^2 = 1 / L` for an :math:`L`-look intensity image. The
    local linear minimum mean square error (LMMSE) estimator is

    .. math::

        \hat{s} = \mu + k \cdot (x - \mu),
        \quad
        k = \frac{\sigma_s^2}{\sigma_s^2 + \sigma_v^2 \mu^2}

    In homogeneous regions the filter behaves like a mean filter; near edges
    it preserves detail by giving the local mean less weight.

    If you use this method in your research, please cite:
    https://doi.org/10.1109/TPAMI.1980.4766994

    Args:
        image: SAR intensity tensor of shape ``(B, H, W, C)`` (or ``(H, W, C)``).
            Values are assumed non-negative intensities, not amplitudes or dB.
        window_size: Odd integer size of the local statistics window. Larger
            values produce more smoothing at the cost of detail.
        num_looks: Equivalent number of looks (ENL) of the input image.
            Single-look complex (SLC) intensity has ``num_looks=1``.
            Sentinel-1 GRDH typically has ``num_looks`` near 5.
        eps: Numerical floor to avoid division by zero in flat regions.

    Returns:
        Filtered tensor of the same shape and dtype as ``image``.

    Raises:
        ValueError: If ``window_size`` is not a positive odd integer.
        ValueError: If ``num_looks`` is not strictly positive.
    """
    if window_size < 1 or window_size % 2 == 0:
        raise ValueError(f"window_size must be a positive odd integer, got {window_size}")
    if num_looks <= 0:
        raise ValueError(f"num_looks must be > 0, got {num_looks}")

    image, was_unbatched = ensure_batched(image)

    sigma_v_sq = 1.0 / float(num_looks)

    mean_local = _box_filter(image, window_size)
    mean_sq_local = _box_filter(image * image, window_size)
    var_local = ops.maximum(mean_sq_local - mean_local * mean_local, 0.0)

    var_signal = ops.maximum(var_local - sigma_v_sq * mean_local * mean_local, 0.0)
    weight = var_signal / (var_signal + sigma_v_sq * mean_local * mean_local + eps)

    out = mean_local + weight * (image - mean_local)
    return ops.squeeze(out, axis=0) if was_unbatched else out

Spatial

keras_climate.transforms.spatial.SatSlideMix

SatSlideMix(gamma=1, beta=(0.0, 1.0), p=0.5)

Applies the Sat-SlideMix augmentation to a batch of images and masks.

Sat-SlideMix rolls (circularly shifts) images along either the height or width axis by a random amount.

If you use this method in your research, please cite: https://doi.org/10.1609/aaai.v39i27.35028

Expects channels-last (... x H x W x C) input.

Initialize a new SatSlideMix instance.

Args: gamma: The number of augmented samples to create for each input image. The output batch size will be gamma * B. beta: The range of percentage (0.0 to 1.0) of the image dimension (height or width) to shift. p: Probability to apply the augmentation on each sample.

Raises: AssertionError: If gamma is not a positive integer.

Source code in keras_climate/transforms/spatial.py
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
def __init__(self, gamma=1, beta=(0.0, 1.0), p=0.5):
    """Initialize a new SatSlideMix instance.

    Args:
        gamma: The number of augmented samples to create for each input
            image. The output batch size will be ``gamma * B``.
        beta: The range of percentage (0.0 to 1.0) of the image
            dimension (height or width) to shift.
        p: Probability to apply the augmentation on each sample.

    Raises:
        AssertionError: If ``gamma`` is not a positive integer.
    """
    if not (isinstance(gamma, int) and gamma > 0):
        raise AssertionError("gamma must be a positive integer")
    self.gamma = gamma
    self.beta = tuple(beta) if isinstance(beta, (tuple, list)) else (0.0, float(beta))
    self.p = p

Temporal

keras_climate.transforms.temporal.Rearrange

Rearrange(*args, **kwargs)

Rearrange tensor dimensions.

Examples: To insert a time dimension::

    Rearrange('b (t c) h w -> b t c h w', c=1)

To collapse the time dimension::

    Rearrange('b t c h w -> b (t c) h w')

Initialize a Rearrange instance.

Args: *args: Positional arguments for :func:einops.rearrange. **kwargs: Keyword arguments for :func:einops.rearrange.

Source code in keras_climate/transforms/temporal.py
19
20
21
22
23
24
25
26
27
def __init__(self, *args, **kwargs):
    """Initialize a Rearrange instance.

    Args:
        *args: Positional arguments for :func:`einops.rearrange`.
        **kwargs: Keyword arguments for :func:`einops.rearrange`.
    """
    self.args = args
    self.kwargs = kwargs