3. GEE核心对象(上):Image、ImageCollection、Geometry、Feature、FeatureCollection
好,咱们正式开始啃GEE的核心对象了。
说实话,我刚接触GEE那会儿,最头疼的就是这些对象之间的关系。Image、ImageCollection、Geometry、Feature、FeatureCollection……名字长得像,用法又不一样。但搞懂了它们,GEE的大门才算真正推开。
一句话总结:GEE里所有数据,要么是栅格(Image/ImageCollection),要么是矢量(Geometry/Feature/FeatureCollection)。就这么简单。
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