Sentinel-2 images | SentinelHub API vs AWS vs Copernicus CDSE

Hi SentinelHub Users,

I have 3 Sentinel-2 L2A images from distinct sources: SentinelHub API, AWS and Copernicus CDSE.
The images from AWS and CDSE shows exactly the same radiometric values and the pixels are in the exact same position (no image distortions or smoothness), same pixel size (10.0m).
The image from SH API has little differences (smoothness appearance, different pixel size (10.002m), pixel values a little off the CDSE reference, and most of all shows some distortions, probably from CRS conversions or other hidden resampling steps.
Discarding radiometric offsets or re-scales, there is any way to get the exact image from SH-API, as we get from AWS/CDSE?

Files date: 2023-05-09

i’m using the following code:

# Download
input_task_L2A = SentinelHubInputTask(
                name="s2l2a", service_url=""
        bands_feature=(FeatureType.DATA, "Sentinel2_L2A"),
        additional_data=[(FeatureType.MASK, 'SCL')],

# Validate pixels using SentinelHub's cloud detection mask and region of acquisition
add_sh_validmask = SentinelHubValidData('IS_VALID')

# Keep timestamps with > 95% valid coverage
valid_data_predicate = ValidDataFractionPredicate(1-maxcc_roi)
filter_task = SimpleFilterTask((FeatureType.MASK, 'IS_VALID'), valid_data_predicate)

# SAVE tifs
save_tiffs_l2a = SaveToTiffs_L2A()

workflow_nodes = linearly_connect_tasks(input_task_L2A, add_sh_validmask, filter_task, save_tiffs_l2a)
workflow = EOWorkflow(workflow_nodes)

result = workflow.execute(
        workflow_nodes[0]: {"bbox": bbox, "time_interval": time_interval}, # "geometry": geometry},
        workflow_nodes[-1]: {"folder": sentinel2_path}
class SaveToTiffs_L2A(EOTask):
    """ Threshold mean NDVI mask """
    def execute(self, eopatch, folder):
        for i, timestamp in enumerate(eopatch["timestamp"]):
            task = ExportToTiffTask((FeatureType.DATA, 'Sentinel2_L2A'), folder=folder, date_indices=[i], crs=32629, compress='None')         
            # task = ExportToTiffTask((FeatureType.DATA, 'Sentinel2_L2A'), folder=folder, date_indices=[i], compress='None')        
            task.execute(eopatch, filename=f'Sentinel2_L2A_{timestamp.strftime("%Y-%m-%d")}')
            task = ExportToTiffTask((FeatureType.MASK, 'SCL'), folder=folder, date_indices=[i], crs=32629, compress='None')
            #task = ExportToTiffTask((FeatureType.MASK, 'SCL'), folder=folder, date_indices=[i], compress='None')         
            task.execute(eopatch, filename=f'SCL{timestamp.strftime("%Y-%m-%d")}')

Thanks for any insights on this question.

Hi Jose,

I think you are asking how to retrieve Sentinel-2 data from Sentinel Hub on the same raster grid as the original images? If so, I recommend reading through this previous thread: Retrieving the sentinel L1C 20m grid - #5 by jacob

If you need some further information, then do let us know and we will try and help clarify your questions.

Hi William, thanks for your reply.

That’s not my point.
I’m talking about pixel values, if you please open the images in the link it would be self-explanatory.
The AWS and CDSE images have the exactly DN for the same pixel, while de SentinelHub one no (discarding the 1000 DN offset). Besides having evident distortions.

My question is if it is possible to download Sentinel-2 data using SH-API, with the exact DN values as the CDSE and AWS ones.
AS far as I understand, the SH does some resampling along the process and that’s what causing the differences.

Yes exactly, if your AOI aligns with the grid then you should have the same values as the original sources of the data. This is what is explained in the thread that I linked you to. However, if your AOI is not aligned with the grid then you will not have the same values.