I have created a scene collection in the Descartes Labs Platform using the Scenes search function (dl.scenes.search) for my area of interest and sensor of choice (Sentinel-2). I would like to iterate through the scenes in the collection and mask for clouds using the cloud-mask band before creating a composite with only clear pixels. How would you approach this task?
You can apply a cloud mask directly to a stack of pixel values before compositing the scenes together. There is a basic derived band computed on all products with red, green, and blue bands called
derived:visual_cloud_mask but for Sentinel-2:L1C there is also a separate "DLCloud" product that provides a variety of cloud mask types that are of better quality. To apply those, fetch a SceneCollection across the same AOI and datetime range you queried Sentinel-2:L1C and apply the mask with numpy.
First, your imports and the AOI. This is a rather cloudy region over the Sierra Nevada de Santa Marta in Colombia.
import descarteslabs as dl import numpy as np aoi = dl.scenes.DLTile.from_latlon(10.783, -73.669 ,60,256, 0) start_datetime = '2017-06-01' end_datetime = '2017-09-01'
Then, fetch your Sentinel RGB data using the SceneCollection.stack method.
sentinel_scenes, sentinel_ctx = dl.scenes.search( aoi.geometry, products=["sentinel-2:L1C"], start_datetime=start_datetime, end_datetime=end_datetime, limit=None ) sentinel_rgb_stack = sentinel_scenes.stack('red green blue', sentinel_ctx, processing_level='surface')
Do the same for the DLCloud masks. We'll use the
valid_cloudfree band in this example. Use the same geocontext returned from the Sentinel scene search to ensure we are working with arrays in the same spatial reference system and resolution.
dlcloud_scenes, dlcloud_ctx = dl.scenes.search( aoi.geometry, products=["sentinel-2:L1C:dlcloud:v1"], start_datetime=start_datetime, end_datetime=end_datetime, limit=None ) dlcloud_valid_cloudfree_stack = dlcloud_scenes.stack('valid_cloudfree', sentinel_ctx , data_type='Byte')
Apply the cloud masks to the RGB data. You'll need to repeat the mask for the 3 bands downloaded to use the Numpy masked array masked_where method
dlcloud_valid_cloudfree_stack = np.repeat(a=dlcloud_valid_cloudfree_stack, repeats=3, axis=1)
Mask out the pixel values where
valid_cloud_free is equal to 0.
cloudfree_rgb_stack = np.ma.masked_where(dlcloud_valid_cloudfree_stack==0, sentinel_rgb_stack)
Display the results to sanity check what you have done. First the unmasked, cloudy pixels using a simple median mosaic through time,
sentinel_rgb_mosaic = np.ma.median(sentinel_rgb_stack, axis=0) dl.scenes.display(sentinel_rgb_mosaic)
And finally with the mask applied.
cloudfree_mosaic = np.ma.median(cloudfree_rgb_stack, axis=0) dl.scenes.display(cloudfree_mosaic)
Here is a complete notebook to get you started.