Skip to content

floods module

hydrafloods.floods

discrete_difference(observation, reference)

Function to find the difference between an observation and reference dataset. The data should be discrete values (i.e. a classification). This function expects that water/floods = 1 and land = 0. Unknown values should be masked.

Parameters:

Name Type Description Default
observation ee.Image

image object representing the observation of water to extract floods

required
reference ee.Image

image object representing reference/permanent water to extract floods from

required

Returns:

Type Description
ee.Image

extracted flood image where flood values = 1

Source code in hydrafloods/floods.py
@decorators.keep_attrs
def discrete_difference(observation, reference):
    """Function to find the difference between an observation and reference dataset.
    The data should be discrete values (i.e. a classification). This function
    expects that water/floods = 1 and land = 0. Unknown values should be masked.

    args:
        observation (ee.Image): image object representing the observation of water to extract floods
        reference (ee.Image): image object representing reference/permanent water to extract floods from

    returns:
        ee.Image: extracted flood image where flood values = 1
    """
    og_mask = observation.mask()
    floods = observation.unmask(0).add(reference.unmask(0).multiply(2)).eq(1)
    return floods.updateMask(og_mask).rename("flood")

extract_flood(observation, reference='seasonal', permanent_threshold=75)

Function used to extract flooded area based off of different JRC datasets. Expects that the water image has water = 1, land = 0, unknown = mask

Parameters:

Name Type Description Default
observation ee.Image

image object representing the observation of water to extract floods

required
reference str

string to define how permanent water is defined. 'yearly' means use past 5 years of JRC yearly data and extract permanent class. 'seasonal' means use monthly water occurrence for the month of observation. 'occurrence' means use full JRC occurrence dataset irregardless of time. default = seasonal

'seasonal'
permanent_threshold int

threshold value in % to define permanent water. Only used when reference equals 'seasonal' or 'occurrence'. default = 75

75

Returns:

Type Description
ee.Image

the extracted flood image where floods = 1

Exceptions:

Type Description
NotImplementedError

when user provides an invalid option for reference parameter

Source code in hydrafloods/floods.py
@decorators.keep_attrs
def extract_flood(observation, reference="seasonal", permanent_threshold=75):
    """Function used to extract flooded area based off of different JRC datasets.
    Expects that the water image has water = 1, land = 0, unknown = mask

    args:
        observation (ee.Image): image object representing the observation of water to extract floods
        reference (str): string to define how permanent water is defined. 'yearly' means use past 5 years
            of JRC yearly data and extract permanent class. 'seasonal' means use monthly water occurrence
            for the month of observation. 'occurrence' means use full JRC occurrence dataset irregardless of
            time. default = seasonal
        permanent_threshold (int): threshold value in % to define permanent water. Only used when
            reference equals 'seasonal' or 'occurrence'. default = 75

    returns:
        ee.Image: the extracted flood image where floods = 1

    raises:
        NotImplementedError: when user provides an invalid option for reference parameter
    """

    if reference == "yearly":
        end_time = observation.date()
        permanent_water = (
            ee.ImageCollection(
                "JRC/GSW1_2/YearlyHistory"
            )  # get the JRC historical dataset
            .filterDate(
                "1985-01-01", end_time
            )  # filter for historical data up to date of interest
            .limit(5, "system:time_start", False)  # grab the 5 latest images
            .map(
                lambda x: x.select("waterClass").eq(3)
            )  # extract out the permanent water class
            .sum()  # check if a pixel has been classified as permanent water in the past 5 years
            .unmask(0)
            .gt(0)
        )

    elif reference == "seasonal":
        month = observation.date().get("month")
        permanent_water = (
            ee.ImageCollection("JRC/GSW1_3/MonthlyRecurrence")
            .select("monthly_recurrence")
            .filter(ee.Filter.eq("month", month))
            .first()
            .gt(permanent_threshold)
        )

    elif reference == "occurrence":
        permanent_water = (
            ee.Image("JRC/GSW1_3/GlobalSurfaceWater")
            .select("occurrence")
            .gt(permanent_threshold)
        )

    else:
        raise NotImplementedError(
            "the selected reference method, {reference}, is not implemeted. please select either 'yearly','seasonal', or 'occurrence'"
        )

    return discrete_difference(observation, permanent_water)

lar_change_detection(observation, reference, band=None, in_units='dB', segmentation='edgeotsu', **kwargs)

Log Amplitude Ratio change detection method. https://doi.org/10.1080/014311698215649 Note: This method only works for SAR imagery.

Parameters:

Name Type Description Default
observation ee.Image required
reference ee.Image required
band str | None,optional

band name to use for thresholding, if set to None will use first band in image. default = None

None
in_units str

string specifying the input units for the imagery. Options are 'dB' or 'power'. If in_units = 'dB', then the data is converted to power units. default = dB

'dB'
segmentation str | None

segmentation method to use to . Options are 'edgeotsu', 'bmaxotsu', or None. If none is provided then no segmentation is applied and the raw log amplitude ratio is returned. default = edgeotsu

'edgeotsu'
**kwargs

optional keywords to pass to segmentation method, not required if segmentation = None

{}

Returns:

Type Description
ee.Image
Source code in hydrafloods/floods.py
@decorators.keep_attrs
def lar_change_detection(
    observation, reference, band=None, in_units="dB", segmentation="edgeotsu", **kwargs
):
    """Log Amplitude Ratio change detection method. https://doi.org/10.1080/014311698215649
    Note: This method only works for SAR imagery.

    args:
        observation (ee.Image):
        reference (ee.Image):
        band (str | None,optional): band name to use for thresholding, if set to `None` will use first band in image. default = None
        in_units (str, optional): string specifying the input units for the imagery. Options are 'dB' or 'power'. If in_units = 'dB',
            then the data is converted to power units. default = dB
        segmentation (str | None, optional): segmentation method to use to . Options are 'edgeotsu', 'bmaxotsu', or None. If none
            is provided then no segmentation is applied and the raw log amplitude ratio is returned. default = edgeotsu
        **kwargs: optional keywords to pass to segmentation method, not required if segmentation = None


    returns:
        ee.Image:
    """
    if band is None:
        band = observation.bandNames().get(0)
    # convert the db data to amplitude units
    # amplitude = sqrt(power)
    # then divide post/pre and take the log
    if in_units == "dB":
        lar = (
            geeutils.db_to_power(observation).sqrt().select(band)
            .divide(geeutils.db_to_power(reference).sqrt().select(band))
            .log10()
        )

    elif in_units == "power":
        lar = observation.sqrt().select(band).divide(reference.sqrt().select(band)).log10()

    else:
        raise NotImplementedError(
            f"input units could not be infered from {in_units}, please select either 'dB' or 'power'"
        )

    if segmentation == "edgeotsu":
        floods_lar = thresholding.edge_otsu(lar, band=band, **kwargs)

    elif segmentation == "bmaxotsu":
        floods_lar = thresholding.bmax_otsu(lar, band=band, **kwargs)

    elif segmentation == None:
        floods_lar = lar

    else:
        raise NotImplementedError(
            f"selected segmentation method {segmentation} is not valid, please select 'edgeotsu', 'bmaxotsu', or None"
        )

    return floods_lar