注:项目距今一年了,部分代码缺失没办法
笔者之前从未接触google earth engine (GEE),网上资料也不是很多,而GEE python的内容更是少之又少。尽管如此,许多不计报酬,无私分享的同志依然给我带来很大的帮助。吃水不忘打井人,我会尽量把我在GEE python的实践经验发出来。下面我以我的项目为例,与大家交流GEE python制作App并部署的方法。
我的实践项目是:编写可以对任意圈取区域的归一化植被指数(NDVI)进行分析的App,并使用Heroku平台或者以自己的电脑为主机部署App。
注:以下内容基于鄙人粗浅的学识,错误不可避免,还请有识之士评论纠正
磨刀不误砍柴功,我斗胆向各位推荐一些好用的工具,网址,值得学习的视频资料。
1.英文翻译工具:copytranslator
和谷歌生草机不一样,它的翻译非常自然准确,而且两种语言多次互相转译依然保持准确。学习GEE常常要看英文资料,用这个可以消除语言障碍。
2.常用的资源
链接: geemap指南.
链接: geemap作者的视频教程.
链接: 区域数值统计(均值,最大值等等).
我比较常用这些
3.geemap
geemap是吴秋生教授开发的包,专门用于python语言。(吴教授还会解答相关的问题,我厚脸皮发邮件问过,教授真的回复我了。)但是要注意,geemap适用于ipynb文件,就是jupyter notebook格式的文件,直接用py文件写应该是看不到地图的。geemap我会详细介绍。
背景我就不说了,没什么意义。要强调的有三点:
a.GEE python相比于GEE JavaScript没有ui类,其它基本类似。所以绘制ui我们要求助于第三方库。下面是java版的API(这图不是我的,侵删):
b.GEE python没有直接部署App的功能,GEE JavaScript代码是可以用App功能直接部署到GEA上的。所以部署App我们选择Heroku平台或者也可以建立服务器。
c.geemap不能用py文件直接编写。
0.Map类:就是地图,但是geemap的地图基于ipyleaflet,ipywidgets所以不能直接在.py中使用
1.Image类:影像,所有卫星拍摄的影像,都是以Image类进行处理的。不同数据集有不同的属性,但是一般波段(Bands)属性。一张影像是由不同的波段构成的,比如红光(R),近红外光(NIR)。除此之外还有含云量等等。影像的属性是我们数据处理的关键。
查看方法:
2.ImageCollection类:从官方发布的文档来看,ImageCollection是由Image构成的列表或队列。但起始不能像列表,队列一样索引,删除,插入,添加等。即使有collection2list函数,返回的也只是名称的列表而已。
3.Geometry类:几何类,地图上的几何图形,可以覆盖想要的区域。点,线,多边形,圆等等。
1.导入地图
import ee
import geemap
myMap = geemap.Map()
myMap
2.导入数据集
S2 = ee.ImageCollection('COPERNICUS/S2')##哨兵2号数据集
#多边形,还有其它类型,不一一列举
ROI = ee.Geometry.Polygon( [[[116.942508, 30.41973],
[116.942508, 30.638437],
[117.215907, 30.638437],
[117.215907, 30.41973],
[116.942508, 30.41973]]])
myMap.addLayer(ROI)#可以加入调色盘和名称,默认黑色
addLayer()可以接受影像,影像集,几何图形,矢量图等
效果:
4.引入矢量图
首先你需要有矢量图资源,具体请自行搜索,有很详细的代码,可以裁剪出城市,省份,国家等
5.裁剪(clip())
Image.clip(ROI)#裁剪出影像ROI的部分
如上所示
from ipyleaflet import WidgetControl,Marker,Popup
marker = Marker(location = (0,0),
draggable=True,)
'''
1.查看Image,ImageCollection等信息用getInfo,不用这个是看不到信息的,返回字典
2.marker初始坐标location 是元组,注意不要把横纵坐标填反
3.可拖拽
'''
message1 = HTML()
marker.popup = message1#弹出信息
myMap.add_layer(marker)
popup = Popup(
location=marker.location,
child=message1,
close_button=False,
auto_close=False,
close_on_escape_key=False
)
#事件响应,这里是弹出marker坐标
def get_callback(marker, html,popup):
def callback(*args, **kwargs):
html.value = '''
marker location:
{}
'''.format(marker.location)
popup.location = marker.location
ndvi_point(marker)
return callback
#不同事件类型
marker.on_click(get_callback(marker, message1,popup))#添加点击事件
#marker.on_mouseover(get_callback(marker, message1,popup))
print(marker.location),你可以用任何方法使用marker所在坐标
链接: Filter 使用指南.
1.按日期筛选
2.按位置筛选
3.按元数据筛选
数据集(COPERNICUS/) | 日期 | 含云量 | 数据集大小 |
---|---|---|---|
S2 | - - | - - | 极大 |
S2 | 18/01/01~02/01 | - - | 降低 |
S2 | - - | <20 | 降低 |
S2 | 18/01/01~02/01 | <20 | 适合处理 |
数据处理之前,建议先筛选出感兴趣的数据,减小运算量。
1.QA60去云
def rmcloud(img):
#去云方法,适用哨兵2号数据。不透明云层和卷云的属性分别是QA60的第10,11号比特位0表示无,1表示有。含云量的属性是CLOUDY_PIXEL_PERCENTAGE。
qa=img.select('QA60')
cloud1=1<<10
cloud2=1<<11
mask = qa.bitwiseAnd(cloud1).eq(0).And(qa.bitwiseAnd(cloud2).eq(0))
return img.updateMask(mask).divide(10000).select("B4","B8").copyProperties(img, ["system:time_start"])
2.云概率文件去云
可以参考知乎或者csdn的文章,我就不便发出了
参考: 知乎 基于sentinel的去云方案对比评估.
但是JavaScript
缩略图指的是:
在GEE JavaScript中缩略图可以用ui.Thumbnail()获取,但是之前提到过,python版没有ui类,python可以考虑用
geemap.ee_export_image()
imageio,制作动图很方便
动图指的是由缩略图制作的gif:
tif是可以在类似Arcmap的软件上进行分析的。
tif:
不能上传原图,截图将就下。
1.使用matplotlib制作图表
在这里插入代码片
2.直接将图表显示在地图上
在这里插入代码片
3.geemap自带功能
1.NDVI(归一化植被指数)的计算方法:
def ndvi_img(img):
#加工原图像成为ndvi图像,将NDVI波段添加至图片
ndvi = img.normalizedDifference(["B8","B4"]).float().rename("NDVI")
ndvi_img = img.addBands(ndvi)
return ndvi_img
2.使用.map()批量处理图片
你可能需要处理一整个数据集
def get_ndvi_collection(start_time,end_time):
try:
no_cloud_S2 = S2.filterDate(start_time,end_time).filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE',20)).map(rmcloud)#选择年份,数据集去云处理
ndvi_list = no_cloud_S2.map(ndvi_img)#转化为ndvi图
vis_params = {
'min': -0.2,
'max': 0.8,
'palette': 'FFFFFF, CE7E45, DF923D, F1B555, FCD163, 99B718, 74A901, 66A000, 529400,' +
'3E8601, 207401, 056201, 004C00, 023B01, 012E01, 011D01, 011301'}
ROI_ndvi = ndvi_list.select("NDVI").map(clip)#ndvi图片裁剪出合肥地区
return ROI_ndvi
except:
return None
3.Reducer
4.geemap中区域统计数值方法
视频参考: GEE教程第12期: Computing zonal statistics with Earth Engine.
5.geemap自带功能
视频参考: GEE教程第11期:Exporting Earth Engine Image and ImageCollection.
视频参考: GEE教程第40期:如何添加交互式控件到地图上.
对于控件较多的App,我推荐Tab控件,可以更好管理界面
tab_contents = ['第1页', '第2页','地图']
tool1 = widgets.VBox()
tool2 = widgets.VBox()
children = [tool1,tool2,myMap]
tab = widgets.Tab()
tab.children = children
for index,i in enumerate(tab_contents):
tab.set_title(index,i) # 需要索引与值两个参数
tab
翻译自:https://help.heroku.com/K1PPS2WM/why-are-my-file-uploads-missing-deleted-from-the-application
Heroku文件系统是短暂的——这意味着在dyno运行时对文件系统的任何更改只会持续到dyno关闭或重新启动。每个dyno都会使用最近部署的文件系统的干净副本启动。这与许多基于容器的系统(如Docker)的运行方式类似。
此外,在正常运行情况下,dynos每天都会重新启动一个称为“循环”的过程。
这两个事实意味着Heroku上的文件系统不适合持久存储数据。在需要存储数据的情况下,我们建议使用数据库插件,如Postgres(用于数据)或专用文件存储服务,如AWS S3(用于静态文件)。如果你不想在AWS上建立一个账户来创建一个S3 bucket,我们这里也有处理静态资产存储和处理的插件https://elements.heroku.com/addons
也就是说,想要长期存储文件——得加钱
你可以使用邮件发送heroku的数据到指定邮箱,写代码可以考虑stmp(如果我没记错的话)
voila(又称Voilà)是构筑web app的捷径。voila会将 Jupyter 笔记本变成独立的 Web 应用程序,这样jupyter代码直接在主机上运行就可以形成app,Voilà 使用 strip_source 选项运行,该选项可以隐藏原始代码。
要注意的是, Voilà 默认不提供作为经典笔记本扩展 (nbextension) 安装的 Jupyter Widget。如果自定义小部件尚未发布到 npm,或者当 Voilà 在没有 Internet 连接的环境中运行时,这可能会导致错误 (404)。所以使用ipywidgets绘制ui时,为了防止界面加载不出来,需要使用命令“voila --enable_nbextensions=True”,支持扩展。
如果你不想用heroku,转而使用自己的笔记本电脑作为主机。那用volia之后,还需要把app发布出来。nigrok可以解决此问题。但是ngrok使用成本高,只是想做个小项目或者糊弄毕设完全不需要。你就可以使用小米球作为替代,一杯可乐钱就ok。
为了与voila功能配合,先使用voila – port = ,将Web App运行到端口。再使用ngrok的内网穿透,就可以完成App的本地服务器部署
具体的部署方法可以参考上面链接中的up,因为时间相距太久具体的部署我已经忘记了。