Skip to content

Layers appear out of sync in WMS and WCS if band math is used in styling #1041

@christophfriedrich

Description

@christophfriedrich

Description

The standard way to serve calculated products (e.g. NDVI) via WMS seems to be to load the raw bands and do the band math accordingly, e.g. like in this example from the documentation:

ndvi_bidirection_cfg = {
    "index_function": {
        "function": "datacube_ows.band_utils.norm_diff",
        "mapped_bands": True,
        "kwargs": {"band1": "nir", "band2": "red"},
    },
    "mpl_ramp": "RdYlGn",
    "range": [-1.0, 1.0]
}

Seeing this all over the docs, I set up a system that uses somewhat complex index functions to calculate various products (see e.g. https://github.com/eo2cube/ows_config/blob/4fe21710cc278e9c2ee4b46a742aaaa9f343899d/s2_vi/formulas.py#L16).

Now we need the raw values of those calculations elsewhere and thought "Perfect, we've got the WCS, we can just export them from there!" But as the WCS serves the "raw data" and the calculations are technically happening in the styling part, the only thing I got were the very raw imagery values, not the calculated product values. (To stay with the example: I got the Red and NIR values, not the NDVI calculated from them.)

I browsed through the existing issues and this has been touched upon before at #510 (comment) with Paul stating:

We feel that the purpose of WCS is to provide access to the raw data and that anybody interested in WCS would be more than capable of doing trivial bandmath on the data themselves after downloading.

I agree that I'm perfectly capable of doing the same bandmath again elsewhere, but (1) it's not me who wants to use those values and (2) I've got everything so nicely configured in OWS already that it would be super sweet to just download the stuff from there straight away. I also agree that WCS should provide the raw data, but the question is how raw should it be?

I would also like to raise the point of consistency of the same product across the various services. Which leads me to formulate the expected behaviour: WMS and WCS export "the same thing". As in: Taking the values from the WCS and applying the same colour ramp as in the styling config results in the same image that the WMS exports. Or worded vice versa: 'Un-applying' the colour ramp from the WMS image yields the WCS values.

Or is there another way to get values out of the WCS that have the index function already applied?

Steps to Reproduce

Compare the result of this WMS request:

https://ows.eo2cube.org/wms?SERVICE=WMS&VERSION=1.3.0&REQUEST=GetMap&LAYERS=s2_vi_ndvi_diff_winter_wheat&STYLES=&WIDTH=512&HEIGHT=512&FORMAT=image%2Fpng&CRS=EPSG%3A3857&DPI=96&MAP_RESOLUTION=96&FORMAT_OPTIONS=dpi%3A96&TRANSPARENT=TRUE&TIME=2020-01-02T00%3A00%3A00Z&BBOX=1389247.83251150674186647,7142683.10669049434363842,1392738.67198907374404371,7146173.94616806134581566

with what you get from this corresponding WCS request:

https://ows.eo2cube.org/wcs?SERVICE=WCS&VERSION=1.0.0&REQUEST=GetCoverage&FORMAT=GeoTIFF&COVERAGE=s2_vi_ndvi_diff_winter_wheat&WIDTH=512&HEIGHT=512&CRS=EPSG:3857&RESPONSE_CRS=EPSG:3857&TIME=2020-01-02T00%3A00%3A00Z&BBOX=1389247.83251150674186647,7142683.10669049434363842,1392738.67198907374404371,7146173.94616806134581566

(same TIME and BBOX and LAYERS/COVERAGE)

Context (Environment)

datacube-ows version

datacube-ows-update --version
Open Data Cube Open Web Services (datacube-ows) version 1.8.36.dev0+g67003f3.d20240617

datacube-ows config

https://github.com/eo2cube/ows_config/

datacube product metadata

datacube product show s2_c1_l2a

Result
description: The Sentinel-2 program provides global imagery in thirteen spectral bands
    at 10m-60m resolution and a revisit time of approximately five days. This dataset
    represents the global Sentinel-2 archive, from 2016 to the present, processed
    to L2A (bottom-of-atmosphere) using Sen2Cor.
measurements:
-   aliases:
    - B01
    dtype: uint16
    name: coastal
    nodata: 0
    units: '1'
-   aliases:
    - B02
    dtype: uint16
    name: blue
    nodata: 0
    units: '1'
-   aliases:
    - B03
    dtype: uint16
    name: green
    nodata: 0
    units: '1'
-   aliases:
    - B04
    dtype: uint16
    name: red
    nodata: 0
    units: '1'
-   aliases:
    - B05
    dtype: uint16
    name: rededge1
    nodata: 0
    units: '1'
-   aliases:
    - B06
    dtype: uint16
    name: rededge2
    nodata: 0
    units: '1'
-   aliases:
    - B07
    dtype: uint16
    name: rededge3
    nodata: 0
    units: '1'
-   aliases:
    - B08
    dtype: uint16
    name: nir
    nodata: 0
    units: '1'
-   aliases:
    - B8A
    dtype: uint16
    name: nir08
    nodata: 0
    units: '1'
-   aliases:
    - B09
    dtype: uint16
    name: nir09
    nodata: 0
    units: '1'
-   aliases:
    - B11
    dtype: uint16
    name: swir16
    nodata: 0
    units: '1'
-   aliases:
    - B12
    dtype: uint16
    name: swir22
    nodata: 0
    units: '1'
-   aliases:
    - SCL
    dtype: uint8
    flags_definition:
        sca:
            bits:
            - 0
            - 1
            - 2
            - 3
            - 4
            - 5
            - 6
            - 7
            description: Sen2Cor Scene Classification
            values:
                '1': saturated or defective
                '10': thin cirrus
                '11': snow or ice
                '2': dark area pixels
                '3': cloud shadows
                '4': vegetation
                '5': bare soils
                '6': water
                '7': unclassified
                '8': cloud medium probability
                '9': cloud high probability
    name: scl
    nodata: 0
    units: '1'
-   aliases:
    - aerosol_optical_thickness
    - AOT
    dtype: uint16
    name: aot
    nodata: 0
    units: '1'
-   aliases:
    - scene_average_water_vapour
    - WVP
    dtype: uint16
    name: wvp
    nodata: 0
    units: '1'
metadata:
    product:
        name: s2_c1_l2a
metadata_type: eo3
name: s2_c1_l2a

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions