GEE数据处理代码不会写?手把手教你GIS数据云端分析(含:完整脚本)

编程与开发
Dr.GIS
wowwwai GIS研习社 · 工具流程与项目排障

如果你正在被“GEE数据处理代码不会写?手把手教你GIS数据云端分析(含:完整脚本)”这个问题卡住,本篇文章会用一个可直接运行的 Google Earth Engine 示例,带你完成从研究区导入、遥感影像筛选、云掩膜、NDVI 计算、结果可视化到导出 GeoTIFF 的完整流程。

引言:GEE数据处理代码不会写时,先从一个完整流程开始

很多 GIS 初学者第一次接触 Google Earth Engine,最大的障碍不是不知道它能做什么,而是不知道代码应该从哪里开始写。

在 QGIS 或 ArcGIS Pro 里,我们习惯点击工具、选择参数、运行结果;但在 GEE 中,数据筛选、波段计算、空间裁剪、时间合成、结果导出,都需要用脚本表达出来。

所以学习 GEE 数据处理代码,建议不要一开始就背 API,而是先跑通一个完整的 GIS 数据云端分析案例。本文选择一个最常见、最实用的任务:使用 Sentinel-2 影像计算研究区 NDVI,并导出分析结果

GEE数据处理代码与GIS数据云端分析完整流程示意图
GEE 数据处理代码的典型流程:先定义研究区,再筛选影像、云掩膜、计算指数、显示结果并导出数据。

背景:为什么 GIS 数据云端分析适合用 GEE

Google Earth Engine,简称 GEE,是一个面向遥感与地理空间分析的云端平台。它内置了大量遥感影像和地理数据集,例如 Sentinel、Landsat、MODIS、ERA5、SRTM 等。

对 GIS 用户来说,GEE 的优势主要体现在三个方面:

  • 不用手动下载海量影像:可以直接在云端调用公开数据集。
  • 不用本地配置复杂环境:大部分计算在云端服务器完成。
  • 适合大范围、长时间序列分析:例如多年 NDVI、土地覆盖变化、干旱监测、城市扩张分析。

但它也有一个明显门槛:GEE 主要通过 JavaScript 或 Python 写代码。对于刚从 ArcGIS Pro、QGIS 转过来的同学来说,GEE 数据处理代码看起来会比较陌生。

本文使用 GEE Code Editor 中的 JavaScript 写法,因为这是入门 GEE 最常用、最直接的方式。

原理:GEE数据处理代码到底在做什么

在 GEE 中,绝大多数 GIS 数据处理都围绕三个对象展开:

  • Geometry:几何对象,例如点、线、面、研究区边界。
  • Image:单景栅格影像,例如某一天的 Sentinel-2 影像。
  • ImageCollection:影像集合,例如某个时间段内的所有 Sentinel-2 影像。

这和传统 GIS 的思路很相似。区别在于,GEE 中很多操作不是立即在本地执行,而是构建一条云端计算任务链。只有当你显示地图、打印统计值或导出结果时,GEE 才会真正计算。

本案例的核心原理如下:

  1. 定义一个研究区。
  2. 从 Sentinel-2 影像集合中筛选时间、范围和云量。
  3. 使用云概率或质量波段进行云掩膜。
  4. 对筛选后的影像做中值合成,减少云和异常值影响。
  5. 使用近红外波段和红光波段计算 NDVI。
  6. 将 NDVI 结果裁剪到研究区。
  7. 在地图上查看并导出 GeoTIFF。

NDVI 的计算公式为:

NDVI = (NIR - Red) / (NIR + Red)

对于 Sentinel-2 SR 数据,常用波段是:

  • B8:近红外波段 NIR。
  • B4:红光波段 Red。

步骤:手把手编写 GEE 数据处理完整脚本

步骤 1:打开 GEE Code Editor

访问 GEE Code Editor 后,新建一个脚本。建议先不要直接写复杂项目,而是从最小可运行代码开始。

如果你还没有创建 GEE 账号,需要先使用 Google 账号申请 Earth Engine 访问权限。账号可用后,就可以在浏览器中运行本文脚本。

步骤 2:定义研究区

为了让脚本可以直接运行,下面示例使用一个手动绘制的矩形范围。你可以把坐标改成自己的研究区,也可以换成上传的行政区边界。

// 1. 定义研究区:这里以一个矩形区域为例
var roi = ee.Geometry.Rectangle([116.20, 39.75, 116.55, 40.05]);

// 将地图定位到研究区
Map.centerObject(roi, 10);
Map.addLayer(roi, {color: 'red'}, '研究区');

如果你的研究区来自 Shapefile,可以先在 GEE 的 Assets 中上传,再用类似下面的方式调用:

