迭代图像集合 Google Earth Engine
Iterate over Image Collection Google Earth Enigne
我编写了处理所有 Landsat 图像和计算 NDVI 的函数。但是,我有 59 个 GPS 点,我想要每个 GPS 点的 NDVI 时间序列输出。在 运行 我的代码之后,生成的 NDVI 值似乎不是每个点,而是每个图像的单个值。我猜是自动创建了某种边界框并用于计算,而不是使用 GPS 点。因此,我需要在所有 59 个点上迭代我的函数,并将输出保存到 table 中。
GPS 文件是 ESRI 点形状文件。
最好的方法是什么?
这是我的一些代码:
// import GPS locations from asset
GPS = GPS.geometry();
// Calculates the median NDVI and add value to image properties.
var meanNDVI = ndviLandsatCol.map(function(img) {
var obs = img.reduceRegion({
geometry: GPS,
reducer: ee.Reducer.median(),
scale: 30
});
return img.set('NDVI', obs.get('NDVI'));
});
ndviLandsatCol
变量是经过预处理的图像集合,其中添加了 NDVI 作为波段。
我对编码和 Google Earth Engine 还是个新手。有人可以建议如何在我所有的 GPS 点上迭代这个过程吗?我应该如何阅读GPS文件、字典?以及如何在不绘制点和下载随附文件的情况下将其保存到 .CSV 中。
如有任何帮助,我们将不胜感激。
如果您想要特征集合中每个点的图像值,您需要 reduceRegions
,而不是 reduceRegion
。这将 return 一个功能集合。类似于:
var allObs = ndviLandsatCol.map(function(img) {
var obsAtTime = img.reduceRegions({
collection: GPS,
reducer: ee.Reducer.median(),
scale: 30
});
return obsAtTime.map(function (feature) {
return feature.copyProperties(img, ['system:time_start']);
});
}).flatten();
请注意,您应该删除您拥有的行GPS = GPS.geometry();
,因为这会丢弃要素集合的结构并将其变成一个几何图形。
这将为您提供一个平面 table suitable 用于导出到 CSV,但您必须自己将这些行分组到时间序列中。
如果您需要在 Earth Engine 中进一步处理时间序列,可以使用以下两种不同的方式对它们进行分组:
使用一个ee.Join.saveAll
。这会让你得到一个 FeatureCollection
像 GPS
但有一个额外的 属性 其中包含时间序列中的 Feature
s,并且每个特征都具有与来自 ndviLandsatCol
.
print(
ee.Join.saveAll('series') // 'series' is the name of the time series property.
.apply(
allObs.distinct('.geo').select([]), // Determines properties of outer features (here, none but the geometry).
allObs,
ee.Filter.equals({leftField: '.geo', rightField: '.geo'})));
使用分组减速器。这将为您提供一个数字列表的字典列表,每个数字列表都是从原始 ndviLandsatCol
中明确选择的一个波段的时间序列。在我看来,这有点混乱,但可能会让您使用起来更简单。
print(allObs.reduceColumns(
ee.Reducer.toList().setOutputs(['NDVI'])
.combine(ee.Reducer.toList().setOutputs(['time']))
.group(0),
[
'.geo', // select geometry for the group() operation
'NDVI', // first toList reducer
'system:time_start', // second toList reducer
]));
这是最终的解决方案:
// Collect GPS, image, NDVI triplets.
var triplets = NDVILandsatCol.map(function(image) {
return image.select('NDVI').reduceRegions({
collection: GPS.select(['Site_ID']),
reducer: ee.Reducer.mean(),
scale: 30
}).filter(ee.Filter.neq('mean', null))
.map(function(f) {
return f.set('imageId', image.id());
});
}).flatten();
print(triplets.first());
// Format a table of triplets into a 2D table of rowId x colId.
var format = function(table, rowId, colId) {
var rows = table.distinct(rowId);
var joined = ee.Join.saveAll('matches').apply({
primary: rows,
secondary: table,
condition: ee.Filter.equals({
leftField: rowId,
rightField: rowId
})
});
return joined.map(function(row) {
var values = ee.List(row.get('matches'))
.map(function(feature) {
feature = ee.Feature(feature);
return [feature.get(colId), feature.get('mean')];
});
return row.select([rowId]).set(ee.Dictionary(values.flatten()));
});
};
// Export table
var table1 = format(triplets, 'imageId', 'Site_ID');
var desc1 = 'Table_demo';
Export.table.toDrive({
collection: table1,
description: desc1,
fileNamePrefix: desc1,
fileFormat: 'CSV'
});
我编写了处理所有 Landsat 图像和计算 NDVI 的函数。但是,我有 59 个 GPS 点,我想要每个 GPS 点的 NDVI 时间序列输出。在 运行 我的代码之后,生成的 NDVI 值似乎不是每个点,而是每个图像的单个值。我猜是自动创建了某种边界框并用于计算,而不是使用 GPS 点。因此,我需要在所有 59 个点上迭代我的函数,并将输出保存到 table 中。
GPS 文件是 ESRI 点形状文件。
最好的方法是什么?
这是我的一些代码:
// import GPS locations from asset
GPS = GPS.geometry();
// Calculates the median NDVI and add value to image properties.
var meanNDVI = ndviLandsatCol.map(function(img) {
var obs = img.reduceRegion({
geometry: GPS,
reducer: ee.Reducer.median(),
scale: 30
});
return img.set('NDVI', obs.get('NDVI'));
});
ndviLandsatCol
变量是经过预处理的图像集合,其中添加了 NDVI 作为波段。
我对编码和 Google Earth Engine 还是个新手。有人可以建议如何在我所有的 GPS 点上迭代这个过程吗?我应该如何阅读GPS文件、字典?以及如何在不绘制点和下载随附文件的情况下将其保存到 .CSV 中。
如有任何帮助,我们将不胜感激。
如果您想要特征集合中每个点的图像值,您需要 reduceRegions
,而不是 reduceRegion
。这将 return 一个功能集合。类似于:
var allObs = ndviLandsatCol.map(function(img) {
var obsAtTime = img.reduceRegions({
collection: GPS,
reducer: ee.Reducer.median(),
scale: 30
});
return obsAtTime.map(function (feature) {
return feature.copyProperties(img, ['system:time_start']);
});
}).flatten();
请注意,您应该删除您拥有的行GPS = GPS.geometry();
,因为这会丢弃要素集合的结构并将其变成一个几何图形。
这将为您提供一个平面 table suitable 用于导出到 CSV,但您必须自己将这些行分组到时间序列中。
如果您需要在 Earth Engine 中进一步处理时间序列,可以使用以下两种不同的方式对它们进行分组:
使用一个
ee.Join.saveAll
。这会让你得到一个FeatureCollection
像GPS
但有一个额外的 属性 其中包含时间序列中的Feature
s,并且每个特征都具有与来自ndviLandsatCol
.print( ee.Join.saveAll('series') // 'series' is the name of the time series property. .apply( allObs.distinct('.geo').select([]), // Determines properties of outer features (here, none but the geometry). allObs, ee.Filter.equals({leftField: '.geo', rightField: '.geo'})));
使用分组减速器。这将为您提供一个数字列表的字典列表,每个数字列表都是从原始
ndviLandsatCol
中明确选择的一个波段的时间序列。在我看来,这有点混乱,但可能会让您使用起来更简单。print(allObs.reduceColumns( ee.Reducer.toList().setOutputs(['NDVI']) .combine(ee.Reducer.toList().setOutputs(['time'])) .group(0), [ '.geo', // select geometry for the group() operation 'NDVI', // first toList reducer 'system:time_start', // second toList reducer ]));
这是最终的解决方案:
// Collect GPS, image, NDVI triplets.
var triplets = NDVILandsatCol.map(function(image) {
return image.select('NDVI').reduceRegions({
collection: GPS.select(['Site_ID']),
reducer: ee.Reducer.mean(),
scale: 30
}).filter(ee.Filter.neq('mean', null))
.map(function(f) {
return f.set('imageId', image.id());
});
}).flatten();
print(triplets.first());
// Format a table of triplets into a 2D table of rowId x colId.
var format = function(table, rowId, colId) {
var rows = table.distinct(rowId);
var joined = ee.Join.saveAll('matches').apply({
primary: rows,
secondary: table,
condition: ee.Filter.equals({
leftField: rowId,
rightField: rowId
})
});
return joined.map(function(row) {
var values = ee.List(row.get('matches'))
.map(function(feature) {
feature = ee.Feature(feature);
return [feature.get(colId), feature.get('mean')];
});
return row.select([rowId]).set(ee.Dictionary(values.flatten()));
});
};
// Export table
var table1 = format(triplets, 'imageId', 'Site_ID');
var desc1 = 'Table_demo';
Export.table.toDrive({
collection: table1,
description: desc1,
fileNamePrefix: desc1,
fileFormat: 'CSV'
});