WMSRequest accessing multiple layer in one request

Hi,

I am trying to request both true color image as well as firemask data for a specific time period for a specific bounding box. I tried with CustomUrlParam.EVALSCRIPT and it gives an error when requesting for get_data.

Program works fine, when accessing using the single layer configured at sentinel-hub.

Objective is to get the timelapse images for a specific bounding box, but with various layers in one call to minimize the API calls.

If possible, I also would like to to get some metadata about the images (e.g. date taken, cc etc.) and access bot S2L1C and S2L2A in one API request.

What can I do to get the images downloaded for this period, in a most effective way ? Should I be using different API?

with HTTPError:
400 Client Error: Bad Request for url: https://services.sentinel-hub.com/ogc/wms/27c25b84-xxx?SERVICE=wms&WARNINGS=False&MAXCC=100.0&Quality=60&ShowLogo=False&EvalScript=CiAgICAvL1ZFUlNJT049MwogICAgZnVuY3Rpb24gc2V0d&BBOX=41.8682%2C-123.90931%2C41.8882%2C-123.88931&FORMAT=image%2Fpng&CRS=EPSG%3A4326&TIME=2023-08-25T17%3A13%3A01Z%2F2023-08-25T21%3A13%3A01Z&WIDTH=512&HEIGHT=512&LAYERS=1_TRUECOLOR&REQUEST=GetMap&VERSION=1.3.0

Server response: “Output default requested but missing from function setup()”

This is my WMSRequest

request = WmsRequest(
    layer=layer,
    bbox=bbox,
    data_collection=data_collection,
    time=time_interval,
    width=img_size[0],
    height=img_size[1],
    image_format=mime_type,
    config=config,
    custom_url_params={CustomUrlParam.QUALITY: 60,
                       CustomUrlParam.SHOWLOGO: False,
                       CustomUrlParam.EVALSCRIPT: evalscript
                    },
    time_difference=time_difference
)

I tried even with one layer, as below. As soon as I add non-default “id” to the layer, it fails.

//VERSION=3
function setup() {
    return {
        input: ["B02", "B03", "B04", "dataMask"],
        output: { id: "truecolor", bands: 4 }
    };
}

function evaluatePixel(sample) {
    return {
    "truecolor": [sample.B04, sample.B03, sample.B02, sample.dataMask],
    }
}

Hi @princeofpersia ,

I believe that Sentinel Hub WMS requests always look for the default output as the multi-output is not compliant to the WMS standard. If you’d like to have multi-output and metadata together in one API call, I would suggest using the Processing API, which is a RESTful API and is more powerful.

Thank you very much for your prompt response.

Could you please point me to the Processing REST API document or examples?

I tried with SentinelhubRequest, but for some reason it seems to fetch more images than I need (I may need to spend some time on debugging).

Wms gives the correct data, but not able to get multiple layers. I could try with evalscripturl, but not very positive this would solve the issue.

Hi @princeofpersia ,

We have some basic examples in the sentinelhub-py documentation. We also have the API Reference where you can find the request body schema.

Thank you for your response.

I was using SentinelHubRequest previously. Most of the examples on the website was pulling one image at a time. The one example ( Example 8 : Multiple timestamps data) where it is pulling multiple images, also seem to send multiple requests, which I want to avoid.

WMSRequest, seems to extract multiple images in one call, however I could only get it working for one layer. My objective is to download all (quality) images from the same location for a specific time interval for two or more layers.

With mosaikingorder set to TILE, I was able to pull multiple images using the following evalscript. But, it seems, most of the scenes are blank :frowning:

    //VERSION=3
    function setup() {
        return {
            input: [{
                bands: ["B02", "B03", "B04", "B12", "dataMask"]
            }],
            output: [
                {
                    id: "truecolor",
                    bands: 4
                },
                {
                    id: "firemask",
                    bands: 3
                }
            ],
            mosaicking: Mosaicking.TILE  //seems to be getting blank images
        };
    }

    function evaluatePixel(sample) {
        ...
        // Return the RGB values for both layers
        return {
            truecolor: [2.5 * sample.B04, 2.5 * sample.B03, 2.5 * sample.B02, sample.dataMask],
            firemask: [firemask_R, sample.B03, sample.B02],
        };
    }

  function updateOutputMetadata(scenes, inputMetadata, outputMetadata) {
       ....
        outputMetadata.userData = {
            scenes:  scenes.tiles
        };
    } 
    """

Hi @princeofpersia ,

Are you trying to get a time series of true color and fire mask images at one call and you’d like to have each acquisition as a separate output TIFF? For example, there’s data on d1 and d2 and you need true_color_d1.tiff, fire_mask_d1.tfff, true_color_d2.tiff, and fire_mask_d2.tiff?

If this is the case the request will be a bit complex, we have an example notebook showing how to generate 1 output TIFF per acquisition in a specified AOI and time range. However, you’ll need to modify the script so you can get true color and fire mask time series at the same time.

Note that WmsRequest does allow you to extract a time series when you call get_data(). However, it actually gets a list available acquisitions and makes a request for each. It is also done by multiple api calls.

Yes, thats exactly what I am trying to do. .tiff or .png or any other format would do.

As mentioned, when using WMS, I am able to get timeseries data for one layer (say, truecolor). Similarly, with SentinelHubRequest, I am able to get multiple layers, but not timeseries data.

As far as WMS, I did not realize it was making multiple calls. Thanks for educating me on that.

Now it’s clear to me. I’m sure the example notebook linked in my previous response should help your development.

I would suggest starting from having one layer first, i.e., trying to get true_color_d1, true_color_d2.tiff, etc. This part should be relatively straight as the example basically does the same thing, and all you need to do is adding B02 to the script.

Next, you could try to add another layer (fire mask) to the script. This should be possible if the output_list (cell 8), return_list (cell 9), and response_list (cell 12) are built correctly.

I hope this would be helpful.

Thank you!!!

I was able to change the script to output both layers now.

The one challenge is to get some of the metadata information (such as cloud cover, tile id etc.).

Previously, I was using the following updateOutputMetadata to output those details. Since I am not able to find a way to get it working with the new evalscript, I am joing SentinelHubCatalog.catalog.search with the image details from the SentinelHubRequest response to tie them together. I am not sure how accurate or correct this approach is :frowning:

  function updateOutputMetadata(scenes, inputMetadata, outputMetadata) {
        if (scenes.orbits && scenes.orbits.length > 0 && scenes.orbits[0].dateFrom) {
            date = scenes.orbits[0].dateFrom;
        } else if (scenes.tiles && scenes.tiles.length > 0 && scenes.tiles[0].date) {
            date = scenes.tiles[0].date;
        }
        outputMetadata.userData = {
            scenes:  scenes.tiles
        };
    }

Hi @princeofpersia ,

The script is using mosaicking “ORBIT”, so the scenes object does not have the tiles property. You should use scenes.orbits instead. scenes.orbits is an array of objects which always has the same length as samples. To obtain information of each tile used for mosaicking, you can, for example, access tiles property of the first orbit like this: scenes.orbits[0].tiles (see documentation).

The Evalscript can be a basic one as shown below and you just need to remember to add a userdata output in your SentinelHubRequest (cell 12):

function updateOutputMetadata(scenes, inputMetadata, outputMetadata) {
  outputMetadata.userData = {
      scenes:  scenes.orbits
  };
}

Thank you.

I will try your suggestion.

I initially had mosaiking set to Tile. And hence scenes was referring to tile. I will fix those and fix the other issue you highlighted, and will try.

The metadata issue was due to the incorect responses that was passed to the sentinelHubRequest. Now, I see metadata is getting populated properly

1 Like