Google Earth Engine Python API:带带条带列表的图像采集上的映射函数

Google Earth Engine Python API:带带条带列表的图像采集上的映射函数,python,google-earth-engine,google-python-api,sentinel2,Python,Google Earth Engine,Google Python Api,Sentinel2,我一直在使用谷歌地球引擎中的Sentinel-2图像大气校正代码。一切进展顺利,它运行速度非常快,为一个单一的形象。我要做的是将以下代码映射到图像集合: output = image.select('QA60') for band in ['B1','B2','B3','B4','B5','B6','B7','B8','B8A','B9','B10','B11','B12']: print(band) output = output.addBands(surface_reflec

我一直在使用谷歌地球引擎中的Sentinel-2图像大气校正代码。一切进展顺利,它运行速度非常快,为一个单一的形象。我要做的是将以下代码映射到图像集合:

output = image.select('QA60')
for band in ['B1','B2','B3','B4','B5','B6','B7','B8','B8A','B9','B10','B11','B12']:
    print(band)
    output = output.addBands(surface_reflectance(band))
我想我需要一个双映射函数来实现这一点(以避免在这里使用for循环),但还没有在GEE中看到任何Python示例

到目前为止,我的想法是:

def atcorrector(image):
    qa = image.select('QA60')
    bands = ee.List(['B1','B2','B3','B4','B5','B6','B7','B8','B8A','B9','B10','B11','B12'])
    def mapper(bands):
        return qa.map(addBands(surface_reflectance(bands)))
    return qa

ImageCollection.map(atcorrector)
然而,这并没有返回所有带区的图像,所以我觉得我的嵌套函数不能正常工作。我是python新手,非常感谢大家的帮助

旁注:我已经用Sam对图像采集进行了大气校正实验,但是它运行得太慢了,我更喜欢使用建议的映射函数进行“服务器端”计算,因为我有大量的图像要处理

PS:下面是从Sam Murphy的存储库中提取的
surface\u reflective
函数的代码。它调用了他定制的一个名为“大气”的类。用于大气校正的模式是Py6S模式

# Package requirement
from Py6S import * 
import datetime
import math
import os
import sys
sys.path.append(os.path.join(os.path.dirname(os.getcwd()),'bin'))
from atmospheric import Atmospheric #Custom-defined class by Sam
import ee
ee.Initialize()

## The Sentinel-2 image collection
studyarea = ee.Geometry.Rectangle(7.8399,59.9273,8.2299,60.1208)#region of interest
S2 = ee.ImageCollection('COPERNICUS/S2').filterBounds(studyarea)\
       .filterDate('2016-06-01', '2016-06-10').sort('system:time_start')

## define metadata
info = S2one.getInfo()['properties']
scene_date = datetime.datetime.utcfromtimestamp(info['system:time_start']/1000)# i.e. Python uses seconds, EE uses milliseconds
solar_z = info['MEAN_SOLAR_ZENITH_ANGLE']
SRTM = ee.Image('USGS/GMTED2010')  # Make sure that your study area is covered by this elevation dataset
alt = SRTM.reduceRegion(reducer=ee.Reducer.mean(), geometry=studyarea.centroid()).get('be75').getInfo() # insert correct name for elevation variable from dataset
km = alt/1000  # i.e. Py6S uses units of kilometers

date = ee.Date(START_DATE)
# the following three variables are called on from the Atmospheric class Sam defined in his GitHub
h2o = Atmospheric.water(studyarea,date).getInfo() 
o3 = Atmospheric.ozone(studyarea,date).getInfo()
aot = Atmospheric.aerosol(studyarea,date).getInfo()

## Create the 6S Object
s = SixS() # Instantiate
# Atmospheric constituents
s.atmos_profile = AtmosProfile.UserWaterAndOzone(h2o,o3)
s.aero_profile = AeroProfile.Continental
s.aot550 = aot

# Earth-Sun-satellite geometry
s.geometry = Geometry.User()
s.geometry.view_z = 0               # always NADIR (I think..)
s.geometry.solar_z = solar_z        # solar zenith angle
s.geometry.month = scene_date.month # month and day used for Earth-Sun distance
s.geometry.day = scene_date.day     # month and day used for Earth-Sun distance
s.altitudes.set_sensor_satellite_level()
s.altitudes.set_target_custom_altitude(km)

# Extract spectral response function for given band name
def spectralResponseFunction(bandname):
    bandSelect = {
        'B1':PredefinedWavelengths.S2A_MSI_01,
        'B2':PredefinedWavelengths.S2A_MSI_02,
        'B3':PredefinedWavelengths.S2A_MSI_03,
        'B4':PredefinedWavelengths.S2A_MSI_04,
        'B5':PredefinedWavelengths.S2A_MSI_05,
        'B6':PredefinedWavelengths.S2A_MSI_06,
        'B7':PredefinedWavelengths.S2A_MSI_07,
        'B8':PredefinedWavelengths.S2A_MSI_08,
        'B8A':PredefinedWavelengths.S2A_MSI_09,
        'B9':PredefinedWavelengths.S2A_MSI_10,
        'B10':PredefinedWavelengths.S2A_MSI_11,
        'B11':PredefinedWavelengths.S2A_MSI_12,
        'B12':PredefinedWavelengths.S2A_MSI_13,
        }
    return Wavelength(bandSelect[bandname])

# Converts top of atmosphere reflectance to at-sensor radiance
def toa_to_rad(bandname):
    ESUN = info['SOLAR_IRRADIANCE_'+bandname]
    solar_angle_correction = math.cos(math.radians(solar_z))# solar exoatmospheric spectral irradiance
    doy = scene_date.timetuple().tm_yday
    d = 1 - 0.01672 * math.cos(0.9856 * (doy-4))# Earth-Sun distance (from day of year)
    multiplier = ESUN*solar_angle_correction/(math.pi*d**2)# conversion factor
    rad = toa.select(bandname).multiply(multiplier)# at-sensor radiance
    return rad

# Calculate surface reflectance from at-sensor radiance given waveband name
def surface_reflectance(bandname):
    s.wavelength = spectralResponseFunction(bandname)  # run 6S for this waveband
    s.run()
    # extract 6S outputs
    Edir = s.outputs.direct_solar_irradiance             #direct solar irradiance
    Edif = s.outputs.diffuse_solar_irradiance            #diffuse solar irradiance
    Lp   = s.outputs.atmospheric_intrinsic_radiance      #path radiance
    absorb  = s.outputs.trans['global_gas'].upward       #absorption transmissivity
    scatter = s.outputs.trans['total_scattering'].upward #scattering transmissivity
    tau2 = absorb*scatter                                #total transmissivity
    # radiance to surface reflectance
    rad = toa_to_rad(bandname)
    ref = rad.subtract(Lp).multiply(math.pi).divide(tau2*(Edir+Edif))
    return ref

要根据需要应用
surface\u reflective
功能,只需修改代码如下:

def atcorrector(image):
    qa = image.select('QA60')
    for band in ['B1','B2','B3','B4','B5','B6','B7','B8','B8A','B9','B10','B11','B12']:
        print(band)
        qa = qa.addBands(surface_reflectance(band))
    return qa

ImageCollection.map(atcorrector)
如您所见,此代码只是复制您为单个图像所做的代码。
for
循环在Python API中没有任何问题(在JavaScript API中,我不建议使用这个)。如果您不想对循环使用
,只需稍微更改代码即可:

def atcorrector(image):
    qa = image.select('QA60')
    bands = ee.List(['B1','B2','B3','B4','B5','B6','B7','B8','B8A','B9','B10','B11','B12'])

    def mapper(band):
        qa = qa.addBands(surface_reflectance(band))
        return band

    bands.map(mapper)
    return qa

ImageCollection.map(atcorrector)
ee.List
map
功能(或任何具有
map
功能的
ee
对象)可以替代
for
循环


希望这能有所帮助。

要根据需要应用
曲面反射率
功能,只需修改代码如下:

def atcorrector(image):
    qa = image.select('QA60')
    for band in ['B1','B2','B3','B4','B5','B6','B7','B8','B8A','B9','B10','B11','B12']:
        print(band)
        qa = qa.addBands(surface_reflectance(band))
    return qa

ImageCollection.map(atcorrector)
如您所见,此代码只是复制您为单个图像所做的代码。
for
循环在Python API中没有任何问题(在JavaScript API中,我不建议使用这个)。如果您不想对
循环使用
,只需稍微更改代码即可:

def atcorrector(image):
    qa = image.select('QA60')
    bands = ee.List(['B1','B2','B3','B4','B5','B6','B7','B8','B8A','B9','B10','B11','B12'])

    def mapper(band):
        qa = qa.addBands(surface_reflectance(band))
        return band

    bands.map(mapper)
    return qa

ImageCollection.map(atcorrector)
ee.List
map
功能(或任何具有
map
功能的
ee
对象)可以替代
for
循环


希望这有帮助。

您根本没有使用
映射器功能?@Kevin是的,我不知道如何修复它-您能指出语法的错误吗?我需要的是让我的
atcorrector
函数拍摄ee.ImageCollection的每个图像,并将
surface\u reflective
函数应用到每个图像的每个波段。你根本没有使用
mapper
函数吗?@Kevin是的,我不知道如何修复它-你能指出语法的错误吗?我需要的是让我的
atcorrector
函数拍摄ee.ImageCollection的每张图像,然后将
surface\u reflective
函数应用于每个图像的每个波段。这就是我试图修复它的方式-向我抛出了这个错误:
UnboundLocalError:assignment之前引用的局部变量“qa”没有意义,因为qa是在函数前面指定的?一定是和我正在调用的曲面反射函数更相关的东西。我怀疑它不喜欢乐队名称的ee.List格式,更喜欢常规的列表。如果您使用的是Python 3.x,请在
def mapper(乐队):
行之后添加
nonlocal qa
行,以使
mapper
函数能够完全访问
qa
。没有这一行,
mapper
函数可以读取
qa
,但不能修改它。这是Python中的变量范围,而不是
surface\u reflective
函数。使用
进行
循环的方法如何?是的!添加的
非本地qa
确实消除了错误。使用
for
循环的方法很有效,这是我一直在使用的方法,但对于我的需求来说太慢了。我希望通过映射一个
ee.List
我可以切换到“服务器端”计算——不确定这是否是一个正确的假设。现在,当我使用正确的代码运行它时,它会显示
keyrerror:
-可能需要调整
surface\u reflective
函数以接受ee。同时列出对象。有什么想法可以实现这种转变吗?谢谢你的时间,顺便说一句!你的
surface\u reflective
函数的代码是什么?这是一个相当大的代码。我已经对问题进行了编辑,以添加完整的问题,但可能原始问题的笔记本会更容易阅读。这就是我试图修复它的方式-向我抛出了这个错误:
UnboundLocalError:assignment之前引用的局部变量“qa”没有意义,因为qa是在函数的前面指定的?一定是和我正在调用的曲面反射函数更相关的东西。我怀疑它不喜欢乐队名称的ee.List格式,更喜欢常规的列表。如果您使用的是Python 3.x,请在
def mapper(乐队):
行之后添加
nonlocal qa
行,以使
mapper
函数能够完全访问
qa
。没有这一行,
mapper
函数可以读取
qa
,但不能修改它。这是Python中的变量范围,而不是
surface\u reflective
函数。使用
进行
循环的方法如何?是的!添加的
非本地qa
确实消除了错误。使用
for
循环的方法很有效,这是我一直在使用的方法,但对于我的需求来说太慢了。我希望通过映射一个
ee.List
我可以切换到“服务器端”计算——不确定这是否是一个正确的假设。现在,当我使用正确的代码运行它时,它会显示
keyrerror:
-可能需要调整
surface\u reflective
函数以接受ee。列出要处理的对象