Processing
cdse.processing
Post-download processing utilities for CDSE products.
This module provides functions for cropping, reprojecting, extracting bands, and previewing downloaded Sentinel products. These operations help users work with data centered on their area of interest rather than full tiles.
Key features: - Extract specific bands from SAFE/ZIP products - Crop to bounding box (city, AOI) - Stack bands into multi-band GeoTIFF - Generate RGB preview images (PNG/JPEG) - Display interactive previews in Jupyter notebooks - Calculate vegetation indices (NDVI)
Requires: rasterio (install with: pip install cdse-client[processing])
crop_to_bbox(input_path: Union[str, Path], bbox: list[float], output_path: Optional[Union[str, Path]] = None, bands: Optional[list[str]] = None) -> Path
Crop a raster file to a bounding box.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
input_path
|
Union[str, Path]
|
Path to input raster file (GeoTIFF or JP2) |
required |
bbox
|
list[float]
|
Bounding box [min_lon, min_lat, max_lon, max_lat] in WGS84 |
required |
output_path
|
Optional[Union[str, Path]]
|
Output path (default: input_cropped.tif) |
None
|
bands
|
Optional[list[str]]
|
List of band indices to extract (1-based), None for all |
None
|
Returns:
| Type | Description |
|---|---|
Path
|
Path to cropped output file |
Raises:
| Type | Description |
|---|---|
ValidationError
|
If input is invalid |
ImportError
|
If rasterio is not installed |
Example
cropped = crop_to_bbox( ... "S2A_MSIL2A.../B04.jp2", ... bbox=[9.15, 45.45, 9.20, 45.50], # Milan center ... )
extract_bands_from_safe(safe_path: Union[str, Path], bands: list[str], output_dir: Optional[Union[str, Path]] = None, resolution: int = 10) -> dict[str, Path]
Extract specific bands from a Sentinel-2 SAFE folder or ZIP.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
safe_path
|
Union[str, Path]
|
Path to .SAFE folder or .zip file |
required |
bands
|
list[str]
|
List of band names (e.g., ["B02", "B03", "B04", "B08"]) |
required |
output_dir
|
Optional[Union[str, Path]]
|
Output directory (default: same as input) |
None
|
resolution
|
int
|
Target resolution in meters (10, 20, or 60) |
10
|
Returns:
| Type | Description |
|---|---|
dict[str, Path]
|
Dictionary mapping band names to extracted file paths |
Example
bands = extract_bands_from_safe( ... "S2A_MSIL2A_20240115.zip", ... bands=["B04", "B03", "B02"], # RGB ... resolution=10 ... )
stack_bands(band_paths: dict[str, Path], output_path: Union[str, Path], band_order: Optional[list[str]] = None) -> Path
Stack multiple bands into a single multi-band GeoTIFF.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
band_paths
|
dict[str, Path]
|
Dictionary mapping band names to file paths |
required |
output_path
|
Union[str, Path]
|
Output GeoTIFF path |
required |
band_order
|
Optional[list[str]]
|
Order of bands in output (default: sorted keys) |
None
|
Returns:
| Type | Description |
|---|---|
Path
|
Path to output stacked GeoTIFF |
Example
stacked = stack_bands( ... {"B04": "red.jp2", "B03": "green.jp2", "B02": "blue.jp2"}, ... "rgb_stack.tif", ... band_order=["B04", "B03", "B02"] ... )
crop_and_stack(safe_path: Union[str, Path], bbox: list[float], bands: Optional[list[str]] = None, output_path: Optional[Union[str, Path]] = None, resolution: int = 10) -> Path
Extract bands, crop to bbox, and stack into single GeoTIFF.
This is a convenience function combining extract, crop, and stack operations.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
safe_path
|
Union[str, Path]
|
Path to .SAFE folder or .zip file |
required |
bbox
|
list[float]
|
Bounding box [min_lon, min_lat, max_lon, max_lat] |
required |
bands
|
Optional[list[str]]
|
Band names (default: true color B04, B03, B02) |
None
|
output_path
|
Optional[Union[str, Path]]
|
Output path (default: auto-generated) |
None
|
resolution
|
int
|
Target resolution in meters |
10
|
Returns:
| Type | Description |
|---|---|
Path
|
Path to output cropped and stacked GeoTIFF |
Example
result = crop_and_stack( ... "S2A_MSIL2A_20240115.zip", ... bbox=[9.15, 45.45, 9.25, 45.55], # Milan ... bands=["B04", "B03", "B02", "B08"], # RGB + NIR ... )
calculate_ndvi(nir_path: Union[str, Path], red_path: Union[str, Path], output_path: Union[str, Path]) -> Path
Calculate NDVI (Normalized Difference Vegetation Index).
NDVI = (NIR - Red) / (NIR + Red)
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
nir_path
|
Union[str, Path]
|
Path to NIR band (B08 for Sentinel-2) |
required |
red_path
|
Union[str, Path]
|
Path to Red band (B04 for Sentinel-2) |
required |
output_path
|
Union[str, Path]
|
Output GeoTIFF path |
required |
Returns:
| Type | Description |
|---|---|
Path
|
Path to NDVI output file (values -1 to 1) |
get_bounds_from_raster(raster_path: Union[str, Path]) -> tuple[list[float], str]
Get bounding box and CRS from a raster file.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
raster_path
|
Union[str, Path]
|
Path to raster file |
required |
Returns:
| Type | Description |
|---|---|
tuple[list[float], str]
|
Tuple of (bbox in WGS84 [min_lon, min_lat, max_lon, max_lat], original CRS string) |
reproject(input_path: Union[str, Path], output_path: Union[str, Path], target_crs: str = 'EPSG:4326', resolution: Optional[float] = None) -> Path
Reproject a raster to a different CRS.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
input_path
|
Union[str, Path]
|
Input raster path |
required |
output_path
|
Union[str, Path]
|
Output raster path |
required |
target_crs
|
str
|
Target CRS (default: WGS84) |
'EPSG:4326'
|
resolution
|
Optional[float]
|
Target resolution (default: preserve original) |
None
|
Returns:
| Type | Description |
|---|---|
Path
|
Path to reprojected raster |
create_rgb_preview(input_path: Union[str, Path], output_path: Optional[Union[str, Path]] = None, bands: tuple[int, int, int] = (1, 2, 3), percentile_stretch: tuple[float, float] = (2, 98), size: Optional[tuple[int, int]] = None, format: str = 'PNG') -> Path
Create an RGB preview image from a multi-band raster.
Generates a color-balanced preview image suitable for visual inspection. Applies percentile stretching to enhance contrast.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
input_path
|
Union[str, Path]
|
Path to multi-band raster (GeoTIFF) |
required |
output_path
|
Optional[Union[str, Path]]
|
Output image path (default: input_preview.png) |
None
|
bands
|
tuple[int, int, int]
|
Tuple of band indices for R, G, B (1-based, default: 1, 2, 3) |
(1, 2, 3)
|
percentile_stretch
|
tuple[float, float]
|
Low and high percentiles for contrast stretch |
(2, 98)
|
size
|
Optional[tuple[int, int]]
|
Output size (width, height) or None for original size |
None
|
format
|
str
|
Output format ("PNG" or "JPEG") |
'PNG'
|
Returns:
| Type | Description |
|---|---|
Path
|
Path to preview image |
Example
preview = create_rgb_preview( ... "milan_rgb.tif", ... bands=(1, 2, 3), # R, G, B order ... percentile_stretch=(2, 98) ... )
preview_product(safe_path: Union[str, Path], bbox: Optional[list[float]] = None, bands: Optional[list[str]] = None, resolution: int = 10, output_path: Optional[Union[str, Path]] = None, display: bool = True, size: tuple[int, int] = (800, 800)) -> dict[str, Any]
Generate and optionally display a preview of a Sentinel product.
This is a convenience function that extracts RGB bands, optionally crops to a bounding box, and generates a preview image. When run in Jupyter, it can display the preview inline.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
safe_path
|
Union[str, Path]
|
Path to .SAFE folder or .zip file |
required |
bbox
|
Optional[list[float]]
|
Optional bounding box to crop [min_lon, min_lat, max_lon, max_lat] |
None
|
bands
|
Optional[list[str]]
|
Band names for RGB (default: ["B04", "B03", "B02"] for true color) |
None
|
resolution
|
int
|
Resolution in meters (10, 20, or 60) |
10
|
output_path
|
Optional[Union[str, Path]]
|
Where to save the preview (default: auto-generated) |
None
|
display
|
bool
|
Whether to display in Jupyter (default: True) |
True
|
size
|
tuple[int, int]
|
Preview size (width, height) |
(800, 800)
|
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
Dictionary with: |
dict[str, Any]
|
|
dict[str, Any]
|
|
dict[str, Any]
|
|
dict[str, Any]
|
|
dict[str, Any]
|
|
Example
result = preview_product( ... "S2A_MSIL2A_20240115.zip", ... bbox=[9.15, 45.45, 9.25, 45.55], # Milan ... display=True ... ) print(f"Preview saved to: {result['preview_path']}")
quick_preview(tiff_path: Union[str, Path], bands: tuple[int, int, int] = (1, 2, 3), figsize: tuple[int, int] = (10, 10), title: Optional[str] = None) -> Any
Quick preview using matplotlib (for Jupyter notebooks).
Simpler alternative to preview_product when you already have a processed GeoTIFF and want a quick visualization.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tiff_path
|
Union[str, Path]
|
Path to GeoTIFF file |
required |
bands
|
tuple[int, int, int]
|
Band indices for RGB (1-based) |
(1, 2, 3)
|
figsize
|
tuple[int, int]
|
Figure size in inches |
(10, 10)
|
title
|
Optional[str]
|
Optional title for the plot |
None
|
Returns:
| Type | Description |
|---|---|
Any
|
matplotlib figure object |
Example
fig = quick_preview("milan_rgb.tif", title="Milan - Sentinel-2")
create_thumbnail(input_path: Union[str, Path], output_path: Optional[Union[str, Path]] = None, size: tuple[int, int] = (256, 256), bands: tuple[int, int, int] = (1, 2, 3)) -> Path
Create a small thumbnail from a raster.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
input_path
|
Union[str, Path]
|
Path to input raster |
required |
output_path
|
Optional[Union[str, Path]]
|
Output thumbnail path |
None
|
size
|
tuple[int, int]
|
Thumbnail size (width, height) |
(256, 256)
|
bands
|
tuple[int, int, int]
|
Band indices for RGB |
(1, 2, 3)
|
Returns:
| Type | Description |
|---|---|
Path
|
Path to thumbnail |
Example
thumb = create_thumbnail("milan_rgb.tif", size=(128, 128))
compare_previews(paths: list[Union[str, Path]], titles: Optional[list[str]] = None, figsize: tuple[int, int] = (15, 5)) -> Any
Display multiple previews side by side for comparison.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
paths
|
list[Union[str, Path]]
|
List of GeoTIFF paths to compare |
required |
titles
|
Optional[list[str]]
|
Optional titles for each image |
None
|
figsize
|
tuple[int, int]
|
Figure size |
(15, 5)
|
Returns:
| Type | Description |
|---|---|
Any
|
matplotlib figure |
Example
compare_previews( ... ["before.tif", "after.tif"], ... titles=["Before", "After"] ... )