AI Earth 是一个由阿里云提供支持的遥感算法开发和数据驱动科学平台。利用平台提供的Python SDK,我们可以通过编写 Python 代码来实现对遥感数据的云端处理。平台既提供了在线Notebook环境,也支持直接在本地Jupyter Notebook编写代码。因为在本地编写更有利于对后续管理,所以本项目也采用了本地Jupyter Notebook编写的方式。
配置准备
安装AI Earth Engine SDK
1
| python -m pip install -U "aie-sdk[engine]"
|
注册阿里云账号
阿里云・云小站
获取鉴权信息
根据不同的配置环境可以选择不同的鉴权方式
- 使用在线
NoteBook环境:无须鉴权
- 使用本地模式,但是不需要长期有效:使用 token 鉴权
- 使用本地模式,但是希望鉴权长期有效:使用阿里云 AccessKey 鉴权
- 使用本地模式,但是希望使用 Aliyun STS 鉴权
在 AI Earth 生成 token
编写代码
鉴权
选取对应的方式进行鉴权
1 2 3 4 5 6 7 8 9 10 11 12 13
| import aie
aie.Authenticate()
aie.Authenticate(token='token')
aie.Authenticate(access_key_id="*", access_key_secret="*")
aie.Authenticate(access_key_id='*', access_key_secret='*', access_key_security_token='*')
aie.Initialize()
|
确定研究区域
分别提取广西和广东的矢量边界并进行合并,然后在地图上表示出来。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| feature_collection_1 = aie.FeatureCollection('China_Province') \ .filter(aie.Filter.eq('province', '广西壮族自治区'))
feature_collection_2 = aie.FeatureCollection('China_Province') \ .filter(aie.Filter.eq('province', '广东省'))
union_fc = feature_collection_1.merge(feature_collection_2).union()
union_geometry = union_fc.geometry()
map = aie.Map( center=union_fc.getCenter(), height=800, zoom=6 )
vis_params = { 'color': '#00FF00' }
map.addLayer( union_fc, vis_params, 'region', bounds=union_fc.getBounds() )
map
|
AI Earth 提供了map方法用以渲染地图组件。将项目流程切分为 NoteBook 的多个 cell 可以让组件进行独立渲染,这将更方便我们观察每个步骤的结果。后续的步骤也将采用这样的方式。
获取地物分类
使用的数据集: https://engine-aiearth.aliyun.com/#/dataset/ESA_WORLD_COVER_V200
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| dataset_classify = aie.ImageCollection('ESA_WORLD_COVER_V200') \ .filterBounds(union_geometry)
img_cover = dataset_classify.mosaic() \ .clip(union_geometry) \ .rename(["cover"])
map = aie.Map( center=union_fc.getCenter(), height=800, zoom=6 ) vis_params = { 'SR_Bands': 'cover', 'min': 10.0, 'max': 100.0, 'palette': [ '#006400','#ffbb22','#ffff4c','#f096ff', '#fa0000','#b4b4b4','#f0f0f0','#0064c8', '#0096a0','#00cf75','#fae6a0' ] }
map.addLayer( img_cover, vis_params, 'cover', bounds=union_fc.getBounds() ) map
|
栅格数据的处理方式大同小异,故下文只展示各种数据需要特别处理的地方。
获取历史火灾数据集
使用的数据集: https://engine-aiearth.aliyun.com/#/dataset/MODIS_MCD64A1_006
1 2 3 4 5 6 7 8 9 10 11 12 13
|
dataset_firepoint = aie.ImageCollection('MODIS_MCD64A1_006') .filterDate('2012-01-01', '2022-12-31')
img_firepoint = dataset_firepoint.select(['BurnDate']).Or() \ .mask() \ .clip(union_geometry) \ .rename(["firepoint"])
|
计算坡度坡向
使用的数据集: https://engine-aiearth.aliyun.com/#/dataset/Copernicus_DEM_30M
1 2 3
| img_slope = aie.Terrain.slope(img_DEM).rename(["slope"]) img_aspect = aie.Terrain.aspect(img_DEM).rename(["aspect"])
|
生物气候变量
使用的数据集: https://engine-aiearth.aliyun.com/#/dataset/ERA5_LAND_MONTHLY
该数据集的各个波段有不同的含义,我们只需提取要用的内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| dataset_avg_temp = dataset_Bioclimatic.select(['temperature_2m']) img_avg_temp = dataset_avg_temp.mean().clip(union_geometry).rename(["avg_temp"])
dataset_skin_avg_temp = dataset_Bioclimatic.select(['skin_temperature']) img_skin_avg_temp = dataset_skin_avg_temp.mean().clip(union_geometry).rename(["skin_avg_temp"])
dataset_surface_pressure = dataset_Bioclimatic.select(['surface_pressure']) img_surface_pressure = dataset_surface_pressure.mean().clip(union_geometry).rename(["surface_pressure"])
dataset_precipitation = dataset_Bioclimatic.select(['total_precipitation']) img_precipitation = dataset_precipitation.sum().clip(union_geometry).rename(["precipitation"])
dataset_evaporation = dataset_Bioclimatic.select(['total_evaporation']) img_evaporation = dataset_evaporation.sum().clip(union_geometry).rename(["evaporation"])
|
WET
利用 Landsat9 的数据计算湿度指标
使用的数据集:https://engine-aiearth.aliyun.com/#/dataset/LANDSAT_LC09_C02_T1_L1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| dataset = aie.ImageCollection('LANDSAT_LC09_C02_T1_L1') \ .filterBounds(union_fc) \ .filterDate('2021-01-01', '2022-12-31') \ .filter(aie.Filter.lte('eo:cloud_cover', 30.0))
def removeLandsatCloud(image): cloudsBitMask = (1 << 3) qa = image.select('QA_PIXEL') mask = qa.bitwiseAnd(aie.Image(cloudsBitMask)).eq(aie.Image(0)) return image.updateMask(mask) images_no_cloud = dataset.map(removeLandsatCloud)
image_L9C2L2 = images_no_cloud.mosaic().clip(union_geometry)
img_wet = image_L9C2L2.select('B2').multiply(aie.Image(0.1511)) \ .add(image_L9C2L2.select('B3').multiply(aie.Image(0.1973))) \ .add(image_L9C2L2.select('B4').multiply(aie.Image(0.3283))) \ .add(image_L9C2L2.select('B5').multiply(aie.Image(0.3407))) \ .add(image_L9C2L2.select('B6').multiply(aie.Image(0.7171))) \ .add(image_L9C2L2.select('B7').multiply(aie.Image(0.4559))) \ .rename(["wet"])
|
土壤分类
使用的数据集: https://engine-aiearth.aliyun.com/#/dataset/OPENLANDMAP_SOL_SOL_TEXTURE-CLASS_USDA-TT_M_V02
过程:略
NDVI
使用的数据集: https://engine-aiearth.aliyun.com/#/dataset/MODIS_MOD13Q1_006
过程:略
使用自适应分类器
划分数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| img_all = img_firepoint.addBands(img_aspect) \ .addBands(img_slope) \ .addBands(img_DEM) \ .addBands(img_precipitation) \ .addBands(img_cover) \ .addBands(img_soil) \ .addBands(img_surface_pressure) \ .addBands(img_avg_temp) \ .addBands(img_ndvi) \ .addBands(img_evaporation) \ .addBands(img_wet) \ .clip(union_geometry)
samples = img_all.sampleRegion(union_geometry, 800, True)
sample = samples.randomColumn() training_sample = sample.filter(aie.Filter.lte('random', 0.80)) validation_sample = sample.filter(aie.Filter.gt('random', 0.80))
|
使用自适应分类器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| trained_classifier = aie.Classifier.adaBoost(10) trained_classifier = trained_classifier.train(training_sample, "firpoint", img_all.bandNames().getInfo())
train_accuracy = trained_classifier.confusionMatrix() print('Training error matrix:', train_accuracy.getInfo()) print('Training overall accuracy:', train_accuracy.accuracy().getInfo())
validation = validation_sample.classify(trained_classifier) validation_accuracy = validation.errorMatrix(label, 'classification') print('Validation error matrix:', validation_accuracy.getInfo()) print('Validation accuracy:', validation_accuracy.accuracy().getInfo())
img_classified = img_all.classify(trained_classifier)
|
查看结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| print(img_classified.getInfo())
map = aie.Map( center=union_fc.getCenter(), height=800, zoom=6 ) map.addLayer( img_classified, { 'min': 0, 'max': 1, 'palette': ["0,255,255","255,0,0"] }, 'aie_classification', bounds=union_fc.getBounds() ) map
|
辅助函数
为了节省调试实践,我在做这个项目的时候封装了一些函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| from math import sqrt
def get_max_and_min(img_target:aie.Image,region:aie.Geometry=union_geometry): reducer = aie.Reducer.max().combine(reducer2=aie.Reducer.min(), sharedInputs=True) result = img_target.reduceRegion(reducer, region) max,min = list(result.getInfo().values()) return max,min
def fix_with_mean(img_target:aie.Image,region:aie.Geometry=union_geometry): reducer = aie.Reducer.mean() result = img_target.reduceRegion(reducer, union_geometry)
mean_tag = list(result.getInfo().keys())[0] target_mean = result.getInfo()[mean_tag] img_mean = aie.Image(target_mean).clip(union_geometry) img_target = img_target.unmask(img_mean) img_target = img_target.updateMask(img_target.mask()) return img_target
def save(img_target:aie.Image, filename:str=None): if filename is None: filename = img_target.bandNames().getInfo()[1]
reducer = aie.Reducer.min() result = img_target.pixelArea().reduceRegion(reducer, union_geometry) area = sqrt(result.getInfo()['area_min']) name = img_target.bandNames().getInfo()[0] print(name + ":" + str(area))
aie.Export.image.toAsset(img_target, filename, area).start()
|
相关链接:
阿里云 AI Earth: https://engine-aiearth.aliyun.com/#/
利用 AI Earth 给 Landsat9 数据去云: https://engine-aiearth.aliyun.com/docs/page/case?d=6cf4e8
WET 湿度指数计算: http://www.yndxxb.ynu.edu.cn/yndxxbzrkxb/article/doi/10.7540/j.ynu.20190174?viewType=HTML