Skip to main content

Sentinel-2-L2A Cloud Mask and valid pixel counts

  • April 26, 2024
  • 1 reply
  • 19 views

I am trying to follow this Tutorial but on a different country. I am currently having a problem with the cloud masks. I tried to visualize the different cloud masks of different patches at different dates, but I always end up with the same purple patch as a cloud mask (and not the actual mask) despite the presence of clouds in my data. This is an example:


and this is the valid pixel count plot:

This is the time interval : time_interval = ['2019-01-01', '2019-12-31']
This is the code I used to download the images:
class SentinelHubValidData:
    """
    Combine Sen2Cor's classification map with `IS_DATA` to define a `VALID_DATA_SH` mask
    The SentinelHub's cloud mask is asumed to be found in eopatch.mask['CLM']
    """
    def __call__(self, eopatch):        
        return np.logical_and(eopatch.mask['IS_DATA'].astype(np.bool), 
                              np.logical_not(eopatch.mask['CLM'].astype(np.bool)))
    
class CountValid(EOTask):   
    """
    The task counts number of valid observations in time-series and stores the results in the timeless mask.
    """
    def __init__(self, count_what, feature_name):
        self.what = count_what
        self.name = feature_name
        
    def execute(self, eopatch):
        eopatch.add_feature(FeatureType.MASK_TIMELESS, self.name, np.count_nonzero(eopatch.mask[self.what],axis=0))
        
        return eopatch

# Correspond to [coastal aerosol, B, G, R, vegetation red edge1,vegetation red edge2,vegetation red edge3, NIR, vegetation red edge4, water vapor, SWIR1, SWIR2] wavelengths BANDS-S2-L2A
band_names=['B01','B02','B03','B04','B05','B06','B07','B08','B8A','B09','B11','B12']  

# TASK FOR BAND DATA
# add a request for S2 bands (downloading the data from the configurator)
# s2cloudless masks and probabilities are requested via additional data
add_data = SentinelHubInputTask(
    bands_feature=(FeatureType.DATA, 'BANDS'),
    bands = band_names,
    resolution=10,
    maxcc=0.1,
    time_difference=datetime.timedelta(minutes=120),
    data_source=DataSource.SENTINEL2_L2A,
    additional_data=[(FeatureType.MASK, 'dataMask', 'IS_DATA'),
                     (FeatureType.MASK, 'CLM'),
                     (FeatureType.DATA, 'CLP')])

# TASK FOR VALID MASK
# validate pixels using SentinelHub's cloud detection mask and region of acquisition 
add_sh_valmask = AddValidDataMaskTask(SentinelHubValidData(), 
                                      'VALID_DATA' # name of output mask
                                     )


# TASK FOR COUNTING VALID PIXELS
# count number of valid observations per pixel using valid data mask 
count_val_sh = CountValid('VALID_DATA', # name of existing mask
                          'VALID_COUNT' # name of output scalar
                         )

Edit: I am guessing that my request to download the masks was not that of S2Cloudless, thus I tried the following:

cloud_classifier = get_s2_pixel_cloud_detector(average_over=2, dilation_size=1, all_bands=True)
add_clm = AddCloudMaskTask(cloud_classifier, 'BANDS', cm_size_y='80m', cm_size_x='80m', 
                           cmask_feature='CLM', # cloud mask name
                           cprobs_feature='CLP' # cloud prob. map name
                          )

However, I got this error:

What is the right service type to do it then?
I have also tried this:

band_names=['B01','B02','B03','B04','B05','B06','B07','B08','B8A','B09','B11','B12']  
add_data = SentinelHubInputTask(
    bands_feature=(FeatureType.DATA, 'BANDS'),
    bands = band_names,
    resolution=10,
    maxcc=0.1,
    time_difference=datetime.timedelta(minutes=120),
    data_source=DataSource.SENTINEL2_L2A,
    additional_data=[(FeatureType.MASK, 'dataMask', 'IS_DATA')],)
                    # (FeatureType.MASK, 'CLM'),                           # 0 (no clouds), 1 (clouds), 255 (no data)
                    # (FeatureType.DATA, 'CLP')])                          # 0–255 (divide by 255 to get to the [0-1] range)


# TASK FOR CLOUD INFO
# cloud detection is performed at 160m resolution 
# and the resulting cloud probability map and mask 
# are scaled to EOPatch's resolution

add_clm = AddMultiCloudMaskTask(data_feature='BANDS',
                                all_bands=True,
                                processing_resolution=160,
                                mono_features=('CLP', 'CLM'),
                                mask_feature=None,
                                average_over=16,
                                dilation_size=8)

and I got this error:

which to be honest I don’t get because my band array is of size (28,500,500,12) according to the logs.
Any kind of help would be highly appreciated.

1 reply

Hi, have you solved this issue by any chance? I’m having the same problem and tried just about everything I could think of, including using evalscript and SentinelHubEvalscriptTask instead of SentinelHubInputTask, all to no avail.


Reply