NOVA Invasives
利用 Sentinel-2 卫星的物候信号差异,在 Google Earth Engine 上识别葛藤、芦苇等入侵物种的分布区域。
研究区域
5 个监测点位
点击地图上的圆点查看每个地点的入侵物种、GEE 坐标代码和检测特征。绿色虚线框是整个研究区域(北弗吉尼亚 bounding box)。
检测原理
为什么卫星能看出入侵植物?
关键在于物候差异:入侵植物和本土植物的发芽 / 落叶时间不同,这个时间差在卫星时间序列里清晰可见。
NDVI 是什么
NDVI = (NIR − RED) / (NIR + RED)
植物叶子吸收红光做光合作用,同时强烈反射近红外光。NDVI 把这个比值归一化到 [-1, +1],值越高代表植被越茂密。Sentinel-2 用 B8(近红外)和 B4(红光)来计算。
物候检测窗口
早春 (3–4月) · 晚秋 (10–11月)
入侵灌木比本土落叶树早 2–3 周发芽,晚 2–3 周落叶。在这两个窗口期,入侵植物的 NDVI 显著高于周围本土植被,形成可检测的信号。

模拟分析
物候曲线对比
用模拟数据验证核心假设:橙色阴影区(早春)和棕色阴影区(晚秋)是入侵植物和本土植物 NDVI 差异最大的检测窗口。

葛藤
Kudzu
夏季 NDVI 异常高 (>0.8)
全年秋橄榄 / 忍冬
Autumn Olive / Bush Honeysuckle
早春比本土植物早 2-3 周发芽
3–4 月芦苇
Phragmites australis
NIR 波段反射率持续偏高
夏末常春藤
English Ivy
冬季保持高 NDVI(常绿)
12–2 月真实数据
5 个站点的 NDVI 时间序列(Sentinel-2 真实测量)
来自 Google Earth Engine 的实测数据:2020–2025 年共 360 个月度观测点。切换「月度物候」可以看到多年平均的物候曲线,「完整时间序列」展示原始时间序列。点击图例可隐藏特定站点。
数据源: COPERNICUS/S2_SR_HARMONIZED · 500m 缓冲区 · 月度中位数合成 · 云量<30%
分类结果
基于物候特征的自动分类
用规则分类器(无需训练数据)对每个站点的 4 个季节性 NDVI 特征做判断。规则来自生态学先验:早春提前发芽、晚秋推迟落叶、冬季常绿、夏季爆发——任何一个超过本土对照的阈值就标记为入侵。
戴克沼泽 / 芦苇
可疑入侵 (单一信号)- 夏季比对照高 +0.10 (相对夏季爆发)
早春
0.401
夏峰
0.660
晚秋
0.505
冬季
0.308
大瀑布 / 葛藤
本土植被- 所有指标与本土对照接近
早春
0.274
夏峰
0.575
晚秋
0.425
冬季
0.206
亨特利湿地 / 芦苇
落叶入侵灌木 (秋橄榄/忍冬型)- 夏季比对照高 +0.29 (相对夏季爆发)
- 早春比对照高 +0.18 (提前发芽)
- 晚秋比对照高 +0.17 (推迟落叶)
早春
0.553
夏峰
0.845
晚秋
0.668
冬季
0.378
本土森林(对照)
本土植被- 所有指标与本土对照接近
早春
0.372
夏峰
0.558
晚秋
0.498
冬季
0.305
斯科茨朗 / 常春藤
广泛温和入侵 (composite signal)- 全季节温和升高 (ΣΔ=+0.25, 4/4 季节 > 对照)
早春
0.465
夏峰
0.610
晚秋
0.535
冬季
0.374



⚠️ 三种失败模式诊断(v1 → v1.1)
v1 (原始规则) 5 个点只检出 1 个 (Huntley Meadows)。诊断 4 个漏报对应 3 种本质不同的失败:(1) Scotts Run — 阈值过严,4 个季节都比对照高 0.05–0.10 但没单一指标突出;(2) Dyke Marsh — 规则缺失,夏季比对照高 +0.10 但旧规则只看绝对值;(3) Great Falls — 采样错误,坐标本身在裸岩/河面而非葛藤片区。v1.1 加入 composite 和 summer-vs-control 规则后,检出率从 1/5 提升到 3/5。Great Falls 需要重新选取坐标,规则改不动这种 ground-truth 层面的问题。
项目脚本
分析 Pipeline
4 个 Python 脚本构成完整的分析流程,每个脚本对应一个阶段。
理解 NDVI 概念
01_explore_ndvi_concept.py用模拟数据画出 NDVI 的定义,以及入侵植物 vs 本土植物的物候曲线。
为什么这么做:在跑真实卫星数据之前,先搞清楚「我们在测量什么」——不需要 GEE 账号就能运行。
输出: 01_ndvi_concept.png · 02_phenology_comparison.png · 03_study_area_map.html
GEE 提取真实 NDVI
02_gee_ndvi_timeseries.py连接 Google Earth Engine,对 5 个研究点提取 2020–2025 年 Sentinel-2 的月度 NDVI 时间序列。
为什么这么做:Sentinel-2 每 5 天过顶一次,6 年下来有几百张图。GEE 在云端并行处理,本地不需要下载任何原始影像。
输出: ndvi_timeseries_nova.csv · 04_gee_ndvi_timeseries.png
STAC API 下载 Landsat
03_download_landsat_stac.py通过 USGS STAC API 下载 Landsat 8/9 的原始波段数据,计算三个季节的 NDVI 地图。
为什么这么做:STAC API 不需要 GEE 账号,是 GEE 的备选方案;Landsat 30m 分辨率适合区域尺度分析。
输出: data/*.tif · outputs/ndvi_*.png
物候分类
04_phenology_analysis.py用早春 / 晚秋的 NDVI 差异特征,给每个站点做规则分类,输出 JSON 给 dashboard。
为什么这么做:这是项目目标:把时间序列信号转化成「这里是不是入侵植物」的判断。
输出: phenology_features.csv · classification.json · 05/06_*.png
# 1. 加载 Sentinel-2 数据集(GEE 懒加载,不下载数据)
collection = (
ee.ImageCollection("COPERNICUS/S2_SR_HARMONIZED")
.filterBounds(roi) # ① 只要北弗吉尼亚范围的影像
.filterDate("2022-03-01", "2022-04-30") # ② 只要早春
.filter(ee.Filter.lt("CLOUDY_PIXEL_PERCENTAGE", 30)) # ③ 去云
)
# 2. 对每张图计算 NDVI(在 GEE 云端并行执行)
def add_ndvi(image):
return image.addBands(
image.normalizedDifference(["B8", "B4"]).rename("NDVI")
)
# 3. 合成 + 提取统计值(转化为本地数字)
ndvi_median = collection.map(add_ndvi).select("NDVI").median()
stats = ndvi_median.reduceRegion(
reducer=ee.Reducer.mean(),
geometry=roi, # 500m 缓冲区
scale=10, # Sentinel-2 原始分辨率
).getInfo() # ← 只在这一步才真正触发 GEE 计算技术栈
数据来源: Copernicus Sentinel-2 · USGS Landsat · EDDMapS · iNaturalist
研究区域: Northern Virginia (38.70°N–39.00°N, 77.00°W–77.55°W)