diff --git a/services/inventory/dev_af/inventory.json b/services/inventory/dev_af/inventory.json index 748826be..63231e2a 100644 --- a/services/inventory/dev_af/inventory.json +++ b/services/inventory/dev_af/inventory.json @@ -1,5 +1,5 @@ { - "total_layers_count": 36, + "total_layers_count": 37, "layers": [ { "layer": "s2_l2a", @@ -169,6 +169,32 @@ "count" ] }, + { + "layer": "gm_ls8_ls9_annual", + "product": [ + "gm_ls8_ls9_annual" + ], + "styles_count": 17, + "styles_list": [ + "simple_rgb", + "infrared_green", + "tmad_rgb_std", + "tmad_rgb_sens", + "ndvi", + "ndwi", + "mndwi", + "blue", + "green", + "red", + "nir", + "swir_1", + "swir_2", + "arcsec_sdev", + "log_edev", + "log_bcdev", + "count" + ] + }, { "layer": "gm_ls5_ls7_annual", "product": [ diff --git a/services/inventory/prod_af/inventory.json b/services/inventory/prod_af/inventory.json index 1e772060..260b46e0 100644 --- a/services/inventory/prod_af/inventory.json +++ b/services/inventory/prod_af/inventory.json @@ -1,5 +1,5 @@ { - "total_layers_count": 35, + "total_layers_count": 36, "layers": [ { "layer": "s2_l2a", @@ -169,6 +169,32 @@ "count" ] }, + { + "layer": "gm_ls8_ls9_annual", + "product": [ + "gm_ls8_ls9_annual" + ], + "styles_count": 17, + "styles_list": [ + "simple_rgb", + "infrared_green", + "tmad_rgb_std", + "tmad_rgb_sens", + "ndvi", + "ndwi", + "mndwi", + "blue", + "green", + "red", + "nir", + "swir_1", + "swir_2", + "arcsec_sdev", + "log_edev", + "log_bcdev", + "count" + ] + }, { "layer": "gm_ls5_ls7_annual", "product": [ diff --git a/services/ows_refactored/dev_af_ows_root_cfg.py b/services/ows_refactored/dev_af_ows_root_cfg.py index 6a469900..61bdfe6b 100644 --- a/services/ows_refactored/dev_af_ows_root_cfg.py +++ b/services/ows_refactored/dev_af_ows_root_cfg.py @@ -154,6 +154,10 @@ "include": "ows_refactored.surface_reflectance.ows_gm_ls8_annual_cfg.layer", "type": "python", }, + { + "include": "ows_refactored.surface_reflectance.ows_gm_ls8_ls9_annual_cfg.layer", + "type": "python", + }, { "include": "ows_refactored.surface_reflectance.ows_gm_ls5_ls7_annual_cfg.layer", "type": "python", diff --git a/services/ows_refactored/prod_af_ows_root_cfg.py b/services/ows_refactored/prod_af_ows_root_cfg.py index 3f6c102e..47882b9c 100644 --- a/services/ows_refactored/prod_af_ows_root_cfg.py +++ b/services/ows_refactored/prod_af_ows_root_cfg.py @@ -153,6 +153,10 @@ "include": "ows_refactored.surface_reflectance.ows_gm_ls8_annual_cfg.layer", "type": "python", }, + { + "include": "ows_refactored.surface_reflectance.ows_gm_ls8_ls9_annual_cfg.layer", + "type": "python", + }, { "include": "ows_refactored.surface_reflectance.ows_gm_ls5_ls7_annual_cfg.layer", "type": "python", diff --git a/services/ows_refactored/surface_reflectance/band_sr_cfg.py b/services/ows_refactored/surface_reflectance/band_sr_cfg.py index 5ea2656b..4646c575 100644 --- a/services/ows_refactored/surface_reflectance/band_sr_cfg.py +++ b/services/ows_refactored/surface_reflectance/band_sr_cfg.py @@ -55,6 +55,8 @@ "COUNT": ["count"], } +bands_ls8_ls9_gm = bands_ls8_gm + bands_ls5_ls7_gm = { "SR_B1": ["blue", "band_2"], "SR_B2": ["green", "band_3"], diff --git a/services/ows_refactored/surface_reflectance/ows_gm_ls5_ls7_annual_cfg.py b/services/ows_refactored/surface_reflectance/ows_gm_ls5_ls7_annual_cfg.py index 8d8edcdb..cd9dfb81 100644 --- a/services/ows_refactored/surface_reflectance/ows_gm_ls5_ls7_annual_cfg.py +++ b/services/ows_refactored/surface_reflectance/ows_gm_ls5_ls7_annual_cfg.py @@ -1,6 +1,6 @@ from ows_refactored.common.ows_reslim_cfg import reslim_continental from ows_refactored.surface_reflectance.band_sr_cfg import bands_ls5_ls7_gm -from ows_refactored.surface_reflectance.style_sr_cfg import styles_gm_ls578_list +from ows_refactored.surface_reflectance.style_sr_cfg import styles_gm_ls5789_list layer = { @@ -50,6 +50,6 @@ "native_resolution": [30.0, -30.0], "styling": { "default_style": "simple_rgb", - "styles": styles_gm_ls578_list, + "styles": styles_gm_ls5789_list, } } diff --git a/services/ows_refactored/surface_reflectance/ows_gm_ls8_annual_cfg.py b/services/ows_refactored/surface_reflectance/ows_gm_ls8_annual_cfg.py index f252920a..45dfc298 100644 --- a/services/ows_refactored/surface_reflectance/ows_gm_ls8_annual_cfg.py +++ b/services/ows_refactored/surface_reflectance/ows_gm_ls8_annual_cfg.py @@ -1,6 +1,6 @@ from ows_refactored.common.ows_reslim_cfg import reslim_continental from ows_refactored.surface_reflectance.band_sr_cfg import bands_ls8_gm -from ows_refactored.surface_reflectance.style_sr_cfg import styles_gm_ls578_list +from ows_refactored.surface_reflectance.style_sr_cfg import styles_gm_ls5789_list layer = { @@ -50,6 +50,6 @@ "native_resolution": [30.0, -30.0], "styling": { "default_style": "simple_rgb", - "styles": styles_gm_ls578_list, + "styles": styles_gm_ls5789_list, } } diff --git a/services/ows_refactored/surface_reflectance/ows_gm_ls8_ls9_annual_cfg.py b/services/ows_refactored/surface_reflectance/ows_gm_ls8_ls9_annual_cfg.py new file mode 100644 index 00000000..53122493 --- /dev/null +++ b/services/ows_refactored/surface_reflectance/ows_gm_ls8_ls9_annual_cfg.py @@ -0,0 +1,55 @@ +from ows_refactored.common.ows_reslim_cfg import reslim_continental +from ows_refactored.surface_reflectance.band_sr_cfg import bands_ls8_ls9_gm +from ows_refactored.surface_reflectance.style_sr_cfg import styles_gm_ls5789_list + + +layer = { + "title": "Annual GeoMAD (Landsat 8 & Landsat 9)", + "name": "gm_ls8_ls9_annual", + "abstract": """ +Individual remote sensing images can be affected by noisy data, such as clouds, cloud shadows, and haze. To produce cleaner images that can be compared more easily across time, we can create 'summary' images or 'composites' that combine multiple images into one image to reveal the median or 'typical' appearance of the landscape for a certain time period. + +One approach is to create a geomedian. A geomedian is based on a high-dimensional statistic called the 'geometric median' (Small 1990), which effectively trades a temporal stack of poor-quality observations for a single high-quality pixel composite with reduced spatial noise (Roberts et al. 2017). In contrast to a standard median, a geomedian maintains the relationship between spectral bands. This allows further analysis on the composite images, just as we would on the original satellite images (e.g. by allowing the calculation of common band indices like NDVI). An annual geomedian image is calculated from the surface reflectance values drawn from a calendar year. + +In addition, surface reflectance varabilities within the same time period can be measured to support characterization of the land surfaces. The median absolute deviation (MAD) is a robust measure (resilient to outliers) of the variability within a dataset. For multi-spectral Earth observation, deviation can be measured against the geomedian using a number of distance metrics. Three of these metrics are adopted to highlight different types of changes in the landscape: +- Euclidean distance (EMAD), which is more sensitive to changes in target brightness. +- Cosine (spectral) distance (SMAD), which is more sensitive to changes in target spectral response. +- Bray Curtis dissimilarity (BCMAD), which is more sensitive to the distribution of the observation values through time. + +More techincal information about the GeoMAD product can be found in the User Guide (https://docs.digitalearthafrica.org/en/latest/data_specs/GeoMAD_specs.html) + +This product has a spatial resolution of 30 m and is available annually from 2013. + +It is derived from USGS Collection 2, Level 2 Landsat 8 & 9 surface reflectance data. + +Annual geomedian images enable easy visual and algorithmic interpretation, e.g. understanding urban expansion, at annual intervals. They are also useful for characterising permanent landscape features such as woody vegetation. The MADs can be used on their own or together with geomedian to gain insights about the land surface, e.g. for land cover classificiation and for change detection from year to year. + +For more information on the algorithm, see https://doi.org/10.1109/TGRS.2017.2723896 and https://doi.org/10.1109/IGARSS.2018.8518312 + +""", + "product_name": "gm_ls8_ls9_annual", + # Low product name + # + # Leave commented until we have an appropriate summary product. + # (Packaged like the main product, but with much much lower + # resolution and much much higher area covered in each dataset. + # + "low_res_product_name": "gm_ls8_ls9_annual_lowres", + "bands": bands_ls8_ls9_gm, + "dynamic": False, + "resource_limits": reslim_continental, + "time_resolution": "year", + "image_processing": { + "extent_mask_func": "ows_refactored.common.ows_util_tools.mask_by_emad_nan", + # "extent_mask_func": "datacube_ows.ogc_utils.mask_by_val", + "always_fetch_bands": ["EMAD"], + "manual_merge": False, # True + "apply_solar_corrections": False, + }, + "native_crs": "EPSG:6933", + "native_resolution": [30.0, -30.0], + "styling": { + "default_style": "simple_rgb", + "styles": styles_gm_ls5789_list, + } +} diff --git a/services/ows_refactored/surface_reflectance/style_sr_cfg.py b/services/ows_refactored/surface_reflectance/style_sr_cfg.py index 402dd8c9..b63fe702 100644 --- a/services/ows_refactored/surface_reflectance/style_sr_cfg.py +++ b/services/ows_refactored/surface_reflectance/style_sr_cfg.py @@ -952,8 +952,8 @@ style_gm_s2_count, ] -# Used in the LS8 GeoMAD and LS5-LS7 GeoMAD -styles_gm_ls578_list = [ +# Used in the LS8, LS8-LS9 and LS5-LS7 GeoMAD +styles_gm_ls5789_list = [ style_gm_simple_rgb, style_gm_irg, style_tmad_rgb_std,