Tilebox indexes Sentinel-2 metadata and public asset locations in the open_data.aws_earth.sentinel2 dataset. In this guide, you query a cloud-free scene over Sandwich Harbour in Namibia, read a small window from its red, green, and blue Cloud Optimized GeoTIFFs (COGs), and combine the bands into an RGB image.
Prerequisites
Section titled “Prerequisites”- You have a Tilebox API key.
- You have Python 3.11 or newer.
uv add tilebox shapely numpy pillowSelect a cloud-free scene
Section titled “Select a cloud-free scene”Define a small area around Sandwich Harbour and query Sentinel-2 Level-2A scenes from June 17, 2024. Select the result with the least cloud cover.
from shapely import boxfrom tilebox.datasets import Client, field
# west, south, east, northarea = box(14.42, -23.43, 14.58, -23.25) # Sandwich Harbour, Namibia
collection = Client().dataset("open_data.aws_earth.sentinel2").collection("L2A")scenes = collection.query( temporal_extent=("2024-06-17", "2024-06-18"), spatial_extent=area, filter=field("cloud_cover") < 1,)
datapoint = scenes.sortby("cloud_cover").isel(time=0)print(datapoint.stac_id.item(), datapoint.cloud_cover.item())See Query open data metadata for broader temporal, spatial, and field-filtering patterns.
Resolve the RGB assets
Section titled “Resolve the RGB assets”Convert the datapoint into an asset collection:
from tilebox.datasets.assets import AssetCollection
assets = AssetCollection.from_datapoint(datapoint)Read and combine the bands
Section titled “Read and combine the bands”Open the three COGs and read only the window that covers the area of interest. The bands share the same pixel grid, so you can fetch them concurrently and stack them directly.
import asyncio
import numpy as npfrom tilebox.storage.aio import Client as StorageClientfrom tilebox.storage.geotiff import window_from_bounds
async def read_rgb(): storage = StorageClient()
async def read_band(key): asset = assets[key] geotiff = await storage.open_geotiff(asset) window = window_from_bounds(geotiff, area.bounds, crs="EPSG:4326") raster = await geotiff.read(window=window) pixels = raster.data[0].astype(np.float32) return pixels * asset.raster.scale + asset.raster.offset
red, green, blue = await asyncio.gather( read_band("red"), read_band("green"), read_band("blue"), ) return np.stack((red, green, blue), axis=-1)
rgb = asyncio.run(read_rgb())The asset metadata supplies the scale and offset that convert stored pixel values to surface reflectance.
Render the RGB image
Section titled “Render the RGB image”Apply a display stretch, gamma correction, and a small contrast clip, then save the array as a PNG:
from PIL import Image, ImageOps
display_rgb = np.power(np.clip(rgb / 0.3, 0, 1), 1 / 2.2)image = Image.fromarray((display_rgb * 255).astype(np.uint8))image = ImageOps.autocontrast(image, cutoff=0.5)image.save("sentinel2-sandwich-harbour.png")