EZ | Get Started with Earth Engi
开始使用GEE
这篇引导旨在为大家使用JavaScript语言的API提供一个快速路径,如果想要JavaScript的详细介绍或是得到API更加深入的使用,可以看这里,如果想要关于JavaScript代码风格的建议,则可以看谷歌对于JS编码的指导
GEE允许用户对储存在Google基础框架上的地理配准图(Georeferrenced Imagery)和矢量(Vector)运行一些算法,API提供了很多的功能,可以在图像上有所运用,既可以做显示,又可以做分析。这里有一份GEE的公开数据清单,它包含了大量开源可用的图像和矢量数据集,大家也可以在个人文件夹里放一些自己的数据。
代码编辑器(Code Editor)是一个用于开发GEE程序的交互式环境,界面就如Fig.1所示,中间的部分是一个JavaScript的代码编辑页面,编辑器上面有一些按钮,可以用来执行保存脚本、运行代码、清空页面等操作。还有一个Get Link按钮,可以在地址框(Address Bar)里生成一个唯一性的URL。底部的展示面板展示了正在运行的脚本所加入的所有图像层(Layer),顶部还有一个搜索栏(Search Box),可以搜索数据集,也可以搜索某个地点,随人所愿。左边有一个实例代码的展示区,可以用来存放脚本或是在里面找API或是在资产库(Asset)里检索自己的私人文件。右部有一个对检查器(Inspector)、一个输出面板(Output Console),还有一个对于任务管理器(Manager),帮助按钮在右上方,里面有指向指导文档的链接还有其他文件。可以从代码编辑器指导和帮助文档中得到更多信息。
打开,并在代码编辑器中Run起来
我们演示一下如何打开GEE的并执行一下显示图像的脚步,如果想得到最好的效果,推荐安装最新的Chrome。
- 打开GEE代码编辑器如果你还没注册,那就用Google账户注册一个。
- 代码编辑器最左边有一个脚本(Scripts)选项卡,可以在那里找到一组脚本实例,你可以访问、展示并且在GEE中运行它们。
- 在图像集(Image Collection)下,选择过滤复合(Filtered Composite),你就能在中控台(Center Console)上看到一个脚本,点一下运行(Run)按钮,就会选择科罗拉多州和犹他州相交位置一定范围内Landsat-7卫星的图像,它的显示使用真彩色合成的,这个例子会展示一下
filter()
、clip()
和Map.addLayer()
等基本的功能。
GEE数据结构
GEE中两个最基本的数据结构是Image和ImageCollection(这两个东西会经常用,也很好理解,不译),二者分别代表了光栅图像(Raster)和矢量图(Vector)。Image容纳里波段(Band)信息和一个特性(Properties)组成的字典,Feature则是由几何信息和特征字典组成。一个图像的堆栈可以被整合为一个ImageCollection,特征的集合则可以被整合为FeatureCollection,GEE中还有一些基本的数据结构,有Dictionary、Data、Number和String等,重要的是记住这些数据结构都是面向服务器端的,这就意味着,除非你特意要求,你的浏览器不会知道你的脚本的任何信息。而你的特意要求会从Google传递到代码编辑器,如果信息Size比较大,速度就会稍微慢一点。
GEE的计算方法
有好几种调用API的方法,包括:
- 调用对象自己的方法;
- 调用算法;
- 使用代码编辑器中特有的的函数;
- 定义一些新函数;
代码编辑器列表中的文档(Docs)里有各个API类的使用方法(Method),举个例子,在Image类里,有一个方法是这样用的:
var image3 = image1.add(image2);
这个方法把image2的波段添加到image1里,ee.Algorithms
类包括一个特定算法的列表,想从输入的DEM中创建一个图层,可以这样做:
var terrainImage = ee.Algorithms.Terrain(dem);
代码编辑器还有一些特殊的函数,包括Map
还有其他的导出方法,能够把选中的图道导出到Google Drive中。在代码编辑器里,可以这样创建函数:
var myFunction = function(args) {
// do something
return something;
};
想要使用定义好的函数去创造一个Collection,可以这样做:
var collection2 = collection1.map(aFunction);
在GEE中,静态的方法叫做Class(像是ee.Image),被写作
Image.staticMethod()
而在类的实例中被调用的放大被写作image.instanceMethod()
,小写的image意思是这是一个名叫image的变量,是ee.Image的一个实例。
使用JavaScript打印‘Hello World!’
把特定的信息打印到输出面板上,是得到一个东西的信息的基本方法,展示一些数据性的结果,或是展示一个元数据(Metadata),或是一些Debug用的帮助信息,都可以这样做。在代码编辑器打印'Hello World!'是这样实现的:
print('Hello World!')
把这行代码Copy到代码编辑中,运行一下,就能在输出面板中看到我们想要的东西。对于一个遥感实例,下面的操作可以看一些Landsat 8卫星图像的一些元数据:
print(ee.Image('LANDSAT/LC08/C01/T1/LC08_044034_20140318'));
展示面板上就能看到这颗卫星的一些图像了。
往Map里增加一些数据
想要在展示面板上显示一些信息,尤其是一些可视化的信息,就要用到Adding操作,使用Map.addLayer()
函数达成这一目的。下面的例子里,我们先用ee.Image()
加载了一张Image,然后使用Map.addLayer()
函数增加了一些东西,然后,地图就被居中显示。
// Load an image.
var image = ee.Image('LANDSAT/LC08/C01/T1/LC08_044034_20140318');
// Center the map on the image.
Map.centerObject(image, 9);
// Display the image.
Map.addLayer(image);
Map.centerObject()
函数的第二个参数代表了缩放等级,越大的数字代表了越大的区域。如果对图像的显示效果不满意,可以对函数的一些参数做一些修改:
var image = ee.Image('LANDSAT/LC08/C01/T1/LC08_044034_20140318');
// Define visualization parameters in an object literal.
var vizParams = {bands: ['B5', 'B4', 'B3'], min: 5000, max: 15000, gamma: 1.3
// Center the map on the image and display.
Map.centerObject(image, 9);
Map.addLayer(image, vizParams, 'Landsat 8 false color');
我们还可以使用这个函数增加一些feature或者featureCollection,代码如下:
var counties = ee.FeatureCollection('TIGER/2016/Counties');
Map.addLayer(counties, {}, 'counties');
找到你想要的数据
images、 image collections 和 feature collections都可以在GEE的数据清单里找到,在搜索栏中输入Landsat 8就可以找到这颗卫星,其他的也类似。完整的数据集的清单,可以在这里找到,点击数据集的名字,可以查看一些基本信息,包括数据来源、ID等等。点击导入(Import)按钮,可以把这个数据集加入进来,自动地,代码的头部就会出现对应的一行import代码。
也可以把数据集的ID复制到代码中来使用这个数据集:
var collection = ee ImageCollection(LANDSAT/LC08/C01/T1 )
一个Collection是来自地表的多层图像组成的,找到一个Collection里单张的图像要用到过滤器(Filter),也可以使用复合(Composite)和镶嵌(Mosaick)把一个图像的Collection削减到单张图像。对于过滤器、复合之类的详细信息,可以看对应部分的文档。
过滤和分类
我们经常需要根据空间和(或)时间对图像集进行过滤,主要目的是限制结果的数量,举个例子,想知道旧金山的Landsat 8数据中没有云雾遮挡的部分,就需要这样做。首先,我们需要定义一个ROI,一个点通常就足够了,点一下代码编辑器右边的检查(Inspector)按钮,就会看到你的ROI的信息,复制下来,然后就可以使用这个点了:
var point = ee.Geometry.Point(-122.262, 37.8719);
开始日期和结束日期应该这样设置:
var start = ee.Date('2014-06-01');
var finish = ee.Date('2014-10-01');
使用这个点和起止时间,就可以对图像进行过滤了。
当然,也可以把一些元数据进行修改,做到更好的过滤:
var filteredCollection = ee.ImageCollection('LANDSAT/LC08/C01/T1')
.filterBounds(point)
.filterDate(start, finish)
.sort('CLOUD_COVER', true);
这个Collection可以很安全地被展示并检查,当然,如果Collection中图像数量太多,可能会很慢,可能会时间超限,甚至可能返回一个error。可以把Collection视为一个列表,使用下面的方法观察第一张图:
var first = filteredCollection.first();
自己可以创建一些过滤器,操作如下:
// Load a feature collection.
var featureCollection = ee.FeatureCollection('TIGER/2016/States');
// Filter the collection.
var filteredFC = featureCollection.filter(ee.Filter.eq('NAME', 'California'))
// Display the collection.
Map.addLayer(filteredFC, {}, 'California');
可以在编辑器上的Get Link按钮获得运行代码的一个唯一URL,方便分享或再次使用。
在Band上执行一些数学操作
使用Image里的方法做一些数学性的操作,包括波段重组、图像区分或是其他数学的运算,举个例子,计算一下NDVI在20年间的变化:
// This function gets NDVI from Landsat 5 imagery.
var getNDVI = function(image) {
return image.normalizedDifference(['B4', 'B3']);
};
// Load two Landsat 5 images, 20 years apart.
var image1 = ee.Image('LANDSAT/LT05/C01/T1_TOA/LT05_044034_19900604');
var image2 = ee.Image('LANDSAT/LT05/C01/T1_TOA/LT05_044034_20100611');
// Compute NDVI from the scenes.
var ndvi1 = getNDVI(image1);
var ndvi2 = getNDVI(image2);
// Compute the difference in NDVI.
var ndviDifference = ndvi2.subtract(ndvi1);
这里使用了用户自己定义的函数,其他的函数在下一部分介绍。
重复测绘工作(拒绝循环程序)
使用map()
函数做重复测绘,不要用循环。这个函数可以用在ImageCollection
、FeatureCollection
或是一个list
里。示例代码把NDVI增加到ImageCollection里的每一张图像上:
// This function gets NDVI from Landsat 8 imagery.
var addNDVI = function(image) {
return image.addBands(image.normalizedDifference(['B5', 'B4']));
};
// Load the Landsat 8 raw data, filter by location and date.
var collection = ee.ImageCollection('LANDSAT/LC08/C01/T1')
.filterBounds(ee.Geometry.Point(-122.262, 37.8719))
.filterDate('2014-06-01', '2014-10-01');
// Map the function over the collection.
var ndviCollection = collection.map(addNDVI);
另一个共同的任务是把一些东西增加到特征中,下面的实例就这样做了:
var sum = ee.Number(feature.get('property1')).add(feature.get('property2'))
return feature.set({'sum': sum}); };
// Create a FeatureCollection from a list of Features.
var features = ee.FeatureCollection([
ee.Feature(ee.Geometry.Point(-122.4536, 37.7403),
{property1: 100, property2: 100}),
ee.Feature(ee.Geometry.Point(-118.2294, 34.039),
{property1: 200, property2: 300}),
]);
可以像下面这样吧Collection的类型修改掉:
// This function returns the image centroid as a new Feature.
var getGeom = function(image) {
return ee.Feature(image.geometry().centroid(), {foo: 1}); };
// Load a Landsat 8 collection.
var collection = ee.ImageCollection('LANDSAT/LC08/C01/T1')
.filterBounds(ee.Geometry.Point(-122.262, 37.8719))
.filterDate('2014-06-01', '2014-10-01');
// Map the function over the ImageCollection.
var featureCollection = ee.FeatureCollection(collection.map(getGeom));
// Print the collection.
print(featureCollection);
注意下那个foo
,对每一个图像的中心它都被创建了。最后一行里我们把结果变成了一个FeatureCollection
。
缩合
在GEE中,缩合是一种通过时间、空间、波段、数组或者其他数据结构将数据聚合在一起的一种方式,在API中,实现这一目的有多种方式。举个例子,如果想聚合成一个ImageCollection,可以使用reduce()
函数将一个collection中的图像聚合成一张。这里有一个代码示例,把早就载入的Landsat-8卫星数据进行聚合,聚合的内容是至少五张无云的图像:
// Load a Landsat 8 collection.
var collection = ee.ImageCollection('LANDSAT/LC08/C01/T1')
// Filter by date and location.
.filterBounds(ee.Geometry.Point(-122.262, 37.8719))
.filterDate('2014-01-01', '2014-12-31')
// Sort by increasing cloudiness.
.sort('CLOUD_COVER');
// Compute the median of each pixel for each band of the 5 least cloudy scene
var median = collection.limit(5).reduce(ee.Reducer.median());
缩合也是一种得到区域内图像统计信息的操作,这个任务是把感兴趣的区域内的像素点逐个进行处理,使用reducRegion()
函数完成这一操作:
// Load and display a Landsat TOA image.
var image = ee.Image('LANDSAT/LC08/C01/T1_TOA/LC08_044034_20140318');
Map.addLayer(image, {bands: ['B4', 'B3', 'B2'], max: 0.3});
// Create an arbitrary rectangle as a region and display it.
var region = ee.Geometry.Rectangle(-122.2806, 37.1209, -122.0554, 37.2413);
Map.addLayer(region);
// Get a dictionary of means in the region. Keys are bandnames.
var mean = image.reduceRegion({
reducer: ee.Reducer.mean(),
geometry: region,
scale: 30
});
关于缩合的具体信息,请看它的文档。
蒙版
在ee.Image
中的每一个像素,都是既包含了值,有包含了一个范围从0到1取值的蒙版的实体,如果蒙版为0,那么就代表这个点完全被挡住了,GEE直接当做没有数据来处理,当蒙版取0到1之间其他值时,就把它当作参与数值计算的一个权值。
用户可以使用蒙版操作做像素转换或者排除它们,如上文所述,蒙版设置为0时意味着这个像素点被挡住了,继续看使用蒙版操作的代码实例:
// This function gets NDVI from Landsat 5 imagery.
var getNDVI = function(image) {
eturn image.normalizedDifference(['B4', 'B3']);
};
// Load two Landsat 5 images, 20 years apart.
var image1 = ee.Image('LANDSAT/LT05/C01/T1_TOA/LT05_044034_19900604');
var image2 = ee.Image('LANDSAT/LT05/C01/T1_TOA/LT05_044034_20100611');
// Compute NDVI from the scenes. var ndvi1 = getNDVI(image1);
var ndvi2 = getNDVI(image2);
// Compute the difference in NDVI.
var ndviDifference = ndvi2.subtract(ndvi1);
// Load the land mask from the SRTM DEM.
var landMask = ee.Image('CGIAR/SRTM90_V4').mask();
// Update the NDVI difference mask with the land mask.
var maskedDifference = ndviDifference.updateMask(landMask);
// Display the masked result.
var vizParams = {min: -0.5, max: 0.5, palette: ['FF0000', 'FFFFFF', '0000FF']
Map.setCenter(-122.2531, 37.6295, 9);
Map.addLayer(maskedDifference, vizParams, 'NDVI difference');
这个例子里,注意一下NDVI中的蒙版,它用updataMask()
函数做过一次更新。
蒙版操作对于把一些数据从分析范围排除出去也是很重要的操作,在它的文档可以看到更多实例。
下面的例子做了多种操作:过滤、重复测绘、缩合还有云层蒙版之类的:
// This function gets NDVI from a Landsat 8 image.
var addNDVI = function(image) {
return image.addBands(image.normalizedDifference(['B5', 'B4']));
};
// This function masks cloudy pixels.
var cloudMask = function(image) {
var clouds = ee.Algorithms.Landsat.simpleCloudScore(image).select(['cloud'])
return image.updateMask(clouds.lt(10)); };
// Load a Landsat collection, map the NDVI and cloud masking functions over i
var collection = ee.ImageCollection('LANDSAT/LC08/C01/T1_TOA')
.filterBounds(ee.Geometry.Point([-122.262, 37.8719]))
.filterDate('2014-03-01', '2014-05-31')
.map(addNDVI)
.map(cloudMask);
// Reduce the collection to the mean of each pixel and display.
var meanImage = collection.reduce(ee.Reducer.mean());
var vizParams = {bands: ['B5_mean', 'B4_mean', 'B3_mean'], min: 0, max: 0.5};
Map.addLayer(meanImage, vizParams, 'mean');
// Load a region in which to compute the mean and display it.
var counties = ee.FeatureCollection('TIGER/2016/Counties');
var santaClara = ee.Feature(counties.filter(ee.Filter.eq('NAME', 'Santa Clara'),
Map.addLayer(santaClara);
// Get the mean of NDVI in the region.
var mean = meanImage.select(['nd_mean']).reduceRegion({
reducer: ee.Reducer.mean(),
geometry: santaClara.geometry(),
scale: 30
});
// Print mean NDVI for the region. mean.get('nd_mean').evaluate(function(val){
print('Santa Clara spring mean NDVI:', val);
});