Source code for xlandsat._enhancement

# Copyright (c) 2022 The xlandsat developers.
# Distributed under the terms of the MIT License.
# SPDX-License-Identifier: MIT
"""
Operations to enhance composites. Basically wrappers for skimage.exposure.
"""
import numpy as np
import skimage.color
import skimage.exposure


[docs] def equalize_histogram(composite, kernel_size=None, clip_limit=0.01): """ Adaptive histogram equalization for a composite Use this function to enhance the contrast of a composite when there are a few very dark or very light patches that dominate the color range. Use this instead of rescaling intensity (contrast stretching) to try to preserve some detail in the light/dark patches. If the composite has an alpha channel (transparency), it will be copied to the output intact. .. warning:: Results can be very bad if there are missing values (NaNs) in the composite. Use :func:`xlandsat.interpolate_missing` on the scene first (before creating the composite) if that is the case. Parameters ---------- composite : :class:`xarray.DataArray` A composite, as generated by :func:`xlandsat.composite`. kernel_size : int or None The size of region used in the algorithm. See :func:`skimage.exposure.equalize_adapthist` for details and defaults. clip_limit : float Clipping limit, normalized between 0 and 1 (higher values give more contrast). Returns ------- equalized_composite : :class:`xarray.DataArray` The composite after equalization, scaled back to the range of the original composite. Notes ----- This function first converts the composite from the RGB color space to the `HSV color space <https://en.wikipedia.org/wiki/HSL_and_HSV>`__. Then, it applies :func:`skimage.exposure.equalize_adapthist` to the values (intensity) channel. Finally, the composite is converted back into the RGB color space. """ result = composite.copy(deep=True) # Make sure the input is in the 0-255 range for the color space transform hsv = skimage.color.rgb2hsv( skimage.exposure.rescale_intensity(result.values[:, :, :3], out_range="uint8") ) hsv[:, :, 2] = skimage.exposure.equalize_adapthist( hsv[:, :, 2], kernel_size=kernel_size, clip_limit=clip_limit, ) result.values[:, :, :3] = skimage.exposure.rescale_intensity( skimage.color.hsv2rgb(hsv), out_range=str(composite.values.dtype), ) return result
[docs] def adjust_l1_colors(composite, percentile=0.1): """ Adjust the colors in an RGB composite from Level 1 data Corrects the balance of the red, green, and blue bands in an RGB (true color) composite made from Level 1 data (without atmospheric correction). This is **not as accurate as atmospheric correction** but can lead to nicer images in places where the atmospheric correction causes artifacts. **Do not use the output for calculating indices.** Parameters ---------- composite : :class:`xarray.DataArray` A composite, as generated by :func:`xlandsat.composite`. percentile : float The percentile range to use for the intensity rescaling. Will use the ``percentile`` as the lower bound and ``100 - percentile`` for the upper bound. Default is 0.1%. Returns ------- adjusted_composite : :class:`xarray.DataArray` The composite after color adjustment, scaled back to the range of the original composite. Notes ----- The correction raises each channel to the power of 1/2.2 (inverse of the sRGB gamma function) and then rescales the transformed intensity to the given percentile range. """ output = composite.copy() for i, channel in enumerate(["red", "green", "blue"]): scaled = composite.sel(channel=channel).values ** (1 / 2.2) vmin, vmax = np.percentile(scaled, (percentile, 100 - percentile)) output.values[:, :, i] = skimage.exposure.rescale_intensity( scaled, in_range=(vmin, vmax), out_range=str(composite.values.dtype), ) return output