Each pixel value of the Sentinel-2 image tiles clipped by SentinelHub is 1000 less than the original Sentinel-2 pixel values

I obtained the Sentinel-2 images of interest from SentinelHub using the following code. However, I noticed that all the ROIs obtained had pixel values 1000 less than the original Sentinel-2 pixel values. Is the 1000 reduction an implicit setting of SentinelHub? If so, how can it be disabled? Thanks.

My environment is: Windows 10, sentinelhub==3.10.2, python==3.9.5.

def save_tiff_to_drive(index, resolution, OUTPUT_DIR):

    try:
        file_name = data_manifest[data_manifest['index'] == index]['imagery_sample_id'][index-1]
        dest_folder = os.path.join(OUTPUT_DIR, file_name)
        
        if os.path.isdir(dest_folder):
            print("Product already downloaded!")
            return "Product already downloaded!"

        
        if len(shape_coord_lists[index-1]) == 0:
            print("Instance does not have a shape extent")
            return "Instance does not have a shape extent"
        
        
        # retrieving datetime from manifest and converting it to the right format
        capture_datetime = data_manifest[data_manifest['index'] == index]['capture_datetime'][index-1]
        
        # capture_datetime = datetime.strptime(capture_datetime, '%d-%m-%Y %H:%M')
        capture_datetime = datetime.strptime(capture_datetime, '%Y-%m-%d %H:%M:%S')
        capture_date = capture_datetime.strftime("%Y-%m-%d")

        # in case you want to broaden date range to include 1 day prior and 1 day after capture day --> possible edge cases?
        #capture_datetime_prior = capture_datetime.replace(day=capture_datetime.day - 1)
        #capture_datetime_post = capture_datetime.replace(day=capture_datetime.day + 1)
        #capture_date_prior = capture_datetime_prior.strftime("%Y-%m-%d")
        #capture_date_post = capture_datetime_post.strftime("%Y-%m-%d")

        print("shape_coord_lists_1 = ", shape_coord_lists[index-1])
        shape_coord_list = create_extended_bbox(shape_coord_lists[index-1], 10)
        print("shape_coord_lists_2 = ", shape_coord_list)
        capture_bbox = BBox(bbox=shape_coord_lists[index-1], crs=CRS.WGS84)
        capture_size = bbox_to_dimensions(capture_bbox, resolution=resolution)
        

        print(f"Image shape at {resolution} m resolution: {capture_size} pixels")
        print("Box: ", capture_bbox)
        
        # API query
        evalscript_all_bands = """
        //VERSION=3
        function setup() {
            return {
                input: [{
                    bands: ["B01","B02","B03","B04","B05","B06","B07","B08","B8A","B09","B10","B11","B12"],
                    units: "DN"
                }],
                output: {
                    bands: 13,
                    sampleType: "INT16"
                }
            };
        }

        function evaluatePixel(sample) {
            return [sample.B01,
                    sample.B02,
                    sample.B03,
                    sample.B04,
                    sample.B05,
                    sample.B06,
                    sample.B07,
                    sample.B08,
                    sample.B8A,
                    sample.B09,
                    sample.B10,
                    sample.B11,
                    sample.B12];
            }
        """

        # requesting from Process API
        request_all_bands = SentinelHubRequest(
            data_folder=dest_folder,
            evalscript=evalscript_all_bands,
            input_data=[SentinelHubRequest.input_data(data_collection=DataCollection.SENTINEL2_L1C,
                                                        time_interval=(capture_date, capture_date),
                                                        mosaicking_order=MosaickingOrder.LEAST_CC,
                                                        )
                        ],
            responses=[SentinelHubRequest.output_response("default", MimeType.TIFF)],
            bbox=capture_bbox,
            size=capture_size,
            config=config,
            )
        
        print("Saving all bands to device...")
        try:
            request_all_bands.save_data()
        except Exception as e:
            print(f"An error occurred in request_all_bands: {e}")
            return None
        
        tiff_path = ''
        for dirpath, _, files in os.walk(dest_folder, topdown=False):
            for file in files:
                if os.path.abspath(os.path.join(dirpath, file))[-5:] == '.tiff':
                    tiff_path = os.path.join(dirpath, file)
        if tiff_path == '':
                    raise TypeError("No .tiff file detected")
                
        with rasterio.open(tiff_path) as src:
            out_images = src.read()
            #out_image_masked, out_transform = rasterio.mask.mask(src, data.geometry, crop=True)
            out_meta = src.meta
        
        print()
        print("done!")
        print()
        
        size = os.path.getsize(tiff_path)
        print(f'The .tiff size is: ', convert_bytes(size))
        
    except Exception as e:
        print(f"An error occurred: {e}")
        return None
    
    return out_meta, out_images

Hi Cris,

thanks for the question; you’ve not been clear on whether you are comparing DN values or Reflectance values. I suggest reading through this specific section of the documentation to check that you are outputting the values that you wish to.

There are also some examples that you will find useful here.

Thank you for your prompt response and suggestions. I checked the links you provided, but I couldn’t solve the problem.

I am comparing the DN values, specifically the difference between the image patches cropped from SentinelHub and the original S2A_MSIL1C image pixel values. As shown in the figure below, there is always a difference of 1000 between them.

Thanks

Is this an issue, or is my understanding incorrect? Thanks

Hi Cris, this might be a harmonization issue. You can read more about this in our docs here. Are you already utilising this parameter?

For more context to others, this issue was also discussed on Github.