
PIE-Engine 远感云计较仄台上散成了海量远感数据、壮大的算力战丰硕的算子,使得年夜范围标准少工夫序列的远感数据阐发能够正在线快速完成,此中一年夜利器即是map算子。本期我们去具体引见map算子的感化,它战传统for轮回的区分,和怎样巧用map算子劣化代码,进步计较服从。
1、 map算子的感化
map算子是我们正在云计较仄台上处置影象经常用的算子,能够对汇合(List、FeatureCollection、ImageCollection)中的每个元素停止操纵,操纵完成返回的成果还是一个汇合工具。以FeatureCollection挪用map算子为例,其根本情势以下:
var featureCol = pie.FeatureCollection('NGCC/CHINA_PROVINCE_BOUNDARY');
var featureColNew = featureCol.map(function (feature) {
var geometry = feature.geometry();
var featureNew = pie.Feature(geometry.centroid());
return featureNew;
})
上述代码掏出featureCol 中的每个feature,然后供与各feature的多少中间,获得一个新的矢量汇合-featureColNew。
2、map算子战for轮回的区分
固然,有些map操纵用传统的for/while轮回也能够完成,但两者正在计较机造上有素质区分,for轮回是正在前端掌握变量的轮回,且是挨次施行代码,服从比力缓,普通正在PIE-Engine里很罕用。而map则是正在背景效劳器上间接感化于汇合中的元素停止轮回操纵,施行服从很快,相称于“并止施行使命”, 但正在map里普通没有再用 print、Map、Export 和Reducer等办法。上面别离比照正在汇合中利用map算子战for轮回的差别的地方。
针对List中的每一个元素停止轮回计较
//对List中的每一个元素减1,接纳map算子
var list1 = pie.List([1,2,3,2]);
var list2 = list1.map(function (value) {
return pie.Number(value).add(1);
});
print("list2",list2);
输出成果:

//对List中的每一个元素减1,接纳for轮回
var list1 = pie.List([1,2,3,2]);
var list2 = [];
for(var i = 0;i
list2.push(pie.Number(list1.get(i)).add(1).getInfo());
}
print("list2",list2);
输出成果:

List汇合挪用map算子后即可间接感化于此中的元素,而接纳for轮回则借需求增长诸多限定,才气完成不异的功用。
针对FeatureCollection中的每一个Feature停止轮回计较
操纵中国省级止政区划矢量数据计较每一个省的里积,别离接纳map算子战for轮回停止计较。
(1)与FeatureCollection中的每一个元素并计较其里积,接纳map算子:
背上滑动阅览
var featureCol = pie.FeatureCollection().load('NGCC/CHINA_PROVINCE_BOUNDARY');
var featureColNew = featureCol.map(function (feature) {
var name = feature.get("name");
var geometry = feature.geometry();
var area = geometry.area().divide(1000000);
feature = feature.set("name",name);
feature = feature.set("area",area);
return feature;
})
var result = featureColNew.reduceColumns(pie.Reducer.toList(2),["name","area"]);
print("result",result);
Map.addLayer(featureCol,,"featureCol");
Map.setCenter(118,39.7,3);
代码链接:
https://engine.piesat.cn/engine-share/shareCode.html?id=cbe5f4f5efca4b5faa8344b0ab325c04

接纳map算子获得中国各省的里积
(2)与FeatureCollection中的每一个元素并计较其里积,接纳for轮回:
背上滑动阅览
var featureCol = pie.FeatureCollection().load('NGCC/CHINA_PROVINCE_BOUNDARY');
print(featureCol)
for(i = 0; i
var name = featureCol.getAt(i).get("name");
var geometry = featureCol.getAt(i).geometry();
var area = geometry.area().divide(1000000);
print(name,area);
}
Map.addLayer(featureCol,,"featureCollection");
Map.setCenter(118,39.7,3);
代码链接:
https://engine.piesat.cn/engine-share/shareCode.html?id=4198d136975841269e367aec1ae47e70
运转成果:
▲for轮回输出各省里积
上述代码接纳map算子,2秒便可出成果,而for轮回则需求40秒,等候工夫较少,从而表现map算子的劣势。
针对ImageCollection中的每一个Image停止轮回计较
(1)与ImageCollection中的每一个元素计较NDVI,接纳map算子:
背上滑动阅览
var featureCol = pie.FeatureCollection().load('NGCC/CHINA_PROVINCE_BOUNDARY');
var beijing = featureCol.filter(pie.Filter.eq("name", "北京市"));
var bjGeo = beijing.getAt(0).geometry();
var visParams = ;
Map.addLayer(beijing, visParams, "北京市");
Map.centerObject(beijing, 6);
var imageCol = pie.ImageCollection("LC08/01/T1")
.filterDate("2019-12-01", "2019-12-31")
.filterBounds(bjGeo);
print("imageCol", imageCol);
var imageColNDVI = imageCol.map(function (image) {
// NDVI计较
var img_Nir = image.select("B5");
var img_Red = image.select("B4");
var img_NDVI = img_Nir.subtract(img_Red).divide(img_Nir.add(img_Red)).rename("NDVI");
return image.addBands(img_NDVI);
});
print("imageColNDVI", imageColNDVI);
//NDVI画造款式
var visParamNDVI = {
min: -0.2,
max: 0.8,
palette: 'CA7A41, CE7E45, DF923d, F1B555, FCD163, 99B718, '+
'74A901, 66A000, 529400,3E8601, 207401, 056201, 004C00,'+
'023B01, 012E01, 011D01, 011301'
};
var imageNDVI = imageColNDVI.select("NDVI").mosaic().clip(bjGeo);
Map.addLayer(imageNDVI, visParamNDVI, "Layer_NDVI");
代码链接:
https://engine.piesat.cn/engine-share/shareCode.html?id=4ec895ce6e3b411daab877713ca81f45
输出成果:


