3. GEE核心对象(上):Image、ImageCollection、Geometry、Feature、FeatureCollection

好,咱们正式开始啃GEE的核心对象了。

说实话,我刚接触GEE那会儿,最头疼的就是这些对象之间的关系。Image、ImageCollection、Geometry、Feature、FeatureCollection……名字长得像,用法又不一样。但搞懂了它们,GEE的大门才算真正推开。

一句话总结:GEE里所有数据,要么是栅格(Image/ImageCollection),要么是矢量(Geometry/Feature/FeatureCollection)。就这么简单。

GEE核心对象体系 栅格数据 矢量数据 Image(单景影像) ImageCollection(影像集合) Geometry(几何体) Feature(矢量要素) FeatureCollection(矢量集合) Feature = Geometry + 属性 FeatureCollection = 多个Feature的集合

3.1 Image——单景影像,GEE里的最小栅格单元

Image就是一张遥感影像。可以是Landsat的一景,也可以是Sentinel-2的一景。说白了,就是你在屏幕上看到的那张图。

创建Image的方式有很多:

  • 直接从GEE数据集加载:ee.Image('LANDSAT/LC08/C02/T1_TOA/LC08_044034_20201001')
  • 用常量创建:ee.Image(1) 或者 ee.Image.constant([0.5, 0.3, 0.8])
  • 从数组转换:ee.Image(ee.Array([[1,2],[3,4]]))

我的小习惯:调试时我经常用 ee.Image(1) 创建一个全1的影像来测试算法逻辑。省得每次都要加载真实数据,快得很。

Image的核心操作:

  • select()——选波段。比如 image.select(['B4', 'B3', 'B2'])
  • clip()——裁剪。用矢量边界把影像切出来
  • normalizedDifference()——算指数。NDVI、NDWI这些
  • addBands()——加波段。把计算结果拼回去
  • reduceRegion()——区域统计。算一个多边形里的均值、最大值等
// 加载Landsat 8影像
var image = ee.Image('LANDSAT/LC08/C02/T1_TOA/LC08_044034_20201001');

// 选波段 + 计算NDVI
var ndvi = image.normalizedDifference(['B5', 'B4']).rename('NDVI');

// 把NDVI加回原影像
var imageWithNdvi = image.addBands(ndvi);

print('影像信息', imageWithNdvi);

注意:GEE里的Image是懒加载的。你写 var image = ee.Image(...) 时,数据并没有真的下载到本地。只有当你调用 print()Map.addLayer()Export 时,才会触发实际计算。

我曾经犯过一个错:在循环里反复加载同一个Image,结果代码跑得巨慢。后来才发现,应该先把它赋给一个变量,后面直接引用变量就行。

3.2 ImageCollection——影像集合,时间序列的利器

ImageCollection就是一堆Image的集合。按时间排列,就是时间序列;按空间排列,就是影像镶嵌。

创建方式:

  • 从数据集筛选:ee.ImageCollection('LANDSAT/LC08/C02/T1_TOA').filterDate('2020-01-01', '2020-12-31')
  • 手动合并:ee.ImageCollection([img1, img2, img3])

最常用的操作——filter(筛选):

  • filterDate()——按时间筛
  • filterBounds()——按空间筛
  • filterMetadata()——按属性筛(比如云量小于10%)
// 获取2020年所有Landsat 8影像,云量小于20%
var collection = ee.ImageCollection('LANDSAT/LC08/C02/T1_TOA')
  .filterDate('2020-01-01', '2020-12-31')
  .filterBounds(roi)  // roi是研究区
  .filterMetadata('CLOUD_COVER', 'less_than', 20);

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

核心方法:

  • mosaic()——拼接成一张大图
  • median() / mean()——取中值/均值合成
  • map()——对集合里每张影像执行同一个操作
  • select()——选波段(所有影像都选)

举个例子,你想做一年内的NDVI中值合成:

var ndviMedian = collection
  .map(function(img) {
    return img.normalizedDifference(['B5', 'B4']).rename('NDVI');
  })
  .median();

Map.addLayer(ndviMedian, {min: -1, max: 1, palette: ['blue', 'white', 'green']}, 'NDVI中值');

嗯,这里要注意:map() 里的函数必须返回一个Image。我刚开始写的时候,经常忘记写 return,结果报错半天找不出原因。

3.3 Geometry——几何体,GEE里的空间骨架