// 如果你上传了矢量边界,可以使用类似写法
// var roi = ee.FeatureCollection('users/your_username/your_boundary');

步骤 3:筛选 Sentinel-2 影像

这里使用 Sentinel-2 Level-2A 地表反射率数据集。它已经经过大气校正,适合植被指数、水体指数、地表覆盖分析等常见 GIS 遥感任务。

// 2. 设置时间范围
var startDate = '2023-06-01';
var endDate = '2023-09-30';

// 3. 读取 Sentinel-2 SR 影像集合
var s2 = ee.ImageCollection('COPERNICUS/S2_SR_HARMONIZED')
  .filterBounds(roi)
  .filterDate(startDate, endDate)
  .filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE', 30));

print('筛选后的影像数量', s2.size());

这段 GEE 数据处理代码完成了三个筛选条件:

  • filterBounds:只保留覆盖研究区的影像。
  • filterDate:只保留指定时间范围内的影像。
  • CLOUDY_PIXEL_PERCENTAGE:只保留整体云量小于 30% 的影像。

注意:整体云量小不代表研究区内一定无云。因此后面仍然需要做云掩膜。

步骤 4:编写 Sentinel-2 云掩膜函数

Sentinel-2 SR 数据包含 SCL 场景分类波段。SCL 可以标记云、云影、水体、植被、裸地等类别。这里使用 SCL 去除云、云影和卷云。

// 4. Sentinel-2 云掩膜函数
function maskS2Clouds(image) {
  var scl = image.select('SCL');

  // SCL 常见类别:
  // 3 = 云影
  // 8 = 中概率云
  // 9 = 高概率云
  // 10 = 薄卷云
  // 11 = 雪或冰

  var mask = scl.neq(3)
    .and(scl.neq(8))
    .and(scl.neq(9))
    .and(scl.neq(10))
    .and(scl.neq(11));

  return image.updateMask(mask)
    .divide(10000)
    .copyProperties(image, ['system:time_start']);
}

这里的 divide(10000) 是为了把 Sentinel-2 的整数反射率缩放为 0 到 1 左右的小数值。计算 NDVI 时,不缩放通常也能得到相同指数结果,但缩放后更方便后续可视化和分析。

步骤 5:进行影像合成

实际遥感影像经常存在云、阴影和局部异常值。为了得到更稳定的结果,可以对时间范围内的多景影像做中值合成。

// 5. 对影像集合应用云掩膜,并进行中值合成
var composite = s2
  .map(maskS2Clouds)
  .median()
  .clip(roi);

// 6. 显示真彩色合成影像
var rgbVis = {
  bands: ['B4', 'B3', 'B2'],
  min: 0,
  max: 0.3
};

Map.addLayer(composite, rgbVis, 'Sentinel-2 真彩色合成');

中值合成并不是万能的。如果某个地区在整个时间段内都持续多云,中值合成仍然可能残留云或缺失像元。因此在南方雨季、山区、热带地区做分析时,建议适当扩大时间范围,或者使用更严格的云概率数据。

步骤 6:计算 NDVI

GEE 提供了 normalizedDifference 方法,可以快速计算归一化差值指数。对于 NDVI,只需要传入近红外波段 B8 和红光波段 B4。

// 7. 计算 NDVI
var ndvi = composite
  .normalizedDifference(['B8', 'B4'])
  .rename('NDVI');

// 8. 设置 NDVI 可视化参数
var ndviVis = {
  min: -0.2,
  max: 0.8,
  palette: ['blue', 'white', 'yellow', 'green']
};

Map.addLayer(ndvi, ndviVis, 'NDVI');

NDVI 一般可以这样粗略理解:

  • 接近 -1 到 0:水体、阴影、云或非植被区域。
  • 0 到 0.2:裸地、建设用地或稀疏植被。
  • 0.2 到 0.5:中等植被覆盖。
  • 0.5 以上:较高植被覆盖。

步骤 7:统计研究区 NDVI 平均值

除了显示地图,我们还可以用 reduceRegion 计算研究区内的统计值。例如平均 NDVI、最小值、最大值等。

// 9. 计算研究区 NDVI 平均值
var meanNdvi = ndvi.reduceRegion({
  reducer: ee.Reducer.mean(),
  geometry: roi,
  scale: 10,
  maxPixels: 1e13
});

print('研究区平均 NDVI', meanNdvi);

这里的 scale: 10 表示按 10 米空间分辨率进行统计。因为 Sentinel-2 的 B8 和 B4 都是 10 米分辨率,所以这个参数是合理的。

步骤 8:导出 NDVI GeoTIFF

