Acces la date COG¶
Produsele sunt stocate ca Cloud Optimized GeoTIFF în object storage.
Asta înseamnă că se poate citi doar porțiunea necesară — o previzualizare
la rezoluție redusă sau o fereastră geografică — prin cereri HTTP Range,
fără a descărca produsul întreg (sute de MB).
Folosim pystac-client pentru a găsi produsul și rioxarray/rasterio
pentru citire.
from pystac_client import Client
catalog = Client.open("https://stac.eocube.ro")
# Nota: extensia `query` nu este disponibilă pe acest catalog (pgstac rulează
# cu cql2), așa că filtrăm norii pe client -- luăm ultimele produse și alegem.
candidates = catalog.search(
collections=["sentinel-2-l2a"],
intersects={"type": "Point", "coordinates": [21.23, 45.75]},
sortby=[{"field": "properties.datetime", "direction": "desc"}],
max_items=20,
).item_collection()
item = min(candidates, key=lambda i: i.properties.get("eo:cloud_cover", 100))
print(item.id)
print(f"data: {item.datetime:%Y-%m-%d} nori: {item.properties['eo:cloud_cover']:.1f}%")
S2A_MSIL2A_20260629T094121_N9999_R036_T34TER.SAFE data: 2026-06-29 nori: 0.0%
De la s3:// la un URL citibil¶
Asset-urile sunt publicate cu href-uri s3://. Pentru colecțiile deschise,
obiectele se pot citi anonim prin endpoint-ul HTTPS al stocării; pentru
date private folosiți credențiale STS (eocube auth login, apoi
eocube.common.auth.get_storage_credentials_using_access_token).
STORAGE = "https://storage.svc.uvt-01.eocube.ro"
def to_https(href: str) -> str:
"""s3://bucket/key -> https://<endpoint>/bucket/key"""
return href.replace("s3://", f"{STORAGE}/", 1)
visual = to_https(item.assets["visual"].href)
print(visual.replace(STORAGE, "…"))
…/sentinel-2-l2a/Sentinel-2/MSI/L2A/2026/06/29/S2A_MSIL2A_20260629T094121_N9999_R036_T34TER.SAFE/GRANULE/L2A_T34TER_A057548_20260629T094441/IMG_DATA/R10m/T34TER_20260629T094121_VISUAL_10m.tif
Citire parțială: doar o previzualizare¶
overview_level folosește piramidele interne ale COG-ului: se transferă
câțiva megaocteți în loc de tot fișierul.
import rioxarray
da = rioxarray.open_rasterio(visual, overview_level=2, masked=True)
print(da.rio.crs, "| formă:", da.shape, "| rezoluție:", [round(r) for r in da.rio.resolution()])
da
EPSG:32634 | formă: (3, 1372, 1372) | rezoluție: [80, -80]
<xarray.DataArray (band: 3, y: 1372, x: 1372)> Size: 23MB
[5647152 values with dtype=float32]
Coordinates:
* band (band) int64 24B 1 2 3
* y (y) float64 11kB 5.1e+06 5.1e+06 5.1e+06 ... 4.99e+06 4.99e+06
* x (x) float64 11kB 5e+05 5.001e+05 ... 6.097e+05 6.097e+05
spatial_ref int64 8B 0
Attributes:
TIFFTAG_IMAGEDESCRIPTION: Enhanced true-colour visual (relief-reshaded, ...
TIFFTAG_SOFTWARE: Sen2Cor 2.12.03; GDAL 3.6.2; sen2cor-service 0...
TIFFTAG_ARTIST: West University of Timisoara on behalf of the ...
TIFFTAG_COPYRIGHT: Copernicus Sentinel data 2026 (c) ESA. Contain...
AREA_OR_POINT: Area
scale_factor: 1.0
add_offset: 0.0import matplotlib.pyplot as plt
rgb = da.transpose("y", "x", "band").values / 255.0
fig, ax = plt.subplots(figsize=(7, 7))
ax.imshow(rgb)
ax.set_axis_off()
ax.set_title(f"{item.id[:38]}\ncompozit true-color (overview)", fontsize=9)
plt.tight_layout(); plt.show()
Un indice spectral, tot din citiri parțiale¶
NDVI din benzile roșu (B04) și infraroșu apropiat (B08), la 10 m, citite la nivel de overview.
import numpy as np
red = rioxarray.open_rasterio(to_https(item.assets["B04_10m"].href),
overview_level=2, masked=True).squeeze()
nir = rioxarray.open_rasterio(to_https(item.assets["B08_10m"].href),
overview_level=2, masked=True).squeeze()
ndvi = (nir - red) / (nir + red)
fig, ax = plt.subplots(figsize=(7, 6))
im = ndvi.plot.imshow(ax=ax, cmap="RdYlGn", vmin=-0.2, vmax=0.9,
add_colorbar=True)
ax.set_axis_off(); ax.set_title("NDVI", fontsize=10)
plt.tight_layout(); plt.show()