Creating timelapse animations
This example illustrates how to use an EOWorkflow
to create a time-lapse. The process is done by first defining some area and the time interval of interest. Then the following workflow will be performed:
Tasks of the workflow:
download S2 images (RGB + CLM)
filter out images with cloud coverage larger than a given threshold (e.g. 0.05)
When the eopatches have been filtered, we create an animation with the help of external packages.
[1]:
import os
from datetime import timedelta
import imageio
import numpy as np
from IPython.display import Image
from sentinelhub import CRS, BBox, DataCollection
from eolearn.core import EOWorkflow, FeatureType, OutputTask, linearly_connect_tasks
from eolearn.features import SimpleFilterTask
from eolearn.io import SentinelHubInputTask
1. Define tasks
First we need to define the download and filter tasks which we need for obtaining the data and filtering it.
1.1 Download Task
The download task accepts a few parameters that you have to set, some of which area shown below. For more information regarding the parameters, check the task documentation page.
In addition to the RGB bands, we also add the cloud mask CLM
band, which provides information regarding the clouds. More info here.
[2]:
add_data_task = SentinelHubInputTask(
data_collection=DataCollection.SENTINEL2_L2A,
bands_feature=(FeatureType.DATA, "RGB"),
bands=["B04", "B03", "B02"],
time_difference=timedelta(hours=2),
resolution=10,
additional_data=[(FeatureType.MASK, "CLM")],
)
1.2 Filter Task
The SimpleFilterTask
has to be provided with some logic in order to filter the framers accordingly. This is why the MaxCCPredicate
function is created. It accepts the cloud image and checks the cloud coverage. If the value of cloud coverage is too high (w.r.t. the provided threshold), the frame is filtered out.
[3]:
class MaxCCPredicate:
def __init__(self, maxcc):
self.maxcc = maxcc
def __call__(self, img_cm):
w, h, _ = img_cm.shape
cc = np.sum(img_cm) / (w * h)
return cc <= self.maxcc
filter_task = SimpleFilterTask((FeatureType.MASK, "CLM"), MaxCCPredicate(maxcc=0.05))
2. Create and execute workflow
We will download the Sentinel-2 images for the period of the Istanbul airport construction.
[4]:
# define region and time interval of interest
roi_bbox = BBox(bbox=[28.726330, 41.248773, 28.759632, 41.274581], crs=CRS.WGS84)
time_interval = ("2017-06-01", "2019-01-01")
[5]:
# define workflow
nodes = linearly_connect_tasks(add_data_task, filter_task, OutputTask("eopatch"))
workflow = EOWorkflow(nodes)
# execute workflow
result = workflow.execute({nodes[0]: {"bbox": roi_bbox, "time_interval": time_interval}})
# extract eopatch
eopatch = result.outputs["eopatch"]
3. Create animation
[6]:
def make_gif(eopatch, output_path, duration):
"""
Generates a GIF animation from an EOPatch.
"""
with imageio.get_writer(output_path, mode="I", duration=duration) as writer:
for image in eopatch:
writer.append_data(np.array(image, dtype=np.uint8))
[7]:
OUTPUT_GIF_PATH = os.path.join(".", "outputs", "eopatch.gif")
make_gif(
eopatch=np.clip(eopatch.data["RGB"] * 2.5 * 255, 0, 255),
output_path=OUTPUT_GIF_PATH,
duration=4, # seconds
)
[8]:
Image(filename=OUTPUT_GIF_PATH, width=500)
[8]:
<IPython.core.display.Image object>