使用 GEE 批量计算 Landsat 遥感指数

本文最后更新于 2026年3月3日 下午

在定量遥感分析中,遥感指数(如 NDVI、EVI、NBR 等)往往是后续建模、变化检测、制图统计的基础。GEE 的优势在于:可以在云端批量处理长时间序列,并将结果按年/按季导出

本文整理一套“能直接跑起来”的流程:

  • 将现成脚本添加到 GEE Code Editor
  • 按时间序列批量计算 Landsat 指数(可选均值/中值等统计)
  • 一键导出每个时间片的多波段 GeoTIFF
  • 扩展:添加自定义指数(以 RVI、DVI 为例)

参考脚本来源与导入方式

bgcasey 在 GEE Code Editor 维护了一套脚本仓库,包含时间序列、指数计算、导出等通用函数:

将脚本仓库添加到你的 GEE Code Editor(Reader 区)的方法:

  1. 打开链接:https://code.earthengine.google.com/?accept_repo=users/bgcasey/science_centre
  2. 在左侧 Scripts 面板的 Reader 中会出现 users/bgcasey/science_centre 相关脚本

仓库结构大致如下:

  • functions/:通用函数(导出 ImageCollection、计算指数、预处理等)
  • landsat_time_series.js:Landsat 时间序列主流程
  • sentinel_time_series.js:Sentinel-2 时间序列主流程
  • modis_time_series.js:MODIS 相关主流程

示例:批量计算 Landsat 年度指数并导出

下面的示例脚本演示:以 AOI(阿尔伯塔省)为区域,按年构建时间序列,为每个时间片计算一组指数,并导出为多波段 GeoTIFF(每个时间片导出一个文件)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
/*
* ---
* title: "Landsat Time Series Analysis"
* author: "Brendan Casey"
* created: "2024-12-05"
* description: Generates a time series of Landsat satellite imagery,
* calculates user-defined spectral indices, and outputs results as
* multiband images for further analysis.
* ---
*/

/* 1. Setup
* Prepare the environment, including the AOI, helper functions,
* and date list for time series processing.
*/

/* Load helper functions */
var utils = require(
"users/bgcasey/science_centre:functions/utils"
);
var landsatTimeSeries = require(
"users/bgcasey/science_centre:functions/landsat_time_series"
);
var landsatIndicesAndMasks = require(
"users/bgcasey/science_centre:functions/landsat_indices_and_masks"
);

/* Define area of interest (AOI) */
var aoi = ee.FeatureCollection('FAO/GAUL_SIMPLIFIED_500m/2015/level1')
.filter(ee.Filter.eq('ADM0_NAME', 'Canada'))
.filter(ee.Filter.eq('ADM1_NAME', 'Alberta'))
.geometry()

/* Small aoi for testing purposes */
// var aoi = ee.Geometry.Polygon([
// [-113.5, 55.5], // Top-left corner
// [-113.5, 55.0], // Bottom-left corner
// [-112.8, 55.0], // Bottom-right corner
// [-112.8, 55.5] // Top-right corner
// ]);


/* Create a date list
* The date list specifies the starting points for time
* intervals used to extract a time series. The createDateList
* function generates a list of dates at a specified interval
* (e.g., 1 year), beginning on the provided start date
* ('2000-06-01') and ending on the end date ('2024-06-01').
*
* For each date in the list, the ls_fn function will create a
* new end date by advancing the start date by a user-defined
* number of time units (e.g., 4 months, 6 weeks). Indices will
* be calculated for each of these time intervals.
*
* Due to memory limits when generating a time series of
* Alberta wide images, time series are generated in five year
* batches. Comment out the unused time periods.
*/


var dateList = utils.createDateList(
ee.Date('2001-06-01'), ee.Date('2005-06-01'), 1, 'years'
);

// var dateList = utils.createDateList(
// ee.Date('2006-06-01'), ee.Date('2010-06-01'), 1, 'years'
// );


print("Start Dates", dateList);

/* Define reducer statistic */
var statistic = 'mean'; // Choose from 'mean', 'median', 'max', etc.


/* 2. Landsat Time Series Processing
* Calculate user-defined spectral indices for Landsat imagery.
*
* Available indices:
* - BSI: Bare Soil Index
* - DRS: Distance Red & SWIR
* - DSWI: Disease Stress Water Index
* - EVI: Enhanced Vegetation Index
* - GNDVI: Green Normalized Difference Vegetation Index
* - LAI: Leaf Area Index
* - NBR: Normalized Burn Ratio
* - NDMI: Normalized Difference Moisture Index
* - NDSI: Normalized Difference Snow Index
* - NDVI: Normalized Difference Vegetation Index
* - NDWI: Normalized Difference Water Index
* - SAVI: Soil Adjusted Vegetation Index
* - SI: Shadow Index
*/
var ls = landsatTimeSeries.ls_fn(
dateList, 121, 'days', aoi,
[
'BSI', 'DRS', 'DSWI', 'EVI', 'GNDVI',
'LAI', 'NBR', 'NDMI', 'NDSI', 'NDVI',
'NDWI', 'SAVI', 'SI'
],
statistic
)
// // Apply NDRS for Conifer
// .map(function(image) {
// return landsatIndicesAndMasks.addNDRS(image, [210]);
// })
// // Apply NDRS for Broadleaf
// .map(function(image) {
// return landsatIndicesAndMasks.addNDRS(image, [220]);
// })
// // Apply NDRS for all forest types
// .map(function(image) {
// return landsatIndicesAndMasks.addNDRS(image);
// })
.map(function(image) {
// Exclude QA_PIXEL band and rename remaining bands
var filteredBandNames = image.bandNames().filter(
ee.Filter.neq('item', 'QA_PIXEL')
);
return image
.select(filteredBandNames)
.toFloat(); // Convert all bands to Float32
});

