【笔记】GEE之python学习

GEE之python环境配置

首先需要vpn和注册GEE账号[参考]

  1. 安装python和pip(略);安装Google的 python API的客户端,命令行如下:pip install google-api-python-client

  2. 安装鉴权验证依赖库:pip install pycryptodomex

  3. 安装GEE的python库:pip install earthengine-api

  4. 第一次运行GEE需要先验证GEE账户,命令行运行如下:earthengine authenticate或者ee.Authenticate()
    如果出现gcloud command not found的错误,该用earthengine authenticate --auth_mode=notebook进行验证(有效期1周)

  5. 运行、初始化GEE,检查本地环境是否搭建完成:python -c “import ee; ee.Initialize()”
    这一步因为开了VPN,要设置代理:

import ee,os
os.environ['HTTP_PROXY'] = 'http://127.0.0.1:41091'
os.environ['HTTPS_PROXY'] = 'http://127.0.0.1:41091'
ee.Initialize()

代理的地址在 “设置->网络和internet->代理” 查看地址和端口。

注:其中可能遇到 “[WinError 10060] 由于连接方在一段时间没有正确答复…” 问题。一方面检查注册账号是否授权,电脑用户名中文也有可能造成问题。另一方面,检查科学上网软件应该是全局模式

  1. jupyter lab
    我原先用的sublimetext,不方便直观的看到数据,更不方便调用地图窗口了,故转而使用jupyter lab。
    在cmd输入:pip install jupyter,pip install jupyter lab

运行GEE时最好开全局代理

学习

数据格式

.getInfo()可以把gee的数据格式转为正常的格式,比如我想遍历遥感影像
在gee平台使用java语句或者在python api循环一个影像集或者一个list,需要获取尺寸size,col.size(),但是这样返回的默认是ee.Number数据格式,是没法用GEE文档中以外的其它的方法遍历的,大家一般推荐的是GEE里面的map(),iterate(),但是有时候这个方法仍然有局限性。所以使用col.size().getInfo()即可。

Task

将矢量导出到asset或者Google drive 的时候,需要使用task,在GEE的java里面使用task,需要在右侧边栏查看task执行情况。对于python的API执行task时,会在GEE中同时开启任务。

保存矢量shp

  1. 导入:本地shp到asset
    直接在GEE里面操作手动添加就好了

  2. 导出:roi到drive,再下载到本地

    在GEE中画出roi中会出现这个,在GEE执行下面的代码将roi导出到drive。
    在这里插入图片描述

var roi = /* color: #98ff00 */ee.FeatureCollection([geometry]); 
//导出的格式写为SHP
Export.table.toDrive({
  collection:roi,
  description: "341521",
  fileNamePrefix: "341521",
  fileFormat: "SHP",
  folder:'earthengine'
});
  1. GEEroi到asset
    Google drive通过谷歌账号可以直接获取15G免费存储空间,Assests是GEE资源存放位置,它里面的资源是可以直接在GEE工作空间中使用,每个用户空间限制是250G,显然选择导入到GEE容量更大。
Export.table.toAsset({
  collection:roi,
  description: "tth_brg",
  assetId:'users/2393251747/tth_brg'
});

保存img影像

  1. 保存img到asset
  2. 保存img到本地
    分为从asset到本地,或者pythonAPI直接到本地。

Map()

map()函数在GEE和在python里面的概念是一致的,即遍历一个序列里面的每一个元素,对这些元素进行操作,然后返回一个新的序列。
例下,完成对影像集里面每一幅图的裁剪,从而形成新的裁剪后的影像集:

def clip(image):
    return image.clip(aoi)
aoi_pnts=[[[114.09269762083298, 30.356153799649764],
           [114.09269762083298, 30.318818747475646],
           [114.12977647825485, 30.318818747475646],
           [114.12977647825485, 30.356153799649764]]]
aoi = ee.Geometry.Polygon(aoi_pnts)
roi=ee.FeatureCollection(aoi)

L8_col = ee.ImageCollection('LANDSAT/LC08/C01/T1_SR').filterBounds(roi).filter(ee.Filter.calendarRange(2012,2013,'year')).filter(ee.Filter.calendarRange(3,11,'month'))
valid_Col = L8_col.map(clip)

属性查询

在python里面用x.get(’…’).getInfo()
'…'可以是的内容通过propertyNames查看
在这里插入图片描述