如果你需要把结果放到 QGIS、ArcGIS Pro 或 Python 中继续处理,可以将 NDVI 导出为 GeoTIFF。

// 10. 导出 NDVI 到 Google Drive
Export.image.toDrive({
  image: ndvi,
  description: 'S2_NDVI_ROI_2023_Summer',
  folder: 'GEE_Export',
  fileNamePrefix: 'S2_NDVI_ROI_2023_Summer',
  region: roi,
  scale: 10,
  crs: 'EPSG:4326',
  maxPixels: 1e13
});

运行脚本后,在右侧 Tasks 面板中点击 Run,确认导出参数后开始任务。导出完成后,GeoTIFF 会出现在你的 Google Drive 对应文件夹中。

完整 GEE 数据处理代码

下面是可以直接复制到 GEE Code Editor 中运行的完整脚本。

// GEE 数据处理完整脚本:Sentinel-2 NDVI 云端分析
// 功能:研究区定义、影像筛选、云掩膜、中值合成、NDVI计算、统计与导出

// 1. 定义研究区
var roi = ee.Geometry.Rectangle([116.20, 39.75, 116.55, 40.05]);

Map.centerObject(roi, 10);
Map.addLayer(roi, {color: 'red'}, '研究区');

// 2. 设置时间范围
var startDate = '2023-06-01';
var endDate = '2023-09-30';

// 3. 读取 Sentinel-2 SR 影像集合
var s2 = ee.ImageCollection('COPERNICUS/S2_SR_HARMONIZED')
  .filterBounds(roi)
  .filterDate(startDate, endDate)
  .filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE', 30));

print('筛选后的影像数量', s2.size());

// 4. Sentinel-2 云掩膜函数
function maskS2Clouds(image) {
  var scl = image.select('SCL');

  var mask = scl.neq(3)
    .and(scl.neq(8))
    .and(scl.neq(9))
    .and(scl.neq(10))
    .and(scl.neq(11));

  return image.updateMask(mask)
    .divide(10000)
    .copyProperties(image, ['system:time_start']);
}

// 5. 云掩膜与中值合成
var composite = s2
  .map(maskS2Clouds)
  .median()
  .clip(roi);

// 6. 显示真彩色影像
var rgbVis = {
  bands: ['B4', 'B3', 'B2'],
  min: 0,
  max: 0.3
};

Map.addLayer(composite, rgbVis, 'Sentinel-2 真彩色合成');

// 7. 计算 NDVI
var ndvi = composite
  .normalizedDifference(['B8', 'B4'])
  .rename('NDVI');

// 8. 显示 NDVI
var ndviVis = {
  min: -0.2,
  max: 0.8,
  palette: ['blue', 'white', 'yellow', 'green']
};

Map.addLayer(ndvi, ndviVis, 'NDVI');

// 9. 统计研究区平均 NDVI
var meanNdvi = ndvi.reduceRegion({
  reducer: ee.Reducer.mean(),
  geometry: roi,
  scale: 10,
  maxPixels: 1e13
});

print('研究区平均 NDVI', meanNdvi);

// 10. 导出 NDVI GeoTIFF
Export.image.toDrive({
  image: ndvi,
  description: 'S2_NDVI_ROI_2023_Summer',
  folder: 'GEE_Export',
  fileNamePrefix: 'S2_NDVI_ROI_2023_Summer',
  region: roi,
  scale: 10,
  crs: 'EPSG:4326',
  maxPixels: 1e13
});

常见坑:GEE 数据处理代码运行失败的原因

1. 研究区太大导致计算超限

GEE 虽然是云端平台,但并不意味着可以无限计算。如果研究区过大、时间范围过长、分辨率过高,就可能出现计算超时或像元数量超限。

解决办法:

  • 先用小范围测试代码是否正确。
  • 导出时设置合理的 scale
  • 必要时按行政区或网格分块处理。
  • 使用 maxPixels 放宽像元数量限制,但不要把它当作万能参数。

2. 地图上没有显示结果

如果运行后地图为空白,常见原因有:

  • 研究区坐标写错,经纬度顺序颠倒。
  • 时间范围内没有可用影像。
  • 云掩膜条件过严,导致像元全部被掩膜。
  • 可视化参数的 minmax 设置不合理。

建议先打印影像数量:

print('影像数量', s2.size());

如果结果为 0,说明筛选条件没有匹配到影像,需要调整时间、区域或云量条件。

3. 导出 GeoTIFF 后在 QGIS 中位置不对

导出结果在 QGIS 或 ArcGIS Pro 中位置不对,通常与坐标系设置、研究区边界或数据显示方式有关。

