Install
openclaw skills install @ruiduobao/image-compositeMulti-temporal image compositing from local GeoTIFF files. Supports median, mean, maxNDVI, and minRed compositing methods with cloud masking. Works on Landsat and Sentinel-2 band naming conventions.
openclaw skills install @ruiduobao/image-compositeCreate multi-temporal image composites from local GeoTIFF files. Supports cloud masking and multiple compositing methods. Works with Landsat and Sentinel-2 data.
pip install rasterio numpy tqdm
# Median composite of multiple scenes
python scripts\image-composite.py composite --inputs scene1.tif scene2.tif scene3.tif --output composite.tif
# Mean composite
python scripts\image-composite.py composite --inputs *.tif --method mean --output mean_composite.tif
# maxNDVI composite (best vegetation)
python scripts\image-composite.py composite --inputs *.tif --method maxNDVI --output ndvi_composite.tif
# Cloud masking
python scripts\image-composite.py cloud-mask --input scene.tif --threshold 0.3 --output masked.tif
pip install rasterio numpy tqdm
# Or: pip install -r scripts/requirements.txt
composite| Argument | Required | Default | Description |
|---|---|---|---|
--inputs | Yes | — | Input GeoTIFF files (2+) |
--output | Yes | — | Output composite path |
--method | No | median | Compositing method: median, mean, maxNDVI, minRed |
--cloud-mask | No | — | Optional cloud mask file |
cloud-mask| Argument | Required | Default | Description |
|---|---|---|---|
--input | Yes | — | Input GeoTIFF file |
--qa-band | No | — | QA band name or index |
--threshold | No | 0.3 | Cloud threshold (0-1) |
--output | Yes | — | Output masked file |
The maxNDVI method selects, for each pixel position, the scene that has the highest NDVI value at that location. This produces a composite with the greenest, healthiest vegetation — ideal for creating cloud-free, maximum vegetation composites. NDVI is calculated as (NIR - Red) / (NIR + Red).
| Method | Required Bands | Description |
|---|---|---|
median | Any | Median of all valid pixels |
mean | Any | Mean of all valid pixels |
maxNDVI | Red + NIR | Selects pixel with highest NDVI |
minRed | Red | Selects pixel with lowest red reflectance |
--target-crs and --target-resolution to overrideThe QA_PIXEL band uses bit flags for cloud/shadow detection:
| Bit | Name | Value | Description |
|---|---|---|---|
| 0 | Fill | 0/1 | Fill data |
| 1 | Dilated Cloud | 0/1 | Dilated cloud |
| 2 | Cirrus | 0/1 | Cirrus (Landsat 8/9) |
| 3 | Cloud | 0/1 | Cloud |
| 4 | Cloud Shadow | 0/1 | Cloud shadow |
| 5 | Snow | 0/1 | Snow |
| 6 | Clear | 0/1 | Clear |
| 7 | Water | 0/1 | Water |
0--qa-bit 3 to mask clouds, --qa-bit 3,4 for cloud + shadow--sequential--max-memory 4096 to limit RAM usage (MB)--dtype: uint8, uint16, float32--dtype float32 for methods requiring decimal precision (mean, median)| Band | Landsat 8/9 | Sentinel-2 |
|---|---|---|
| Blue | SR_B2 | B2 |
| Green | SR_B3 | B3 |
| Red | SR_B4 | B4 |
| NIR | SR_B5 | B8 |
| SWIR1 | SR_B6 | B11 |
| SWIR2 | SR_B7 | B12 |
| QA_PIXEL | QA_PIXEL | SCL (Scene Classification) |
--nodata VALUE to set custom nodatarasterio.plot.show(composite, cmap='terrain')matplotlibplt.imshow(ndvi, cmap='RdYlGn', vmin=-1, vmax=1)matplotlib subplots for before/afterrasterio.plot.show(out_file='preview.png')| Error | Cause | Solution |
|---|---|---|
ConnectionError | Network issue | Check internet, retry |
HTTP 429 | Rate limit | Wait 60s, retry |
ValueError | Invalid input | Check parameter format |
| Empty output | No data | Try different parameters |
ModuleNotFoundError | Missing dep | Run pip install |
MemoryError | Too many scenes | Use --sequential or --max-memory |
CRSError | CRS mismatch | Use --target-crs to unify |
| Band not found | Wrong naming | Check band mapping table above |
If you use this tool in your research, please cite the input data sources (e.g., USGS Landsat, ESA Sentinel-2) and acknowledge the compositing methodology:
@software{image_composite_2024,
author = {ruiduobao},
title = {Image Composite Tool},
year = {2024},
note = {Multi-temporal image compositing for Landsat/Sentinel-2}
}
For Landsat data: "Landsat data are provided by the U.S. Geological Survey and/or the National Aeronautics and Space Administration." For Sentinel-2 data: "Copernicus Sentinel data [2024] processed by ESA."
# Composite all scenes from a week
python scripts\image-composite.py composite --images S2A_20230101.tif S2A_20230105.tif S2A_20230110.tif --method maxNDVI --sensor sentinel2 --output composite_week1.tif
# .github/workflows/weekly-composite.yml
name: Weekly Image Composite
on:
schedule:
- cron: '0 12 * * 1' # Every Monday at 12:00
jobs:
composite:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.11'
- run: pip install numpy rasterio
- run: |
python scripts\image-composite.py composite \
--images data/scenes/*.tif \
--method maxNDVI --sensor sentinel2 \
--output data/composite_$(date +%Y%m%d).tif
import rasterio
import geopandas as gpd
from rasterio.features import geometry_mask
with rasterio.open('composite.tif') as src:
img = src.read(1)
profile = src.profile
# Compute zonal stats for polygons
gdf = gpd.read_file('aoi.gdf')
--max-memory to limit RAM usage for large scenes--sequential mode reads one band at a time (slower but memory-safe)--reference to control output grid从本地 GeoTIFF 文件创建多时相影像合成。支持云掩膜和多种合成方法。兼容 Landsat 和 Sentinel-2 数据。
pip install rasterio numpy tqdm
# 中位数合成
python scripts\image-composite.py composite --inputs scene1.tif scene2.tif scene3.tif --output composite.tif
# 平均值合成
python scripts\image-composite.py composite --inputs *.tif --method mean --output mean_composite.tif
# 最大 NDVI 合成(最佳植被)
python scripts\image-composite.py composite --inputs *.tif --method maxNDVI --output ndvi_composite.tif
# 云掩膜
python scripts\image-composite.py cloud-mask --input scene.tif --threshold 0.3 --output masked.tif
maxNDVI 方法在每个像素位置选择 NDVI 值最高 的场景。这样生成的合成影像具有最绿、最健康的植被——适合创建无云、最大植被覆盖的合成影像。NDVI 计算公式: (NIR - Red) / (NIR + Red)。
| 方法 | 所需波段 | 描述 |
|---|---|---|
median | 任意 | 所有有效像素的中位数 |
mean | 任意 | 所有有效像素的平均值 |
maxNDVI | 红 + 近红外 | 选择 NDVI 最高的像素 |
minRed | 红波段 | 选择红反射率最低的像素 |
--target-crs 和 --target-resolution 覆盖默认行为QA_PIXEL 波段使用位标志进行云/阴影检测:
| 位 | 名称 | 值 | 描述 |
|---|---|---|---|
| 0 | Fill | 0/1 | 填充数据 |
| 1 | Dilated Cloud | 0/1 | 膨胀云 |
| 2 | Cirrus | 0/1 | 卷云(Landsat 8/9) |
| 3 | Cloud | 0/1 | 云 |
| 4 | Cloud Shadow | 0/1 | 云阴影 |
| 5 | Snow | 0/1 | 雪 |
| 6 | Clear | 0/1 | 晴空 |
| 7 | Water | 0/1 | 水体 |
0--qa-bit 3 掩膜云,--qa-bit 3,4 掩膜云+阴影--sequential 顺序处理--max-memory 4096 限制内存使用(MB)--dtype 指定: uint8, uint16, float32--dtype float32| 波段 | Landsat 8/9 | Sentinel-2 |
|---|---|---|
| 蓝 | SR_B2 | B2 |
| 绿 | SR_B3 | B3 |
| 红 | SR_B4 | B4 |
| 近红外 | SR_B5 | B8 |
| 短波红外1 | SR_B6 | B11 |
| 短波红外2 | SR_B7 | B12 |
| QA_PIXEL | QA_PIXEL | SCL (场景分类) |
--nodata VALUE 设置自定义 nodatarasterio.plot.show(composite, cmap='terrain')matplotlib 堆叠 Red/Green/Blue 波段plt.imshow(ndvi, cmap='RdYlGn', vmin=-1, vmax=1)matplotlib subplots 显示前后对比rasterio.plot.show(out_file='preview.png')| 错误 | 原因 | 解决方案 |
|---|---|---|
ConnectionError | 网络问题 | 检查网络,重试 |
HTTP 429 | 速率限制 | 等待 60 秒后重试 |
ValueError | 无效输入 | 检查参数格式 |
| 空输出 | 无数据 | 尝试不同参数 |
ModuleNotFoundError | 缺少依赖 | 运行 pip install |
MemoryError | 场景过多 | 使用 --sequential 或 --max-memory |
CRSError | 坐标系不匹配 | 使用 --target-crs 统一 |
| 波段未找到 | 命名错误 | 查看上方波段映射表 |