注意:本教程不包括如何申请谷歌账号,如何打开地球引擎以及如何开启谷歌地球引擎账号,请自行访问谷歌地球引擎:
https://earthengine.google.com/
Part 1 编程和遥感基础知识
为了更好地使用地球引擎,您需要学会遥感和编程的基本技能。本书的编程语言是 JavaScript,你将首先学习如何使用它来操作变量。在此基础上,你将学习查看单个卫星图像,在地球引擎中查看图像集合,以及常见的遥感术语在地球引擎中是如何被引用和使用的。
1. JavaScript 和地球引擎(Earth Engine) API
原作者:Ujaval Gandhi
概述
本章介绍了谷歌地球引擎应用程序编程接口(API)以及使用它所需的 JavaScript 语法。你将了解代码编辑器环境,并熟悉键入、运行和保存脚本。你还将学习 JavaScript 语言的基础知识,如变量、数据结构和函数。
学习目标
• 熟悉地球引擎代码编辑器。
• 熟悉 JavaScript 语法。
• 能够从代码编辑器使用地球引擎 API 函数。
假设你已经知道如何:
• 注册地球引擎账户(详见谷歌文档)。
• 访问地球引擎代码编辑器(详见谷歌文档)。
1.1 理论介绍
地球引擎 API
谷歌地球引擎是一个用于科学数据分析的基于云的平台。它提供了随时可用的、云托管的数据集和一个大型服务器池。地球引擎特别有吸引力的一个特点是能够通过在大型服务器池中分布计算来非常快速地运行大型计算。通过地球引擎 API 实现了高效利用云托管数据集和计算的能力。
API 是与地球引擎服务器通信的一种方式。它允许你指定你想要进行的计算,然后接收结果。API 的设计使得用户不需要担心计算是如何在一组机器上分布的,以及结果是如何组装的。API 的用户只需指定需要做什么。这通过向用户隐藏实现细节大大简化了代码。它也使地球引擎对于不熟悉编写代码的用户非常容易接近。
地球引擎 API 被设计为与语言无关。谷歌提供了官方的客户端库,以便从 JavaScript 和 Python 使用该 API。无论你使用哪种编程语言,API 的使用方法基本保持不变。主要的区别在于调用 API 函数所使用的语法。一旦你学会了编程语言的语法,你的代码可以很容易地进行调整,因为它们都使用相同的 API 函数。
为什么选择 JavaScript
对于许多研究人员和数据科学家来说,JavaScript可能不是首选编程语言,有些人可能想知道为什么这本书是基于 JavaScript API 而不是 Python 或 R。
地球引擎 JavaScript API 在刚开始时是最成熟和最容易使用的。地球引擎平台带有一个基于网络的代码编辑器,允许你在无需任何安装的情况下开始使用地球引擎 JavaScript API。它还提供了额外的功能来在地图上显示你的结果、保存你的脚本、访问文档、管理任务等等。它有一个一键式机制与其他用户分享你的代码——便于轻松重现和协作。此外,JavaScript API 带有一个用户界面库,帮助你省力地创建图表和基于网络的应用程序。
实际上,你不需要成为一个JavaScript 专家来使用地球引擎。这里介绍的基本语法应该就足够了。一个好建议是,如果你平时用JavaScript很难实现一些操作,那么你会发现在地球引擎中可能会容易许多。地球引擎中所有重要的计算都需要使用 API 函数,甚至一个基本操作——比如在地球引擎中计算加两个数相加——都应该使用地球引擎 API 来完成。
1.2 实操
1.2.1 第 1 部分:代码编辑器入门
代码编辑器是地球引擎 JavaScript API 的集成开发环境。它提供了一种简单的方式来键入、调试、运行和管理代码。按照 Google 关于注册 Earth Engine 帐户的文档进行操作后,你应该按照文档打开代码编辑器。当你首次访问代码编辑器时,你将看到一个如图 1.1 所示的屏幕。代码编辑器(图 1.1)允许你输入 JavaScript 代码并执行它。当你刚开始学习一门新语言并适应一个新的编程环境时,通常会制作一个显示“Hello World”字样的程序。这是一个开始编码的有趣方式,它向你展示了如何向程序提供输入以及如何执行它。它还展示了程序显示输出的位置。在 JavaScript 中做这个非常简单。将以下代码复制到中心面板中。
print('Hello World');
图1. 1代码编辑器
图1. 2 输入并运行代码
上面的代码行使用JavaScript print 函数将文本“Hello World”打印到屏幕上。输入代码后,单击“运行”按钮。代码将会输出显示在控制台选项卡下的右上面板上(图 1.2)。现在,您知道在何处键入代码、如何运行代码以及在何处查找输出。您刚刚编写了第一个Earth Engine 脚本,可能想要保存它。单击“save”按钮(图 1.3)。如果这是你第一次使用代码编辑器,会弹出一个窗口,提示创建一个主文件夹。这是云端的一个文件夹,你所有的代码都将保存在这里。你可以选择一个你喜欢的名字,但要记住它不能被更改,并且将永远与你的账户相关联。用你的谷歌账户用户名作为文件夹名字或许是个不错的选择(图 1.4)。创建个人文件夹后,系统将提示您输入新的存储库。存储库可以帮助您组织和共享代码。您的帐户可以有多个存储库,每个存储库内部可以保存多个脚本。首先,您可以创建一个名为“default”的存储库(图 1.5)。最后,您将能够将脚本保存在新创建的文件夹中。输入名称“hello_world”,然后单击“确定”(图 1.6)。脚本保存在云端,当你打开代码编辑器时总是可以供你使用。现在,你应该熟悉如何在代码编辑器中创建、运行和保存脚本,准备好开始学习 JavaScript 的基础知识。
图1. 3 保存脚本
图1. 4 创建主文件夹
图1. 5 创建新的储存库
图1. 6 以文件形式保存
图1. 7 脚本管理器面板(你的脚本保存在这个地方)
1.2.2 第 2 部分 JavaScript基础知识
为了能够为你的分析构建脚本,你需要使用 JavaScript。这一部分涵盖了 JavaScript 的语法和基本数据结构。在接下来的部分,你将看到更多标有独特字体和阴影背景的 JavaScript 代码。当你遇到代码时,将其粘贴到代码编辑器并运行脚本。
变量
在编程语言中,变量用于存储数据值。在JavaScript 中,使用“var”关键字后接变量的名称来定义变量。下面的代码将文本“San Francisco”分配给名为“city”的变量(就是定义city为San Francisco)。注意代码中的文本字符串应该用引号括起来。你可以自由使用单引号(')或双引号("),并且它们在每个字符串的开头和结尾必须匹配。在你的程序中,最好保持一致——在给定的脚本中始终使用单引号或双引号(本书中的代码通常在代码中使用单引号)。你的脚本的每个语句通常应该以分号结尾,尽管地球引擎的代码编辑器并不要求这样做。(注意:不要使用中文引号。同样的,在编程中所有符号都要使用英文符号)
var city = 'San Francisco';
如果你打印变量“city”,你将在控制台中得到存储在该变量(“San Francisco”)中的值被打印出来
print(city);
当你分配一个文本值时,该变量会自动被分配为字符串类型。你也可以给变量分配数字,并创建数字类型的变量。下面的代码创建了一个名为“population”的新变量,并为其分配了一个数字作为值
var population = 873965;
print(population);
列表
能够在一个单一变量中存储多个值是很有用的。JavaScript 提供了一种叫做列表的数据结构,它可以存储多个值。我们可以使用方括号 [] 并添加用逗号分隔(,)的多个值来创建一个新列表
var cities = ['San Francisco', 'Los Angeles', 'New York', 'Atlanta'];
print(cities);
如果你查看控制台中的输出,你会看到“列表”以及旁边带有一个展开箭头(▷)。点击该箭头将展开列表并向你展示其内容。你会注意到,除了列表中的四个项目外,每个值旁边都有一个数字。这是每个项目的索引。它允许你使用一个表示其在列表中位置的数字值来指代列表中的每个项目(图 1.8)。
图1. 8 JavaScript的列表
对象
列表允许你在一个单一的容器变量中存储多个值。虽然很有用,但它不太适合存储结构化数据。能够通过名称而不是位置来指代每个项目是很有帮助的。JavaScript 中的对象允许你存储键值对(键值对key-value,顾名思义,每一个键会对应一个值。),其中每个值都可以通过其键来指代。你可以使用花括号 {} 创建一个字典。下面的代码创建了一个名为“cityData”的对象,其中包含一些关于旧金山的信息。
在这里注意关于 JavaScript 语法的几个重要事项。首先,我们可以使用多行来定义对象。只有当我们放入分号(;)时,该命令才被认为是完整的。这有助于格式化代码使其更具可读性。还要注意变量名“cityData”的选择。这个变量包含两个单词。第一个单词是小写,第二个单词的首字母大写。这种将多个单词组合成一个单一变量名的命名方案被称为“驼峰命名法”。虽然不强制使用这种方案来命名你的变量,但遵循它被认为是一个好的实践。地球引擎 API 中的函数和参数遵循这个约定,所以如果你也遵循它,你的代码将会更具可读性。
var cityData = {
'city':'San Francisco',
'coordinates':[-122.4194, 37.7749],
'population':873965
};
print(cityData);
该对象将在控制台中被打印出来。你可以看到,每个项目不是有一个数字索引,而是有一个标签。这被称为键,并且可以用来检索一个项目的值(图 1.9)。
图1. 9 JavaScript对象
函数
在使用地球引擎时,你将需要定义自己的函数。函数接受用户输入,使用它们进行一些计算,并返回一个输出。函数允许你将一组操作组合在一起,并对不同的参数重复相同的操作,而不必每次都重新编写它们。函数使用“function”关键字来定义。下面的代码定义了一个名为“greet”的函数,它接受一个名为“name”的输入,并返回一个以“Hello”为前缀的问候语。注意,我们可以用不同的输入来调用这个函数,它会用相同的代码生成不同的输出(图 1.10)。
var greet = function(name)
{
return 'Hello ' + name;
};
print(greet('World'));
print(greet('Readers'));
图1. 10 JavaScript函数输出
注释
在编写代码时,添加一些文本来解释代码或给自己留个便签是很有用的。在代码中始终添加注释来解释每一步是一个好的编程习惯。在 JavaScript 中,你可以在任何一行前面加上两个正斜杠 // 使其成为注释。注释中的文本将被解释器忽略,不会被执行。(注释可以写中文,因为注释不会被运行)
// This is a comment!
//这是一个注释!
代码编辑器还提供了一个快捷键——在 Windows 上是 Ctrl + /,在 Mac 上是 Cmd + /——可以一次对多行进行注释或取消注释。你可以选择多行并按下这个组合键使它们都成为注释。再次按下可取消注释操作。这在调试代码以阻止脚本的某些部分被执行时很有帮助(图 1.11)。
恭喜!你已经学习了足够的 JavaScript 知识,能够使用地球引擎 API 了。在下一节中,你将看到如何使用JavaScript 访问和执行地球引擎 API 函数。
图1. 11 多行注释
代码检查点 F10a
这本书的资源库包含一个脚本,展示了在这一点上你的代码应该是什么样子。
1.2.3 第三部分:地球引擎API基础
地球引擎 API 非常广泛,提供了从简单数学到用于图像处理的高级算法等各种对象和方法。在代码编辑器中,你可以切换到“文档”(Docs)选项卡,查看按对象类型分组的 API 函数。API 函数带有前缀“ee”(代表地球引擎Earth Engine)(图 1.12)。
让我们学习使用这个 API。假设你想要将由变量 a 和 b 表示的两个数字相加,如下所示。创建一个新脚本并输入以下内容:
var a = 1;
var b = 2;
在1.2.1 中,你学习了如何将数字存储在变量中,但没有学习如何进行任何计算。这是因为当你使用地球引擎时,你不是使用 JavaScript 运算符进行加法运算。例如,你不会写“var c = a + b”来将这两个数字相加。相反,地球引擎 API 为你提供了进行此操作的函数,并且重要的是,无论何时你都要使用 API 函数。
图1. 12 地球引擎API docs
一开始这可能看起来有点别扭,但使用这些函数,正如我们将在下面描述的,将帮助你避免浪费时间并创建高效的代码。
查看“文档”(Docs)选项卡,你会找到一组可以在 ee.Number 上调用的方法。展开它以查看可用于处理数字的各种函数。你会看到创建地球引擎数字对象的ee.Number 函数,该函数从一个值创建。在函数列表中,有一个用于将两个数字相加的加法函数。这就是你用来将 a 和 b 相加的那个(图 1.13)。
图1. 13 数字模块
为了将 a 和 b 相加,我们首先用 ee.Number(a)从变量 a 创建一个 ee.Number 对象。然后我们可以使用 add(b)调用将 b 的值添加到它上面。下面的代码展示了语法并打印出结果,当然,结果是 3。
以下是相应的代码示例:
var result = ee.Number(a).add(b);
print(result);
到现在,你可能已发现,当学习在地球引擎中编程时,你不需要深入学习 JavaScript 或 Python——相反,它们是访问地球引擎 API 的方式。无论从 JavaScript 还是 Python 调用,这个 API 的用法都是一样的。
这里有另一个例子来强化这一点。假设你正在处理一项任务,需要创建一个从 1980 年到 2020 年以 5 年为间隔的年份列表。如果你面临这个任务,第一步是切换到“文档”(Docs)选项卡并打开 ee.List 模块。浏览这些函数,看看是否有任何函数可以提供帮助。你会注意到一个函数 ee.List.sequence。点击它将弹出该函数的文档(图 1.14)。
图1. 14 ee.List.sequence函数
函数 ee.List.sequence 能够从给定的起始值到结束值生成一系列数字。它还有一个可选参数步长来指示每个数字之间的增量。我们可以通过使用以下值调用这个预定义函数来创建一个表示从 1980 年到 2020 年、以 5 为步长的数字的 ee.List:起始值(start)=1980,结束值(end)=2020,步长(step)=5。(“步长”指的是在生成序列时,相邻两个数字之间的间隔大小。比如这里从 1980 开始,以步长 5 来生成序列,那么下一个数字就是 1985,再下一个是 1990,依次类推,直到达到或超过结束值 2020。步长决定了序列中数字递增或递减的幅度。)
以下是相应的代码示例:
var yearList = ee.List.sequence(1980, 2020, 5);
print(yearList);
图1. 15 ee.List.sequence函数的输出
控制台中打印的输出将显示变量 `yearList` 确实包含具有正确间隔的年份列表(图 1.15)。你刚刚在地球引擎 API 的帮助下完成了一个中等复杂程度的编程任务。
代码检查点 F10b
这本书的代码库包含一个脚本,展示了在这一点上你的代码应该是什么样子的。
1.3 综合练习
任务1. 假设在下面的代码中定义了以下两个字符串变量。使用地球引擎 API 通过组合这两个字符串来创建一个名为结果的新字符串变量。在控制台中打印它。打印的值应该读作“Sentinel2A”。
var mission = ee.String('Sentinel');
var satellite = ee.String('2A');
提示:使用 ee.String 模块中的 cat 函数来“连接”(concatenate,组合在一起)这两个字符串。你将在代码编辑器的“文档”选项卡中找到关于所有可用函数的更多信息(图 1.16)。
图1. 16
1.4 总结
这一章介绍了地球引擎 API。你还学习了 JavaScript 语法的基础知识,以便能够在代码编辑器环境中使用该 API。我们希望你现在在开始成为地球引擎开发者的旅程时感觉稍微更自在一些。无论你的编程背景或对 JavaScript 的熟悉程度如何,你都有可供使用的工具来开始使用地球引擎 API 构建用于遥感分析的脚本。