Google Earth Engine Python API: функция карты над коллекцией изображений со списком полос - PullRequest
0 голосов
/ 13 февраля 2019

Я использовал код Сэма Мерфи для атмосферной коррекции изображений Sentinel-2 в Google Earth Engine.Все идет хорошо и работает очень быстро для одного изображения.То, что я хотел бы сделать, это сопоставить следующий код с коллекцией изображений:

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 здесь), но я не виделникаких примеров Python в GEE пока нет.

Пока что это то, что я придумал:

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, поэтому всякая помощь приветствуется!

Примечание: я уже экспериментировал с вторым хранилищем Сэма для атмосферной коррекции коллекций изображений, но он работает слишком медленно иЯ бы предпочел иметь вычисления на стороне сервера с использованием предложенной функции карты, так как у меня есть множество изображений для обработки.

PS: Ниже приведен код для функции surface_reflectance, извлеченный из репозитория Сэма Мерфи.Он призывает один из его индивидуальных классов под названием "Атмосферный".Для атмосферной коррекции используется модель 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

1 Ответ

0 голосов
/ 19 февраля 2019

Чтобы применить функцию surface_reflectance, как вы хотите, просто измените код следующим образом:

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 я бы не рекомендовал использовать это).Если вы не хотите использовать цикл for, просто немного измените код:

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)

Функция map ee.List (или любой объект ee, который имеетmap функция) может заменить цикл for.

Надеюсь, это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...