使用遥感图像来判断是否适合赏枫

赏枫,实在是秋季亲近自然的一大妙方。
在规划赏枫行程的时候(没错,我们J人就是这么喜欢规划),我却遇到了一个问题:“我怎么知道哪里适合赏枫?”最简单的方法当然是出行前看下小红书,判断是否适合赏枫,但如果提前一个星期多进行规划就不方便了(是的我们J人就是喜欢超前规划)。而且,也不是所有地方都会有人发枫叶状况,这该怎么办呢?

巧的很,我现在学的是遥感方向,那就找点遥感图像看看呗。

尝试(With GPT5)

虽说我是遥感方向,但是我本科完全不懂遥感啊,顶天了解CV相关的语意分割、目标检测啥的。所以我问了下GPT该怎么衡量该区域是否要落叶了,他给出的回答是 NDVI在0.3~0.5 之间 一般是落叶区域。我在 Copernicus Data Space Browser 中使用 Sentinel-2 拍摄的实时数据进行分析,发现城市区域造成的视觉干扰很大:20251020150515419于是我使用 SCL 并mask掉了城市区域。此外,我还将NDVI0.3~0.5区域标红。

可视化脚本
//VERSION=3
function setup() {
return {
input: ["B04", "B08", "SCL", "dataMask"],
57 collapsed lines
output: [
{ id: "default", bands: 4 },
{ id: "index", bands: 1, sampleType: "FLOAT32" },
{ id: "eobrowserStats", bands: 2, sampleType: "FLOAT32" },
{ id: "dataMask", bands: 1 }
]
};
}
// 参数:根据需要微调这三个阈值
const NDVI_MIN = 0.25; // 低于此值基本认为非有效植被(透明)
const FALL_LO = 0.30; // 落叶/变色窗口下界(偏黄)
const FALL_HI = 0.55; // 落叶/变色窗口上界(偏红)
function isVegetation(scl) {
return scl === 4; // SCL=4: Vegetation
}
function lerp(a,b,t){ return a + (b-a)*t; }
function clamp01(x){ return Math.max(0, Math.min(1, x)); }
function evaluatePixel(s) {
const ndvi = (s.B08 - s.B04) / (s.B08 + s.B04);
const veg = isVegetation(s.SCL) && s.dataMask === 1;
// 非植被或无效像素:透明
if (!veg || ndvi < NDVI_MIN) {
return {
default: [0,0,0,0],
index: [NaN],
eobrowserStats: [0,0],
dataMask: [0]
};
}
let rgba;
if (ndvi >= FALL_LO && ndvi <= FALL_HI) {
// 在“变色窗口”内:黄(#FFC800) → 红(#FF0000) 渐变
const t = clamp01((ndvi - FALL_LO) / (FALL_HI - FALL_LO)); // 0..1
const r = lerp(1.00, 1.00, t);
const g = lerp(0.78, 0.00, t);
const b = lerp(0.00, 0.00, t);
rgba = [r, g, b, 1]; // 高亮标红
} else if (ndvi > FALL_HI) {
// 常绿/高NDVI:降饱和的深绿,避免喧宾夺主
const g = clamp01((ndvi - FALL_HI) / (0.85 - FALL_HI)); // 0..1
rgba = [0.05, 0.25 + 0.5*g, 0.08, 0.9];
} else {
// 介于 NDVI_MIN 和 FALL_LO:稀疏植被,弱黄棕
rgba = [0.75, 0.65, 0.35, 0.9];
}
return {
default: rgba,
index: [ndvi],
eobrowserStats: [ndvi, 0],
dataMask: [1]
};
}

效果如下:20251020151205324

但是,这只是落叶区域啊?

我该怎么判断枫树在哪里😨?
“在最近NDVI大幅变化的大概率是阔叶林。”GPT如是说。

Delta NDVI
//VERSION=3
function setup() {
50 collapsed lines
return {
input: ["B04","B08","SCL","dataMask"],
output: [{ id:"default", bands:4 }],
mosaicking: "ORBIT" // 允许多时相
};
}
// ---- 参数可调 ----
const NDVI_MIN = 0.25; // 植被下限(低于则透明)
const DROP_LO = 0.05; // 认为“开始变色”的NDVI下降阈值
const DROP_HI = 0.25; // 强变色上限(越接近越红)
const CLOUDS = new Set([7,8,9,10]); // SCL 云类(排除)
function ndvi(s){ return (s.B08 - s.B04) / (s.B08 + s.B04); }
function clamp01(x){ return Math.max(0, Math.min(1, x)); }
function goodVeg(s){
return s.dataMask === 1 && s.SCL === 4; // 仅植被
}
function notCloud(s){ return !CLOUDS.has(s.SCL); }
function evaluatePixel(samples, scenes) {
if (samples.length < 2) return [0,0,0,0];
// 约定:samples[0] 较新,samples[samples.length-1] 较早
const sNew = samples[0];
const sOld = samples[samples.length-1];
// 基本质量控制:两期都得是植被且非云
if (!(goodVeg(sNew) && goodVeg(sOld) && notCloud(sNew) && notCloud(sOld))) {
return [0,0,0,0];
}
const nNew = ndvi(sNew);
const nOld = ndvi(sOld);
if (nNew < NDVI_MIN && nOld < NDVI_MIN) return [0,0,0,0];
const drop = nOld - nNew; // NDVI 下降为正值 = 疑似变色/落叶
if (drop >= DROP_LO) {
// 黄(#FFC800) -> 红(#FF0000) 渐变
const t = clamp01((drop - DROP_LO) / (DROP_HI - DROP_LO));
const r = 1.0;
const g = 0.78*(1.0 - t); // 0.78 -> 0
const b = 0.0;
return [r, g, b, 1.0];
} else {
// 变化不大:用低饱和绿显示“仍然茂盛的林地”
// 这样红色区域会非常醒目
const g = clamp01((nNew - NDVI_MIN) / (0.85 - NDVI_MIN));
return [0.05, 0.25 + 0.5*g, 0.08, 0.6];
}
}

但是田也会被标出来,就先这样吧。如果把两张图叠加,或许能筛选出高概率红的枫叶林:


20251020151457311

20251020151510243


小红书上云观景了一下 和统计结果差不多 没有太多红的地方。

结果最后决定爬山去了。