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:
and this is the valid pixel count plot:
This is the time interval :
time_interval = ['2019-01-01', '2019-12-31']
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.