var list=ee.Dictionary(ee.Dictionary(ee.Algorithms.Describe(image)).get('properties'))
print(list)
print(list.get('REFLECTIVE_LINES'))
//pretty code
var bandList = ee.List(ee.Dictionary(ee.Algorithms.Describe(image)).get('bands'));
var b1 = ee.Dictionary(bandList.get(0));  
print(b1)
var dimensions = b1.get("dimensions");
dimensions = ee.List(dimensions);
print("dimensions", dimensions);
var sizex = ee.Number(dimensions.get(0));
var sizey = ee.Number(dimensions.get(1));
print("sizex", sizex);
print("sizey", sizey);
var crs_transform = b1.get("crs_transform");
print("crs_transform", crs_transform);
  1. 新建属性
  2. 设置属性值

制作GIF

有了裁剪过后的影像集,只需要调用getVideoThumbURL()函数就可以得到动图,点开打印的链接就可以看到了。

def mk_gif(collection):
    visParams = {'bands':['B4','B3','B2'],'min':0,'max':2000}
    url=collection.getVideoThumbURL(visParams)
    print(url)
    return url

请添加图片描述

这个是我做的一个gif,这里面的标签是怎么添加的呢?原本生成的动图里面是没有标签的,我在用影像集生成gif的时候同时把影像集的index保存到本地txt里面,就用下面这个代码:

indexList = collection.reduceColumns(ee.Reducer.toList(), ["system:index"]).get("list")
save_date=indexList.getInfo()
File = open(r"C:\Users\23932\Desktop\hello.txt", "w")
for date in save_date:
    File.write(str(date) + ";")
File.close()

有了标签index序列之后,我用了这位的代码(python给gif添加文本),他是用的PIL库做的。我在这里设置的帧率0.5(每2秒一幅图),文本颜色白色。

可以看到这个位置的江心洲和心滩,5~10月的心滩都基本处于淹没状况,而江心洲出露面积基本无变化。

给影像集排序

按时间排序

col.sort(‘system:time_start’,True)
设置true的话是升序,false就是降序。

按裁剪区域的云量排序

首先制作裁剪后的数据集
然后写个函数用于计算一幅图的云量并同时设置为‘cloudcover’的值
最后排序

img.set(‘start_time’,date);
img.set({ ‘start_time’:date,‘end_time’:date.advance(1,‘month’)});
Img.setMulti({ ‘start_time’:date,‘end_time’:.advance(1,‘month’)});
img.propertyNames()

geemap

https://geemap.org/common/?h=ee_to_numpy#geemap.common.ee_to_numpy

ee_to_numpy

这个函数可以实现影像转numpy,这样很方便将数据放到本地来用python处理。
ee_to_numpy(ee_object, bands=None, region=None, properties=None, default_value=None)
使用它的过程中遇到许多困难

  1. region,它不是要素,而是geometry,这个geometry这样制造:
    首先在GEE中圈出你要的范围,然后在代码框中点击这个在这里插入图片描述
    就可以看见具体geometry的坐标了。
  2. 其次问题是它的region是你范围的最小外接矩形,所以这里还是推荐在GEE先处理成MNDWI再导出。或者直接在GEE完成选择影像,水体提取在python做。
  3. 输入的img包含的波段必须要有同样的空间分辨率
aoi = ee.Geometry.Polygon(
        [[[92.37187894329809, 34.23795235235915],
          [92.37187894329809, 34.22063708300215],
          [92.41633923992894, 34.22063708300215],
          [92.41633923992894, 34.23795235235915]]], None, False);
rgb_img = geemap.ee_to_numpy(img, region = aoi)
  1. 缺陷,这个函数有一个致命的缺陷,它每次导出的数组大小,即aoi最小外接矩形所包含的像元个数必须小于等于262144,下面我写了一个函数来把大的roi切分为若干满足条件的roi:

面积最大来切分

def cut_poly_by_maxarea(pnts,maxarea):
	#pnts=[[x],[y]]
	#1.首先划分aoi
	poly1=Polygon(zip(pnts[0],pnts[1]))
	area=poly1.area
	x,y=list(pnts[0]),list(pnts[1])
	if area>=maxarea:
		#需要切分
		ids=area//maxarea
		cut=(max(x)-min(x))/ids
		sub_aoi,cut_X=[],[]
		cut_x1,cut_x2=min(x),min(x)+cut
		for i in range(int(ids)):
			poly2=Polygon([[cut_x1,max(y)],[cut_x2,max(y)],[cut_x2,min(y)],[cut_x1,min(y)]])
			if not poly1.intersects(poly2):
				cut_X.append(max(x))
				break
			elif poly1.intersection(poly2).area>maxarea:
				small_cut=cut
				while poly1.intersection(poly2).area>maxarea:
					small_cut/=2
					cut_x2=cut_x1+small_cut
					poly2=Polygon([[cut_x1,max(y)],[cut_x2,max(y)],[cut_x2,min(y)],[cut_x1,min(y)]])
				cut_X.append(cut_x2)
			else:
				cut_X.append(cut_x2)
			cut_x1,cut_x2=cut_x2,cut_x2+cut#换到下一个切分区域
	else:pass
	#return aoi,[0,0]
	return cut_X