建议检查:

  • 导出参数中的 crs 是否符合项目需求。
  • QGIS 工程坐标系是否正确。
  • 是否误把经纬度坐标当作投影坐标输入。
  • 研究区边界是否本身就存在坐标系错误。

4. NDVI 结果看起来异常

NDVI 异常通常不是公式错,而是数据和掩膜存在问题。常见情况包括云未去除、阴影未去除、水体范围较大、季节选择不合适。

建议同时显示真彩色影像和 NDVI 结果,对照检查高值区和低值区是否合理。

方法比较:GEE、QGIS、ArcGIS Pro 做遥感分析有什么区别

方法 适合场景 优势 限制
GEE 大范围、多时相、云端遥感分析 数据丰富,云端计算,不必批量下载影像 需要写代码,导出任务有配额和限制
QGIS 本地制图、栅格处理、结果检查 免费开源,插件丰富,适合交互式操作 大数据处理依赖本机性能
ArcGIS Pro 工程化 GIS 项目、空间分析、制图生产 工具链完整,适合单位项目流程 商业软件,遥感大批量处理仍需合理组织数据
Python GIS 自动化批处理、自定义模型 灵活,可结合 GeoPandas、Rasterio、GDAL 环境配置和代码能力要求较高

一个实用的工作流是:用 GEE 完成云端数据筛选和初步分析,导出 GeoTIFF 后,再在 QGIS 或 ArcGIS Pro 中进行制图、叠加分析和成果整理。

检查清单:写 GEE 数据处理代码前先确认这些问题

  • 研究区是否正确:经纬度顺序是否为经度、纬度,边界是否覆盖目标区域。
  • 数据集是否适合任务:NDVI 推荐使用 Sentinel-2 SR 或 Landsat Collection 2 SR。
  • 时间范围是否合理:植被分析应避开非生长季或持续多云时段。
  • 云掩膜是否有效:不要只依赖整体云量字段。
  • 空间分辨率是否匹配:Sentinel-2 NDVI 常用 10 米,MODIS 常用更粗分辨率。
  • 导出区域是否过大:大范围导出建议分块。
  • 结果是否经过目视检查:真彩色影像、NDVI 图层和研究区边界应一起检查。
  • 是否需要后续 GIS 制图:如果需要制图,导出 GeoTIFF 后可在 QGIS 或 ArcGIS Pro 中继续处理。

FAQ:GEE 数据处理代码常见问题

GEE 数据处理代码一定要会 JavaScript 吗?

不一定。GEE 同时支持 JavaScript 和 Python。但对初学者来说,GEE Code Editor 的 JavaScript 示例最多,调试也最方便。建议先用 JavaScript 跑通流程,再根据需要学习 Python API。

为什么我的 Sentinel-2 影像筛选结果为 0?

通常是研究区、时间范围或筛选条件过严导致的。可以先放宽云量限制,扩大时间范围,并确认研究区坐标是否正确。

GEE 云端分析结果可以直接用于论文或项目吗?

可以,但需要说明数据来源、时间范围、处理方法、云掩膜规则和空间分辨率。对于正式项目,还应进行精度验证或与地面样本、已有数据进行对比。

NDVI 导出到 QGIS 后为什么只有一个波段?

这是正常的。NDVI 本身就是由红光和近红外计算得到的单波段指数影像。你可以在 QGIS 中使用单波段伪彩色渲染来显示它。

GEE 适合处理 Shapefile 吗?

可以。你可以把 Shapefile 打包为 ZIP 上传到 GEE Assets,然后作为 FeatureCollection 调用。但要注意字段编码、几何合法性和坐标系问题。

为什么导出任务一直排队或失败?

可能是导出范围太大、分辨率太高、任务过多或服务器资源暂时紧张。建议减少导出区域、提高 scale、分块导出,或者稍后重新运行任务。

结论:先跑通完整脚本,再逐步改成自己的 GEE 项目

学习 GEE 数据处理代码,不建议一开始就追求复杂模型。更有效的方法是先掌握一个完整、可运行、可验证的 GIS 数据云端分析流程。

本文的 Sentinel-2 NDVI 示例覆盖了 GEE 入门中最核心的环节:研究区定义、影像集合筛选、云掩膜、指数计算、统计分析和 GeoTIFF 导出。你可以把这套脚本改造成水体提取、城市热岛、土地覆盖变化或生态监测项目的基础模板。

真正写好 GEE 数据处理代码的关键,不是记住每一个函数,而是理解每一步为什么要做、输入输出是什么、结果如何检查。只要这个思路建立起来,GEE 就会从“代码门槛”变成一个非常高效的 GIS 云端分析工具。