I am trying to follow this Tutorial but in a different country. I am currently having a problem with cloud masks. I tried to visualize the different cloud masks of different patches at different dates. Sometimes the masks over-estimate the cloud coverage like the following screenshot, but in this case, I think it classified clouds and cloud shadow as clouds (not sure though):
But when it comes to small clouds they go undetected, which will most likely jeopardize later processing steps (crop type classification). Here is an example of that:
These cloud masks are generated using s2cloudless (a machine learning algorithm trained on S2-L1C images). 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 and CLOUD MASK and CLOUD PROBABILITY # 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 )
I found out that fmask is also used for cloud masking but I couldn't download the python package in google colab. So I want to know if there is any other way, using python, to mask those undetected small clouds.