Geometry就是点、线、面这些空间形状。GEE支持的类型有:

  • ee.Geometry.Point()——点
  • ee.Geometry.MultiPoint()——多点
  • ee.Geometry.LineString()——线
  • ee.Geometry.MultiLineString()——多线
  • ee.Geometry.Polygon()——面
  • ee.Geometry.MultiPolygon()——多面
// 创建一个点(经度, 纬度)
var point = ee.Geometry.Point([116.4, 39.9]);

// 创建一个矩形(用两个对角点定义)
var rectangle = ee.Geometry.Rectangle([116.0, 39.5, 117.0, 40.5]);

// 创建一个多边形
var polygon = ee.Geometry.Polygon([
  [[116.0, 39.5], [117.0, 39.5], [117.0, 40.5], [116.0, 40.5], [116.0, 39.5]]
]);

避坑指南:创建多边形时,最后一个点必须和第一个点相同,才能闭合。我曾经漏掉这个,结果画出来的多边形是个开口的,统计面积时数值完全不对。

常用空间操作:

  • intersection()——求交集
  • union()——求并集
  • difference()——求差集
  • buffer()——缓冲区分析
  • centroid()——求质心
  • area()——算面积(单位:平方米)

3.4 Feature——矢量要素,几何体+属性

Feature就是Geometry加上一堆属性数据。比如一个地块,它的形状是Geometry,它的面积、地类、权属等信息就是属性。

// 创建一个带属性的点要素
var pointFeature = ee.Feature(
  ee.Geometry.Point([116.4, 39.9]),
  {name: '天安门', type: '景点', area: 440000}
);

print('点要素', pointFeature);

属性操作:

  • set()——添加或修改属性
  • get()——获取属性值
  • select()——只保留某些属性
  • rename()——重命名属性

说白了,Feature就是「空间位置 + 数据表格里的一行」。你想想看,GIS里的矢量数据,本质上不就是这样吗?

3.5 FeatureCollection——矢量集合,批量处理的核心

FeatureCollection就是一堆Feature的集合。可以理解为整个矢量图层,或者一个Shapefile文件。

创建方式:

  • 从GEE数据集加载:ee.FeatureCollection('FAO/GAUL/2015/level0')(全球行政区划)
  • 手动创建:ee.FeatureCollection([feature1, feature2])
  • 从GeoJSON导入

核心操作:

  • filterBounds()——按空间筛选
  • filterMetadata()——按属性筛选
  • map()——对每个要素执行操作
  • reduceColumns()——统计属性列
  • aggregate_mean() / aggregate_sum()——聚合统计
// 加载中国省级行政区划
var china = ee.FeatureCollection('FAO/GAUL/2015/level0')
  .filterMetadata('ADM0_NAME', 'equals', 'China');

// 计算每个省份的面积(单位:平方公里)
var areas = china.map(function(province) {
  var areaSqKm = province.area().divide(1e6);
  return province.set('area_km2', areaSqKm);
});

print('带面积的省份', areas);

性能提示:FeatureCollection里的要素数量不要太多。GEE对单个FeatureCollection有5000个要素的限制(客户端)。如果你要处理上百万个点,建议用 reduceToImage() 转成栅格再算。

我遇到过最惨的一次:把一个100万点的CSV转成FeatureCollection,然后直接做空间连接……浏览器直接崩了。后来改用 reduceToImage()reduceRegion(),几秒钟就出结果。

3.6 对象之间的关系——一张图说清楚

对象 本质 包含什么 典型用途
Image 单张栅格 波段 + 像素值 单景影像分析
ImageCollection 栅格集合 多张Image 时间序列、影像合成
Geometry 空间形状 坐标点 定义研究区、空间操作
Feature 矢量要素 Geometry + 属性 单个地物表达
FeatureCollection 矢量集合 多个Feature 矢量图层、批量处理

我个人习惯把GEE的对象体系想象成乐高积木:

  • Geometry 是积木的形状
  • Feature 是形状上贴了标签
  • FeatureCollection 是一堆积木
  • Image 是一张完整的拼图
  • ImageCollection 是多张拼图的相册

你想想看,是不是这个理?

我的经验:刚开始学的时候,别纠结于每个对象的所有方法。先记住这5个对象长什么样、怎么创建、怎么打印出来看看。用 print()Map.addLayer() 多观察,比死记硬背强一百倍。


公众号:蓝海资料掘金营,微信deep3321