// print("Landsat Time Series:", ls);

/* 3. Export Time Series to Google Drive
* Export each image in the collection as multiband GeoTIFFs.
*/

/* Export parameters */
var folder = 'gee_exports';
var scale = 30; // 30-meter resolution
var crs = 'EPSG:4326'; // WGS 84 CRS

/* Define file naming function */
var fileNameFn = function(img) {
var year = img.get('year').getInfo() || 'unknown';
return 'landsat_multiband_' + year;
};

/* Export images to Google Drive */
utils.exportImageCollection(ls, aoi, folder, scale, crs, fileNameFn);

关键参数怎么改

你只需要改这几处:

  • AOI:把示例中的行政区筛选改成你的矢量/几何(ee.FeatureCollection/ee.Geometry 都可以)。
  • 时间范围utils.createDateList(start, end, step, unit) 决定时间片起点列表;ls_fn(dateList, window, unit, ...) 决定每个时间片的长度。
  • 统计方式statistic = 'mean' 可换成 'median''max' 等(视脚本实现支持情况)。
  • 导出参数folder / scale / crs / fileNameFn 控制导出位置、分辨率、投影与命名。

建议:AOI 很大、年份很多时,导出任务会非常多。可以按 3–5 年分段跑(示例代码里已经给了分段写法),避免超时或任务队列过长。

扩展:添加自定义遥感指数

如果需要计算脚本未内置的指数,一般做法是:

  1. landsat_indices_and_masks.js(或该仓库对应的指数工具文件)里新增 exports.addXXX 方法
  2. 在时间序列主逻辑中把 'XXX' 映射到对应的 addXXX 方法
  3. 在主脚本的指数列表里加上 'XXX'

下面以 RVI、DVI 为例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/**
* Adds Ratio Vegetation Index (RVI) band to an image.
* RVI = NIR / Red
* @param {Object} image - The image to process.
* @returns {Object} The image with the RVI band added.
*
* Tucker, C. J. (1979). Red and photographic infrared linear combinations for monitoring vegetation.
* Remote Sensing of Environment, 8(2), 127-150.
*/
exports.addRVI = function(image) {
var RVI = image.expression(
'NIR / Red', {
'NIR': image.select('SR_B4'),
'Red': image.select('SR_B3')
}).rename('RVI');
// Clamp RVI to reasonable range to handle extreme values
var RVI_clamped = RVI.clamp(0, 10);
return image.addBands([RVI_clamped]);
};

/**
* Adds Difference Vegetation Index (DVI) band to an image.
* DVI = NIR - Red
* @param {Object} image - The image to process.
* @returns {Object} The image with the DVI band added.
*
* Jordan, C. F. (1969). Derivation of leaf area index from quality of light on the forest floor.
* Ecology, 50(4), 663-666.
*/
exports.addDVI = function(image) {
var DVI = image.expression(
'NIR - Red', {
'NIR': image.select('SR_B4'),
'Red': image.select('SR_B3')
}).rename('DVI');
return image.addBands([DVI]);
};

将这些函数添加到相应文件后,需要在 landsat_time_series.js(或它内部调用的 switch/case 逻辑)里为新指数加映射。例如:

1
2
3
4
5
6
7
8
9
case 'SI':
combinedCollection = combinedCollection.map(landsat.addSI);
break;
case 'RVI':
combinedCollection = combinedCollection.map(landsat.addRVI);
break;
case 'DVI':
combinedCollection = combinedCollection.map(landsat.addDVI);
break;

最后在主脚本的指数列表里添加 'RVI''DVI',即可随时间序列一起批量输出。

1
2
3
4
5
6
7
8
9
10
11
var ls = landsatTimeSeries.ls_fn(
dateList, 121, 'days', aoi,
[
'BSI', 'DRS', 'DSWI', 'EVI', 'GNDVI',
'LAI', 'NBR', 'NDMI', 'NDSI', 'NDVI',
'NDWI', 'SAVI', 'SI',
// add new indices here
'RVI', 'DVI', 'TVI', 'CI', 'BI',
'NDBI', 'NSRVI'
],
statistic

常见注意事项

  • 波段命名要对得上:示例里自定义指数用的是 SR_B4/SR_B3(脚本重新统一了波段名称)。如果你的数据源是 Landsat 8/9 Collection 2 L2,红光/近红外通常是 SR_B4(Red)和 SR_B5(NIR)。请以脚本实际输入影像的 band 名称为准。
  • QA 波段处理:示例里通过过滤 QA_PIXEL 避免导出该波段;但更关键的是云/阴影掩膜是否已在上游处理(取决于 landsat_indices_and_masks 的实现)。
  • 导出任务数量:每个时间片一个导出任务,年份越多任务越多。建议分段跑,或把 AOI 先做裁剪/缩小用于调试。
  • 投影与分辨率scale=30 对 Landsat 常见;crs 可按你的区域/后处理习惯改(例如 UTM)。

到这里,就能比较稳定地用 GEE 批量计算并导出 Landsat 遥感指数时间序列了。Sentinel-2、MODIS 也有类似的脚本结构,可以参考上述方法进行修改和使用。希望对你有所帮助!

参考资料


使用 GEE 批量计算 Landsat 遥感指数
https://bintodo.top/links/gee-landsat-indices-batch.html
作者
bin
发布于
2026年1月22日
许可协议