(2)与ImageCollection中的每一个元素计较NDVI,接纳for轮回:
背上滑动阅览
var featureCol = pie.FeatureCollection().load('NGCC/CHINA_PROVINCE_BOUNDARY');
var beijing = featureCol.filter(pie.Filter.eq("name", "北京市"));
var bjGeo = beijing.getAt(0).geometry();
var visParams = { color: "ff0000ff", fillColor: "00000000" };
Map.addLayer(beijing, visParams, "北京市");
Map.centerObject(beijing, 6);
var imageCol = pie.ImageCollection("LC08/01/T1")
.filterDate("2019-8-01", "2019-8-30")
.filterBounds(bjGeo);
print("imageCol", imageCol);
var newCol=[];
for (i = 0; i
var image = imageCol.getAt(i);
var img_Nir = image.select("B5");
var img_Red = image.select("B4");
var img_NDVI = img_Nir.subtract(img_Red).divide(img_Nir.add(img_Red))
.rename("NDVI");
image = image.addBands(img_NDVI);
newCol.push(image);
}
var newImageCol=pie.ImageCollection().fromImages(newCol);
print("newImageCol", newImageCol);
//NDVI画造款式
var visParamNDVI = {
min: -0.2,
max: 0.8,
palette: 'CA7A41, CE7E45, DF923D, F1B555, FCD163, 99B718, ' +
'74A901, 66A000, 529400,3E8601, 207401, 056201, 004C00,' +
'023B01, 012E01, 011D01, 011301'
};
var imageNDVI = newImageCol.select("NDVI").mosaic().clip(bjGeo);
Map.addLayer(imageNDVI, visParamNDVI, "Layer_NDVI");
代码链接:
https://engine.piesat.cn/engine-share/shareCode.html?id=ef81bdf97c8d45809c3101f5f8dee4c4
上述代码接纳map算子战for轮回的计较工夫根本不异, 但正在利用for轮回时要从头机关一个寄存新的image汇合的数组,并正在轮回完毕后从头机关一个由那些image构成的ImageCollection,正在步调上较为庞大。
因而,正在远感云计较仄台中,触及到对汇合中的每一个元素停止操纵时,保举利用map算子,快速且便当。但前述提到,正在map算子中没有宜再用 print、Map、Export 和Reducer等办法,假如需求对汇合中的每一个元素停止统计操纵,则可用for轮回替代,以下代码展现了利用for轮回统计北京各乡区提与的修建区里积:
背上滑动阅览
var chn = pie.FeatureCollection('NGCC/CHINA_PROVINCE_BOUNDARY');
var beijing = chn.filter(pie.Filter.eq("name", "北京市"));
var bjGeo = beijing.getAt(0).geometry();
var chn2 = pie.FeatureCollection('NGCC/CHINA_COUNTY_BOUNDARY');
var beijing2 = chn2.filter(pie.Filter.eq("cname", "北京市"));
var bjGeo2 = beijing2.getAt(0).geometry();
Map.centerObject(beijing, 7)
var visParams = { color: "ff0000ff", fillColor: "00000000" };
Map.addLayer(beijing, visParams, "北京市鸿沟");
Map.addLayer(beijing2, visParams, "北京市各区");
function rmCloud(image) {
var qa = image.select("BQA");
var cloudMask = qa.bitwiseAnd(1
return image.updateMask(cloudMask);
}
var l8 = pie.ImageCollection("LC08/01/T1")
.filterDate("2020-7-1", "2020-8-30")
.filterBounds(bjGeo)
.select(["B2", "B3", "B4", "B5", "B6", "BQA"])
.map(rmCloud);
//计较用到的指数
function imgCalculate(image) {
var green = image.select("B3");
var red = image.select("B4");
var nir = image.select("B5");
var swir1 = image.select("B6");
var ndvi = (nir.subtract(red)).divide(nir.add(red)).rename("NDVI");
var mndwi = green.subtract(swir1)
.divide(green.add(swir1))
.rename("MNDWI");
return image.addBands(ndvi).addBands(mndwi);
}
var imgCol = l8.map(imgCalculate)
.mean()
.clip(bjGeo);
Map.addLayer(imgCol, { min: 0, max: 3000, bands: ["B4", "B3", "B2"] }, "imgCol");
var ndvi = imgCol.select("NDVI");
var nonVeg = imgCol.updateMask(ndvi.lte(0.6));
Map.addLayer(nonVeg, { min: 0, max: 3000, bands: ["B4", "B3", "B2"] }, "nonVeg");
var mndwi = imgCol.select("MNDWI");
var nonVegWater = nonVeg.updateMask(mndwi.lte(0.3));
Map.addLayer(nonVegWater, { min: 0, max: 3000, bands: ["B4", "B3", "B2"] }, "nonVegWater");
var nonVegWater2 = nonVegWater.select("B2").gt(0);
Map.addLayer(nonVegWater2, { min: 0, max: 1, palette: "ff0000" }, "nonVegWater2");
var areaImage = nonVegWater2.pixelArea().multiply(nonVegWater2.gt(0));
var area = areaImage.reduceRegion(pie.Reducer.sum(), bjGeo, 30);
print("北京市修建用空中积(单元:仄圆千米): ", pie.Number(area.get("constant")).divide(1000000));
var newFeatures = [];
for (var i = 0; i
var temp = nonVegWater2.clip(beijing2.getAt(i).geometry());
var areaImg = temp.pixelArea().multiply(temp.gt(0));
var area = areaImg.reduceRegion(pie.Reducer.sum(), beijing2.getAt(i).geometry(), 30);
newFeatures.push(beijing2.getAt(i).set("area", area.get("constant")));
}
beijing2 = pie.FeatureCollection(newFeatures);
print("beijing2",beijing2);
var result = beijing2.reduceColumns(pie.Reducer.toList(2), ["name", "area"]);
print("result", result);
代码链接:
https://engine.piesat.cn/engine-share/shareCode.html?id=bf885222bf584f33aaa96c2a0093c03d
输出成果:

3、巧用map算子,进步计较服从
map算子带去便当的同时,也将大批的计较转移给了背景计较效劳。凡是我们正在影象处置时管帐算多个指数,单个指数的计较公式凡是会写成函数的情势便利挪用。多个map算子配合利用时,相称于屡次轮回,所触及到的运算量也很年夜,如何利用map算子才气劣化计较逻辑,进步计较服从呢?
上面以来云后计较裸土指数BSI、改良的回一化差别火体指数MNDWI、加强型的裸土指数EBSI、修建用天指数NDBI等4个指数的计较为例,来讲明怎样正在代码级别停止劣化去削减计较量从而进步计较服从。
办法1,将每一个指数的计较零丁写成函数,正在挑选完影象后顺次用map算子挪用:

背上滑动阅览
var chn = pie.FeatureCollection('NGCC/CHINA_PROVINCE_BOUNDARY');
var beijing = chn.filter(pie.Filter.eq("name", "北京市"));
var bjGeo = beijing.getAt(0).geometry();
Map.centerObject(beijing, 7)
var visParams = { color: "ff0000ff", fillColor: "00000000" };
Map.addLayer(beijing, visParams, "北京市鸿沟");
//来云
function rmCloud(image) {
var qa = image.select("BQA");
var cloudMask = qa.bitwiseAnd(1
return image.updateMask(cloudMask);
}
//裸土指数BSI: [(B06 + B04)-(B05 + B02)]/[(B06 + B04)+(B05 + B02)]
function BSI(image) {
var nir = image.select("B5");
var swir1 = image.select("B6");
var red = image.select("B4");
var blue = image.select("B2");
var bsi = (swir1.add(red).subtract(nir.add(blue)))
.divide(swir1.add(red).add(nir.add(blue)));
return image.addBands(bsi.rename("BSI"));
}
//改良的回一化差别火体指数MNDWI: (B03 - B06)/(B03 + B06)
function MNDWI(image) {
var mndwi = image.select("B3").subtract(image.select("B6"))
.divide(image.select("B3").add(image.select("B6")))
return image.addBands(mndwi.rename("MNDWI"));
}
//加强型的裸土指数EBSI:(BSI - MNDWI)/(BSI + MNDWI)
function EBSI(image) {
var mndwi = image.select("MNDWI");
var bsi = image.select("BSI");
var ebsi = (bsi.subtract(mndwi)).divide(bsi.add(mndwi));
return image.addBands(ebsi.rename("EBSI"));
}
//修建用天指数NDBI: (B06 - B05)/(B06 + B05)
function NDBI(image) {
var ndbi = image.select("B6").subtract(image.select("B5"))
.divide(image.select("B6").add(image.select("B5")))
return image.addBands(ndbi.rename("NDBI"));
}
//减载Landsat 8影象数据汇合
var imgColl8 = pie.ImageCollection("LC08/01/T1")
.filterDate("2020-4-1", "2020-4-30")
.filterBounds(bjGeo)
.select(["B2", "B3", "B4", "B5", "B6", "B7", "BQA"])
.map(rmCloud)
.map(BSI)
.map(MNDWI)
.map(EBSI)
.map(NDBI)
.mean()
.clip(bjGeo);
print("imgColl8",imgColl8);
Map.addLayer(imgColl8, { min: 0, max: 3000, bands: ["B4", "B3", "B2"] }, "imgCol1");
Map.addLayer(imgColl8.select("BSI"), { min: -0.2, max: 0.2 }, "BSI");
Map.addLayer(imgColl8.select("NDBI"), { min: -0.2, max: 0.2 }, "NDBI");
Map.addLayer(imgColl8.select("MNDWI"), , "MNDWI");
Map.addLayer(imgColl8.select("EBSI"), { min: 0, max: 1 }, "EBSI");
代码链接:
https://engine.piesat.cn/engine-share/shareCode.html?id=402cadc45985400c8650620b9d93bad9
上述代码共挪用了5次map算子,相称于对挑选后的影象停止了5次遍历,撤除云操纵中,每次皆是对每景影象停止波段运算完后增加计较后的指数,将大批的算力耗损正在了反复读与战写进上,输出计较成果用时85秒,完好显现用时135秒。

顺次挪用多个map计较每一个指数
办法2,将来云及指数运算启拆成一个函数,正在挑选完影象后仅用map算子挪用一次:

背上滑动阅览
var chn = pie.FeatureCollection('NGCC/CHINA_PROVINCE_BOUNDARY');
var beijing = chn.filter(pie.Filter.eq("name", "北京市"));
var bjGeo = beijing.getAt(0).geometry();
Map.centerObject(beijing, 7)
var visParams = { color: "ff0000ff", fillColor: "00000000" };
Map.addLayer(beijing, visParams, "北京市鸿沟");
var imgColl8 = pie.ImageCollection("LC08/01/T1")
.filterDate("2020-4-1", "2020-4-30")
.filterBounds(bjGeo)
.select(["B2", "B3", "B4", "B5", "B6", "B7", "BQA"]);
//影象处置函数
function imgCalculate(image) {
var qa = image.select("BQA");
var cloudMask = qa.bitwiseAnd(1
image = image.updateMask(cloudMask);
var blue = image.select("B2");
var green = image.select("B3");
var red = image.select("B4");
var nir = image.select("B5");
var swir1 = image.select("B6");
var bsi = (swir1.add(red).subtract(nir.add(blue)))
.divide(swir1.add(red).add(nir.add(blue)))
.rename("BSI");
var mndwi = green.subtract(swir1)
.divide(green.add(swir1))
.rename("MNDWI");
var ebsi = (bsi.subtract(mndwi)).divide(bsi.add(mndwi))
.rename("EBSI");
var ndbi = swir1.subtract(nir)
.divide(swir1.add(nir))
.rename("NDBI");
return image.addBands(mndwi).addBands(bsi).addBands(ebsi)
.addBands(ndbi);
}
imgColl8 = imgColl8.map(imgCalculate).mean().clip(bjGeo);
print("imgColl8", imgColl8);
Map.addLayer(imgColl8, { min: 0, max: 3000, bands: ["B4", "B3", "B2"] }, "imgCol1");
Map.addLayer(imgColl8.select("BSI"), { min: -0.2, max: 0.2 }, "BSI");
Map.addLayer(imgColl8.select("NDBI"), { min: -0.2, max: 0.2 }, "NDBI");
Map.addLayer(imgColl8.select("MNDWI"), , "MNDWI");
Map.addLayer(imgColl8.select("EBSI"), { min: 0, max: 1 }, "EBSI");
代码链接:
https://engine.piesat.cn/engine-share/shareCode.html?id=ce08fdb1cca147acb6ae6da7629fb49f

将指数计较启拆到一个函数中挪用
上述代码仅挪用了1次map算子,对挑选后的影象停止了来云操纵和4个指数波段的增加,仅需对每景影象读与写进一次,年夜年夜节流了算力,只用8秒便可输出成果并完好显现,比拟于办法1,计较速率提拔远10倍。
教会了这类思绪后,平居我们正在编写代码时,留意将计较历程劣化,就能够进步计较服从,削减等候工夫。 |