按最小外接矩形面积最大来切分


def cut_by_max_rectarea(pnts,maxarea):
    def get_pnts(poly):
        #poly是shapely的multipoly或者polygon
        if poly.type=='MultiPolygon':
            xy=[]
            for i in poly:
                xy+=list(zip(*i.exterior.coords.xy))
        else:
            xy=list(zip(*poly.exterior.coords.xy))

        return list(zip(*xy))


    def get_geometries(poly):
        #poly是shapely的multipoly或者polygon
        xy=[]
        if poly.type=='MultiPolygon':
            for i in poly:
                xy.append(list(zip(*i.exterior.coords.xy)))
        else:
            xy.append(list(zip(*poly.exterior.coords.xy)))

        return xy
    #pnts=[[x],[y]]
    #1.首先划分aoi
    poly1=Polygon(zip(pnts[0],pnts[1]))
    [x,y]=get_pnts(poly1)
    area=(max(x)-min(x))*(max(y)-min(y))
    if area>=maxarea:
        #需要切分
        sub_aoi,rel_coor=[],[]
        cut=(max(x)-min(x))/(area//maxarea)
        cut_x1,cut_x2=min(x),min(x)+cut#初始切分区域
        while cut_x1<max(x):
            poly2=Polygon([[cut_x1,max(y)],[cut_x2,max(y)],[cut_x2,min(y)],[cut_x1,min(y)]])
            poly_insec=poly1.intersection(poly2)
            #计算满足条件的最小外接矩形
            [sub_x,sub_y]=get_pnts(poly_insec)
            sub_area=(max(sub_x)-min(sub_x))*(max(sub_y)-min(sub_y))
            if sub_area>maxarea:
                small_cut=cut/sub_area*maxarea*0.9
                while sub_area>maxarea:
                    cut_x2=cut_x1+small_cut
                    poly2=Polygon([[cut_x1,max(y)],[cut_x2,max(y)],[cut_x2,min(y)],[cut_x1,min(y)]])
                    poly_insec=poly1.intersection(poly2)
                    [sub_x,sub_y]=get_pnts(poly_insec)
                    sub_area=(max(sub_x)-min(sub_x))*(max(sub_y)-min(sub_y))
                    small_cut=small_cut*0.9
                else:
                    cut=small_cut/0.9#定下该次的cut
                    sub_aoi.append(get_geometries(poly_insec))
            else:
                large_cut=cut
                while sub_area<=maxarea and cut_x2<max(x):
                    large_cut=large_cut*1.1
                    cut_x2=cut_x1+large_cut
                    poly2=Polygon([[cut_x1,max(y)],[cut_x2,max(y)],[cut_x2,min(y)],[cut_x1,min(y)]])
                    poly_insec=poly1.intersection(poly2)
                    [sub_x,sub_y]=get_pnts(poly_insec)
                    sub_area=(max(sub_x)-min(sub_x))*(max(sub_y)-min(sub_y))
                else:
                    large_cut=large_cut/1.1
                    cut_x2=cut_x1+large_cut
                    poly2=Polygon([[cut_x1,max(y)],[cut_x2,max(y)],[cut_x2,min(y)],[cut_x1,min(y)]])
                    poly_insec=poly1.intersection(poly2)
                    [sub_x,sub_y]=get_pnts(poly_insec)
                    cut=large_cut#定下该次的cut
                    sub_aoi.append(get_geometries(poly_insec))

            cut_x1,cut_x2=cut_x2,cut_x2+cut#换到下一个切分区域
    else:
        #不需要切分
        sub_aoi=[zip(pnts[0],pnts[1])]
    #return aoi,[0,0]
    return sub_aoi
sub_aois=cut_by_max_rectarea(aoi_proj,262144*30**2)

请添加图片描述
上图便是按最小外接矩形面积不大于262144*30**2(分辨率是30m)来切分的结果,之后只需要遍历sub_aois分别来使用ee_to_numpy。

roi的调用

1 可以直接在gee里面画roi,然后代码里面创建geometry,geometry=ee.Geometry.Polygon(pnts)
roi=ee.FeatureCollection(geometry)
2 在gee里面画的roi导入到asset里面,这样代码直接调用
roi=ee.FeatureCollection(”users/xxxxx/xxxxxx”)
geometry=roi.geometry()

根据坐标获取数组

根据遍历multipolygon坐标来提取多个波段数组,可以被用来制作数据集。

工作流

  1. ROI:在GEE里面画roi,导出到GEE的asset,同时取得aoi的坐标放到程序中。
  2. 选择影像:在pythonAPI中筛选计算每幅裁剪影像的云量,并按云量从小到大将影像排序。再依次遍历影像并显示,人工判断是否需要该幅影像。需要的影像img,以txt格式保存影像信息到本地。
  3. 保存影像:把裁剪的影像以npy格式保存到本地,其中aoi比较大的先用我的算法切分为若干个sub_aoi,依次转numpy数组后再组合为完整数组,导出本地为npy文件,命名就是上面的txt命名,同时保存对应的geotrans和proj。不同分辨率的波段影像放在不同的子文件夹下。
  4. 融合:pan_sharpen提高分辨率
  5. 计算MNDWI得到mask
  6. 在本地python直接处理mask.npy。

注:融合在GEE里面我只找到了HSV sharpen,之后可以在本地合成tiff后再用gdal_sharpe

应用

画水系

如果不在线画的话,会需要很多遥感影像来对比着话水系,所以最方便的是在GEE里面直接画roi,然后把roi导入Google Drive再下载到本地。

  • 7
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
GEE(Google Earth Engine)和geemap是一个用于地理空间数据处理和可视化的强大工具。下面是一个简单的教程,介绍如何使用GEEgeemap创建一个简单的交互式地图应用程序。 1. 安装geemap geemap可以通过pip进行安装。在终端或命令行中输入以下命令即可安装geemap: ``` pip install geemap ``` 2. 连接到GEEPython中使用GEE之前,需要连接到GEE。可以使用以下代码进行连接: ```python import ee ee.Authenticate() ee.Initialize() ``` 3. 创建交互式地图 使用geemap可以很容易地创建交互式地图。以下代码将创建一个交互式地图,其中显示了全球的高程数据: ```python import geemap Map = geemap.Map() Map.add_basemap('HYBRID') dem = ee.Image('USGS/SRTMGL1_003') Map.addLayer(dem, {}, 'DEM') Map.addLayerControl() Map ``` 这将创建一个交互式地图,其中显示了全球的高程数据,并允许用户使用控件在不同的地图图层之间切换。 4. 添加交互式控件 geemap还提供了很多交互式控件,使用户可以更轻松地探索地理空间数据。以下代码将在地图上添加一个滑块控件,允许用户在不同的时间段之间切换: ```python import geemap Map = geemap.Map() Map.add_basemap('HYBRID') Map.setCenter(0, 0, 2) # Add time slider widget Map.add_time_slider(start_time='1984-01-01', end_time='2020-12-31', layer_name='Landsat 8') # Add Landsat 8 surface reflectance data collection = ee.ImageCollection('LANDSAT/LC08/C01/T1_SR') \ .filterBounds(ee.Geometry.Point([-122.262, 37.8719])) \ .filterDate('1984-01-01', '2020-12-31') \ .sort('CLOUD_COVER') vis_params = { 'min': 0, 'max': 3000, 'gamma': 1.4, 'bands': ['B5', 'B4', 'B3'], } image = ee.Image(collection.first()) Map.addLayer(image, vis_params, 'Landsat 8') Map.addLayerControl() Map ``` 这将创建一个交互式地图,其中包含一个滑块控件,允许用户在不同的时间段之间切换,并显示了Landsat 8表面反射数据。 5. 导出地图 geemap还提供了导出地图的功能。以下代码将导出地图为HTML文件: ```python import geemap Map = geemap.Map() Map.add_basemap('HYBRID') Map.setCenter(0, 0, 2) # Add time slider widget Map.add_time_slider(start_time='1984-01-01', end_time='2020-12-31', layer_name='Landsat 8') # Add Landsat 8 surface reflectance data collection = ee.ImageCollection('LANDSAT/LC08/C01/T1_SR') \ .filterBounds(ee.Geometry.Point([-122.262, 37.8719])) \ .filterDate('1984-01-01', '2020-12-31') \ .sort('CLOUD_COVER') vis_params = { 'min': 0, 'max': 3000, 'gamma': 1.4, 'bands': ['B5', 'B4', 'B3'], } image = ee.Image(collection.first()) Map.addLayer(image, vis_params, 'Landsat 8') Map.addLayerControl() # Export the map as an HTML file Map.to_html('my_map.html') ``` 这将导出地图为HTML文件,用户可以在浏览器中打开该HTML文件,并与地图交互。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值