进入GEE

右上角dataset打开

页面往下拉找到Landsat系列数据


选择地表反射率的L2层级产品,这个产品是做了辐射定标,大气校正,以及正射校正的产品

点击L2进入如下界面

下拉找到代码编辑器,点击

转到如下界面

可以新建一个项目或者是使用一个创建好的项目,之后的结果会存放再对应的项目之下,第一次使用需要登录谷歌账号绑定google cloud,可以创建项目相关文件夹
绑定完成之后输入js代码,选择研究区域,以及时间,在时间范围内筛选云量较少,有效区域范围95%以上的影像,建议不要使用镶嵌影像,因为在内蒙等区域植被生长周期不同,镶嵌尽管相差一两个月也可能导致植被的生长周期出现巨大差异,将代码复制点击Run运行。
bash
```javascript
/************************************
* 丰镇周边15km Landsat8 L2 两期植被分析
*
* 方法:
* 1. ROI缩小为丰镇中心周边15km
* 2. 每期只选择一景Landsat8 L2影像,不镶嵌
* 3. 后期保持2024年7-8月窗口
* 4. 前期放宽到2020年6-9月窗口,重新筛选有效影像
* 5. 加入VALID_RATIO,保证云掩膜后ROI内有效像元比例足够高
*
* 导出连续值:
* 1. 前期L2多波段
* 2. 后期L2多波段
* 3. 前期NDVI
* 4. 后期NDVI
* 5. 前期FVC
* 6. 后期FVC
* 7. NDVI差异:后期 - 前期
* 8. FVC差异:后期 - 前期
*
* 地图显示:
* NDVI、FVC、NDVI差异、FVC差异使用5级可视化
************************************/
// ===============================
// 1. 研究区:丰镇市中心周边15km
// ===============================
var fengzhenPoint = ee.Geometry.Point([113.169, 40.440]);
// 周边15km范围,外接矩形,便于导出
var roi = fengzhenPoint.buffer(15000).bounds();
Map.centerObject(roi, 10);
// ===============================
// 2. 白色背景图层:用于隐藏GEE底图
// ===============================
// 如果你想看Google底图,就在Layers里取消勾选这个图层
var whiteBackground = ee.Image.constant(1).visualize({
min: 0,
max: 1,
palette: ['ffffff']
});
Map.addLayer(
whiteBackground,
{},
'白色背景_隐藏底图',
true
);
// 只显示ROI边框,避免遮挡影像
var roiOutline = ee.Image().byte().paint({
featureCollection: ee.FeatureCollection([ee.Feature(roi)]),
color: 1,
width: 3
});
Map.addLayer(
roiOutline,
{palette: ['red']},
'ROI_丰镇周边15km'
);
// ===============================
// 3. 设置两个时间窗口
// ===============================
// 前期:放宽窗口,允许重新找一景有效覆盖更完整的影像
var startDate1 = '2020-06-01';
var endDate1 = '2020-09-30';
var targetDate1 = '2020-08-15';
// 后期:保持原来的7-8月窗口
var startDate2 = '2024-07-01';
var endDate2 = '2024-08-31';
var targetDate2 = '2024-08-15';
// 文件名标识
var periodTag1 = '2020_0601_0930_single_valid';
var periodTag2 = '2024_0701_0831_single_valid';
// ===============================
// 4. 导出参数
// 丰镇大致位于UTM 49N,使用EPSG:32649
// ===============================
var exportFolder = 'GEE_Fengzhen_Landsat8_15km_single_valid';
var exportScale = 30;
var exportCrs = 'EPSG:32649';
// ===============================
// 5. 影像筛选参数
// ===============================
// 影像足迹至少覆盖ROI的比例
var minCoverageRatio = 0.99;
// 云掩膜后,ROI内有效像元比例
// 如果前期候选影像数量为0,可以改成0.85
var minValidRatio = 0.90;
// Landsat整景云量上限
var maxCloudCover = 80;
// ===============================
// 6. Landsat8 L2尺度因子
// ===============================
function applyScaleFactors(image) {
image = ee.Image(image);
var opticalBands = image.select([
'SR_B1', 'SR_B2', 'SR_B3', 'SR_B4',
'SR_B5', 'SR_B6', 'SR_B7'
])
.multiply(0.0000275)
.add(-0.2);
var thermalBand = image.select('ST_B10')
.multiply(0.00341802)
.add(149.0);
var out = image
.addBands(opticalBands, null, true)
.addBands(thermalBand, null, true);
return ee.Image(out.copyProperties(image, image.propertyNames()));
}
// ===============================
// 7. 云、云影、雪、无效值、饱和像元掩膜
// ===============================
function maskL8L2(image) {
image = ee.Image(image);
var qa = image.select('QA_PIXEL');
// QA_PIXEL位说明:
// bit0: Fill
// bit1: Dilated Cloud
// bit2: Cirrus
// bit3: Cloud
// bit4: Cloud Shadow
// bit5: Snow
var qaMask = qa.bitwiseAnd(parseInt('111111', 2)).eq(0);
// 去除辐射饱和像元
var saturationMask = image.select('QA_RADSAT').eq(0);
var out = image
.updateMask(qaMask)
.updateMask(saturationMask);
return ee.Image(out.copyProperties(image, image.propertyNames()));
}
// ===============================
// 8. 计算NDVI
// ===============================
function addNDVI(image) {
image = ee.Image(image);
var ndvi = image.expression(
'(NIR - RED) / (NIR + RED)',
{
'NIR': image.select('SR_B5'),
'RED': image.select('SR_B4')
}
).rename('NDVI');
var out = image.addBands(ndvi);
return ee.Image(out.copyProperties(image, image.propertyNames()));
}
// ===============================
// 9. 计算影像足迹覆盖ROI比例
// ===============================
function addCoverageRatio(image) {
image = ee.Image(image);
var roiArea = roi.area(1);
var intersectArea = image.geometry().intersection(roi, 1).area(1);
var coverageRatio = intersectArea.divide(roiArea);
return ee.Image(image.set('ROI_COVERAGE_RATIO', coverageRatio));
}
// ===============================
// 10. 计算云掩膜后ROI内有效像元比例
// 这是关键:避免去云后只剩一小块
// ===============================
function addValidRatio(image) {
image = ee.Image(image);
var masked = ee.Image(maskL8L2(image));
// 取红光波段mask作为有效像元掩膜
// unmask(0)非常关键:无效区域计为0,否则均值可能虚高
var validMask = masked.select('SR_B4')
.mask()
.rename('valid')
.unmask(0);
var validRatio = validMask.reduceRegion({
reducer: ee.Reducer.mean(),
geometry: roi,
scale: exportScale,
maxPixels: 1e13,
tileScale: 4
}).get('valid');
return ee.Image(image.set('VALID_RATIO', validRatio));
}
// ===============================
// 11. 计算影像与目标日期的距离
// 方便优先选择接近目标日期的影像
// ===============================
function addDateDistanceAndScore(image, targetDate) {
image = ee.Image(image);
var dateDistance = ee.Date(image.get('system:time_start'))
.difference(ee.Date(targetDate), 'day')
.abs();
var cloudCover = ee.Number(image.get('CLOUD_COVER'));
var validRatio = ee.Number(image.get('VALID_RATIO'));
// 分数越低越优:
// 1. 有效像元比例越高越好
// 2. 云量越低越好
// 3. 日期越接近目标日期越好
var score = ee.Number(1).subtract(validRatio).multiply(200)
.add(cloudCover.multiply(0.2))
.add(dateDistance.multiply(0.1));
return ee.Image(image.set({
'DATE_DISTANCE_DAYS': dateDistance,
'SCENE_SCORE': score
}));
}
// ===============================
// 12. 获取单景L2影像
// ===============================
function getSingleL2Scene(startDate, endDate, targetDate, label) {
var collectionRaw = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2')
.filterBounds(roi)
.filterDate(startDate, endDate)
.filter(ee.Filter.lt('CLOUD_COVER', maxCloudCover))
.map(addCoverageRatio)
.filter(ee.Filter.gte('ROI_COVERAGE_RATIO', minCoverageRatio))
.map(addValidRatio)
.filter(ee.Filter.gte('VALID_RATIO', minValidRatio))
.map(function(img) {
return addDateDistanceAndScore(img, targetDate);
})
.sort('SCENE_SCORE');
print(label + '_有效候选影像数量', collectionRaw.size());
print(label + '_有效候选影像列表', collectionRaw);
var infoTable = collectionRaw.map(function(img) {
img = ee.Image(img);
return ee.Feature(null, {
'DATE_ACQUIRED': img.get('DATE_ACQUIRED'),
'CLOUD_COVER': img.get('CLOUD_COVER'),
'ROI_COVERAGE_RATIO': img.get('ROI_COVERAGE_RATIO'),
'VALID_RATIO': img.get('VALID_RATIO'),
'DATE_DISTANCE_DAYS': img.get('DATE_DISTANCE_DAYS'),
'SCENE_SCORE': img.get('SCENE_SCORE'),
'LANDSAT_PRODUCT_ID': img.get('LANDSAT_PRODUCT_ID'),
'WRS_PATH': img.get('WRS_PATH'),
'WRS_ROW': img.get('WRS_ROW')
});
});
print(label + '_候选影像日期云量有效像元表', infoTable);
var raw = ee.Image(collectionRaw.first());
print(label + '_最终选中影像', raw);
print(label + '_DATE_ACQUIRED', raw.get('DATE_ACQUIRED'));
print(label + '_CLOUD_COVER', raw.get('CLOUD_COVER'));
print(label + '_ROI_COVERAGE_RATIO', raw.get('ROI_COVERAGE_RATIO'));
print(label + '_VALID_RATIO', raw.get('VALID_RATIO'));
print(label + '_DATE_DISTANCE_DAYS', raw.get('DATE_DISTANCE_DAYS'));
print(label + '_SCENE_SCORE', raw.get('SCENE_SCORE'));
print(label + '_LANDSAT_PRODUCT_ID', raw.get('LANDSAT_PRODUCT_ID'));
var masked = ee.Image(maskL8L2(raw));
var scaled = ee.Image(applyScaleFactors(masked));
var withNDVI = ee.Image(addNDVI(scaled));
var processed = ee.Image(withNDVI.clip(roi));
return processed;
}
// ===============================
// 13. 获取两期单景影像
// ===============================
var image1 = ee.Image(getSingleL2Scene(
startDate1,
endDate1,
targetDate1,
'前期'
));
var image2 = ee.Image(getSingleL2Scene(
startDate2,
endDate2,
targetDate2,
'后期'
));
var ndvi1 = image1.select('NDVI').rename('NDVI_period1');
var ndvi2 = image2.select('NDVI').rename('NDVI_period2');
// ===============================
// 14. 统一NDVIsoil和NDVIveg,用于FVC计算
// 两期共用同一套参数,保证FVC可比
// ===============================
var ndviStats1 = ndvi1.reduceRegion({
reducer: ee.Reducer.percentile([5, 95]),
geometry: roi,
scale: exportScale,
maxPixels: 1e13,
tileScale: 4
});
var ndviStats2 = ndvi2.reduceRegion({
reducer: ee.Reducer.percentile([5, 95]),
geometry: roi,
scale: exportScale,
maxPixels: 1e13,
tileScale: 4
});
var ndviSoil1 = ee.Number(ndviStats1.get('NDVI_period1_p5'));
var ndviVeg1 = ee.Number(ndviStats1.get('NDVI_period1_p95'));
var ndviSoil2 = ee.Number(ndviStats2.get('NDVI_period2_p5'));
var ndviVeg2 = ee.Number(ndviStats2.get('NDVI_period2_p95'));
var ndviSoil = ndviSoil1.min(ndviSoil2);
var ndviVeg = ndviVeg1.max(ndviVeg2);
print('前期NDVI_5%', ndviSoil1);
print('前期NDVI_95%', ndviVeg1);
print('后期NDVI_5%', ndviSoil2);
print('后期NDVI_95%', ndviVeg2);
print('统一NDVIsoil', ndviSoil);
print('统一NDVIveg', ndviVeg);
// ===============================
// 15. 计算两期FVC
// FVC = (NDVI - NDVIsoil) / (NDVIveg - NDVIsoil)
// ===============================
var fvc1 = ndvi1
.subtract(ndviSoil)
.divide(ndviVeg.subtract(ndviSoil))
.clamp(0, 1)
.rename('FVC_period1');
var fvc2 = ndvi2
.subtract(ndviSoil)
.divide(ndviVeg.subtract(ndviSoil))
.clamp(0, 1)
.rename('FVC_period2');
// ===============================
// 16. 计算NDVI和FVC差异
// 差异 = 后期 - 前期
// ===============================
var ndviDiff = ndvi2
.subtract(ndvi1)
.rename('NDVI_diff_period2_minus_period1');
var fvcDiff = fvc2
.subtract(fvc1)
.rename('FVC_diff_period2_minus_period1');
// ===============================
// 17. 5级可视化分级函数
// 注意:这些分级影像只用于地图显示,不参与连续值导出
// ===============================
function classifyNDVI5(ndvi) {
ndvi = ee.Image(ndvi);
var cls = ee.Image(1)
.where(ndvi.gt(0.10).and(ndvi.lte(0.30)), 2)
.where(ndvi.gt(0.30).and(ndvi.lte(0.50)), 3)
.where(ndvi.gt(0.50).and(ndvi.lte(0.70)), 4)
.where(ndvi.gt(0.70), 5)
.updateMask(ndvi.mask())
.rename('NDVI_class_5');
return ee.Image(cls);
}
function classifyFVC5(fvc) {
fvc = ee.Image(fvc);
var cls = ee.Image(1)
.where(fvc.gt(0.20).and(fvc.lte(0.40)), 2)
.where(fvc.gt(0.40).and(fvc.lte(0.60)), 3)
.where(fvc.gt(0.60).and(fvc.lte(0.80)), 4)
.where(fvc.gt(0.80), 5)
.updateMask(fvc.mask())
.rename('FVC_class_5');
return ee.Image(cls);
}
function classifyDiff5(diff) {
diff = ee.Image(diff);
var cls = ee.Image(3)
.where(diff.lte(-0.20), 1)
.where(diff.gt(-0.20).and(diff.lte(-0.05)), 2)
.where(diff.gt(-0.05).and(diff.lte(0.05)), 3)
.where(diff.gt(0.05).and(diff.lte(0.20)), 4)
.where(diff.gt(0.20), 5)
.updateMask(diff.mask())
.rename('diff_class_5');
return ee.Image(cls);
}
var ndviClass1 = classifyNDVI5(ndvi1);
var ndviClass2 = classifyNDVI5(ndvi2);
var fvcClass1 = classifyFVC5(fvc1);
var fvcClass2 = classifyFVC5(fvc2);
var ndviDiffClass = classifyDiff5(ndviDiff);
var fvcDiffClass = classifyDiff5(fvcDiff);
// ===============================
// 18. 提取L2多波段数据
// 只导出L2地表反射率和地表温度
// 不包含NDVI和FVC
// ===============================
var l2Bands1 = image1.select([
'SR_B1', 'SR_B2', 'SR_B3', 'SR_B4',
'SR_B5', 'SR_B6', 'SR_B7',
'ST_B10'
]).toFloat();
var l2Bands2 = image2.select([
'SR_B1', 'SR_B2', 'SR_B3', 'SR_B4',
'SR_B5', 'SR_B6', 'SR_B7',
'ST_B10'
]).toFloat();
// ===============================
// 19. 可视化检查
// Map.addLayer只影响显示,不影响导出TIF真实值
// ===============================
Map.addLayer(
image1.select(['SR_B4', 'SR_B3', 'SR_B2']),
{min: 0.02, max: 0.30},
'前期L2真彩色_单景'
);
Map.addLayer(
image2.select(['SR_B4', 'SR_B3', 'SR_B2']),
{min: 0.02, max: 0.30},
'后期L2真彩色_单景'
);
// NDVI五级可视化
Map.addLayer(
ndviClass1,
{
min: 1,
max: 5,
palette: [
'#d73027',
'#fc8d59',
'#fee08b',
'#91cf60',
'#1a9850'
]
},
'前期NDVI_五级显示'
);
Map.addLayer(
ndviClass2,
{
min: 1,
max: 5,
palette: [
'#d73027',
'#fc8d59',
'#fee08b',
'#91cf60',
'#1a9850'
]
},
'后期NDVI_五级显示'
);
// FVC五级可视化
Map.addLayer(
fvcClass1,
{
min: 1,
max: 5,
palette: [
'#f7f7f7',
'#ffffb2',
'#fecc5c',
'#78c679',
'#006837'
]
},
'前期FVC_五级显示'
);
Map.addLayer(
fvcClass2,
{
min: 1,
max: 5,
palette: [
'#f7f7f7',
'#ffffb2',
'#fecc5c',
'#78c679',
'#006837'
]
},
'后期FVC_五级显示'
);
// NDVI差异五级可视化
Map.addLayer(
ndviDiffClass,
{
min: 1,
max: 5,
palette: [
'#b2182b',
'#ef8a62',
'#f7f7f7',
'#67a9cf',
'#2166ac'
]
},
'NDVI差异_五级显示'
);
// FVC差异五级可视化
Map.addLayer(
fvcDiffClass,
{
min: 1,
max: 5,
palette: [
'#b2182b',
'#ef8a62',
'#f7f7f7',
'#67a9cf',
'#2166ac'
]
},
'FVC差异_五级显示'
);
// ===============================
// 20. 均值统计,方便检查和写报告
// ===============================
var meanStats = ee.Image.cat([
ndvi1, ndvi2, ndviDiff,
fvc1, fvc2, fvcDiff
]).reduceRegion({
reducer: ee.Reducer.mean(),
geometry: roi,
scale: exportScale,
maxPixels: 1e13,
tileScale: 4
});
print('NDVI和FVC均值统计', meanStats);
// ===============================
// 21. 导出:L2多波段
// ===============================
Export.image.toDrive({
image: l2Bands1,
description: 'Fengzhen_15km_L8_L2_Multiband_' + periodTag1,
folder: exportFolder,
fileNamePrefix: 'Fengzhen_15km_L8_L2_Multiband_' + periodTag1,
region: roi,
scale: exportScale,
crs: exportCrs,
maxPixels: 1e13
});
Export.image.toDrive({
image: l2Bands2,
description: 'Fengzhen_15km_L8_L2_Multiband_' + periodTag2,
folder: exportFolder,
fileNamePrefix: 'Fengzhen_15km_L8_L2_Multiband_' + periodTag2,
region: roi,
scale: exportScale,
crs: exportCrs,
maxPixels: 1e13
});
// ===============================
// 22. 导出:NDVI连续值
// ===============================
Export.image.toDrive({
image: ndvi1.toFloat(),
description: 'Fengzhen_15km_NDVI_' + periodTag1,
folder: exportFolder,
fileNamePrefix: 'Fengzhen_15km_NDVI_' + periodTag1,
region: roi,
scale: exportScale,
crs: exportCrs,
maxPixels: 1e13
});
Export.image.toDrive({
image: ndvi2.toFloat(),
description: 'Fengzhen_15km_NDVI_' + periodTag2,
folder: exportFolder,
fileNamePrefix: 'Fengzhen_15km_NDVI_' + periodTag2,
region: roi,
scale: exportScale,
crs: exportCrs,
maxPixels: 1e13
});
// ===============================
// 23. 导出:FVC连续值
// ===============================
Export.image.toDrive({
image: fvc1.toFloat(),
description: 'Fengzhen_15km_FVC_' + periodTag1,
folder: exportFolder,
fileNamePrefix: 'Fengzhen_15km_FVC_' + periodTag1,
region: roi,
scale: exportScale,
crs: exportCrs,
maxPixels: 1e13
});
Export.image.toDrive({
image: fvc2.toFloat(),
description: 'Fengzhen_15km_FVC_' + periodTag2,
folder: exportFolder,
fileNamePrefix: 'Fengzhen_15km_FVC_' + periodTag2,
region: roi,
scale: exportScale,
crs: exportCrs,
maxPixels: 1e13
});
// ===============================
// 24. 导出:NDVI差异和FVC差异连续值
// ===============================
Export.image.toDrive({
image: ndviDiff.toFloat(),
description: 'Fengzhen_15km_NDVI_Diff_' + periodTag2 + '_minus_' + periodTag1,
folder: exportFolder,
fileNamePrefix: 'Fengzhen_15km_NDVI_Diff_' + periodTag2 + '_minus_' + periodTag1,
region: roi,
scale: exportScale,
crs: exportCrs,
maxPixels: 1e13
});
Export.image.toDrive({
image: fvcDiff.toFloat(),
description: 'Fengzhen_15km_FVC_Diff_' + periodTag2 + '_minus_' + periodTag1,
folder: exportFolder,
fileNamePrefix: 'Fengzhen_15km_FVC_Diff_' + periodTag2 + '_minus_' + periodTag1,
region: roi,
scale: exportScale,
crs: exportCrs,
maxPixels: 1e13
});
生成结果如下

点击右下角layer可以选择可视化展示对应的图像
右上角task可以看到生成的结果,点击Run将其保存在google cloud对应的项目之下,即可进入对应的项目进行下载使用
NDVI可视化结果

FCV植被覆盖度可视化结果

NDVI变化可视化结果

想制作其他区域的将对应的经纬度范围更换即可