Commit dc5b1c37 authored by Daniel Scheffler's avatar Daniel Scheffler
Browse files

Added SRF object (needed for atmospheric correction of Landsat).

algorithms.L1C_P.AtmCorr:
- _get_srf(): now returns an instance of SRF object
- run_atmospheric_correction(): activated SRF getter

io.Input_reader:
- SRF_reader(): added verbose mode
- added class SRF

- updated __version__


Former-commit-id: 32d65014
parent d08a8a57
...@@ -15,7 +15,7 @@ from . import config ...@@ -15,7 +15,7 @@ from . import config
from .processing.process_controller import process_controller from .processing.process_controller import process_controller
__version__ = '20170126.02' __version__ = '20170127.01'
__author__ = 'Daniel Scheffler' __author__ = 'Daniel Scheffler'
__all__ = ['algorithms', __all__ = ['algorithms',
'io', 'io',
......
...@@ -39,7 +39,8 @@ from ..config import GMS_config as CFG ...@@ -39,7 +39,8 @@ from ..config import GMS_config as CFG
from . import GEOPROCESSING as GEOP from . import GEOPROCESSING as GEOP
from .L1B_P import L1B_object from .L1B_P import L1B_object
from .METADATA import get_LayerBandsAssignment from .METADATA import get_LayerBandsAssignment
from ..misc.definition_dicts import get_outFillZeroSaturated from ..misc.definition_dicts import get_outFillZeroSaturated, proc_chain
from ..io.Input_reader import SRF
from S2SCAPEM.s2_ac import AC_GMS from S2SCAPEM.s2_ac import AC_GMS
from S2MSI import RSImage from S2MSI import RSImage
...@@ -651,9 +652,15 @@ class AtmCorr(object): ...@@ -651,9 +652,15 @@ class AtmCorr(object):
def _get_srf(self): def _get_srf(self):
"""Returns an SRF object S2SRF. """Returns an instance of SRF in the same structure like S2MSI.Tools.S2SRF.S2SRF
""" """
return None # TODO # FIXME calculation of center wavelengths within SRF() used not the GMS algorithm
# SRF instance must be created for all bands and the previous proc level
GMS_identifier_fullScene = self.inObjs[0].GMS_identifier
GMS_identifier_fullScene['Subsystem'] = ''
GMS_identifier_fullScene['proc_level'] = proc_chain[proc_chain.index(self.inObjs[0].proc_level) - 1]
return SRF(GMS_identifier_fullScene, wvl_unit='nanometers', format_bandnames=True)
def run_atmospheric_correction(self, dump_ac_input=False): def run_atmospheric_correction(self, dump_ac_input=False):
...@@ -675,7 +682,7 @@ class AtmCorr(object): ...@@ -675,7 +682,7 @@ class AtmCorr(object):
band_spatial_sampling = self.band_spatial_sampling, band_spatial_sampling = self.band_spatial_sampling,
tile_name = self.tile_name, tile_name = self.tile_name,
dem = self._get_dem(), dem = self._get_dem(),
#srf = self._get_srf() srf = self._get_srf()
) # NOTE: all keys of this dict are later converted to attributes of RSImage ) # NOTE: all keys of this dict are later converted to attributes of RSImage
options = self.inObjs[0].ac_options options = self.inObjs[0].ac_options
script = False script = False
......
...@@ -26,6 +26,7 @@ import numpy as np ...@@ -26,6 +26,7 @@ import numpy as np
import scipy.interpolate import scipy.interpolate
import spectral import spectral
from spectral.io import envi as envi from spectral.io import envi as envi
from pandas import DataFrame, Series
from ..config import GMS_config as CFG from ..config import GMS_config as CFG
from ..algorithms import METADATA as META from ..algorithms import METADATA as META
...@@ -175,10 +176,11 @@ def get_list_GMSfiles(dataset_list, target): ...@@ -175,10 +176,11 @@ def get_list_GMSfiles(dataset_list, target):
return GMS_list return GMS_list
def SRF_reader(GMS_identifier): def SRF_reader(GMS_identifier, v=False):
"""Reads SRF for any sensor and returns a dictionary containing band names as keys and SRF numpy arrays as values. """Reads SRF for any sensor and returns a dictionary containing band names as keys and SRF numpy arrays as values.
:param GMS_identifier: :param GMS_identifier:
:param v: verbose mode
""" """
satellite, sensor, logger = (GMS_identifier['Satellite'], GMS_identifier['Sensor'], GMS_identifier['logger']) satellite, sensor, logger = (GMS_identifier['Satellite'], GMS_identifier['Sensor'], GMS_identifier['logger'])
...@@ -190,7 +192,8 @@ def SRF_reader(GMS_identifier): ...@@ -190,7 +192,8 @@ def SRF_reader(GMS_identifier):
SRF_path = PG.get_path_srf_file(GMS_identifier, bandname=bandname) SRF_path = PG.get_path_srf_file(GMS_identifier, bandname=bandname)
try: try:
SRF_dict[bandname] = np.loadtxt(SRF_path,skiprows=1) SRF_dict[bandname] = np.loadtxt(SRF_path,skiprows=1)
logger.info('Reading SRF for %s %s, %s...' %(satellite,sensor,bandname)) if v:
logger.info('Reading SRF for %s %s, %s...' %(satellite,sensor,bandname))
except FileNotFoundError: except FileNotFoundError:
logger.warning('No spectral response function found for %s %s %s at %s! >None< is returned.' logger.warning('No spectral response function found for %s %s %s at %s! >None< is returned.'
%(satellite,sensor,bandname,SRF_path)) %(satellite,sensor,bandname,SRF_path))
...@@ -202,6 +205,90 @@ def SRF_reader(GMS_identifier): ...@@ -202,6 +205,90 @@ def SRF_reader(GMS_identifier):
return SRF_dict return SRF_dict
class SRF(object):
def __init__(self, GMS_identifier=None, wvl_unit='nanometers', format_bandnames= False, v=False):
# type: (dict, str, bool, bool) -> None
"""SRF instance provides SRF functions, wavelength positions, etc..
:param GMS_identifier: dictionary as provided by GMS_object
:param wvl_unit: the wavelengths unit to be used within SRF instance ('nanometers' or 'micrometers)
:param format_bandnames: whether to format default strings from LayerBandsAssignment as 'B01', 'B02' etc..
:param v: verbose mode
"""
if not wvl_unit in ['micrometers', 'nanometers']:
raise ValueError('Unknown wavelength unit %s.' %wvl_unit)
self.srfs_wvl = []
self.srfs = []
self.bands = []
self.wvl = []
self.wvl_unit = wvl_unit
self.format_bandnames = format_bandnames
self.v = v
if GMS_identifier:
self.from_GMS_identifier(GMS_identifier)
def _set_attrs(self, wvl, srfs):
for bN in srfs:
srf = np.array(srfs[bN], dtype=np.float)
srfs[bN] = srf / np.trapz(x=wvl,y=srf)
self.srfs_wvl = wvl
self.srfs = srfs
self.bands = sorted(list(self.srfs.keys()))
# FIXME this is not the GMS algorithm to calculalate center wavelengths
self.wvl = [np.trapz(x=self.srfs_wvl, y=self.srfs_wvl * self.srfs[band]) for band in self.bands] # calculate center wavelengths
self.wvl = self.wvl if self.wvl_unit=='micrometers' else [int(i) for i in self.wvl]
self.conv = {}
self.conv.update({key: value for key, value in zip(self.bands, self.wvl)})
self.conv.update({value: key for key, value in zip(self.bands, self.wvl)})
def from_GMS_identifier(self, GMS_identifier):
srf_dict = SRF_reader(GMS_identifier, v=self.v)
return self.from_dict(srf_dict)
def from_dict(self, srf_dict):
"""Create an instance of SRF from a dictionary.
:param dict: {'key_LayerBandsAssignment': <2D array: cols=[wvl,resp],rows=samples>}
"""
is_nm = [300 < np.max(srf_dict[band][:, 0]) < 15000 for band in srf_dict]
assert len(set(is_nm))==1, "'srf_dict' must contain only one wavelength unit."
scale_factor = 1 if is_nm[0] else 1000
all_wvls = np.concatenate(list((arr[:,0] for key, arr in srf_dict.items())))*scale_factor
wvl = np.arange(all_wvls.min(), all_wvls.max() + 1, 1).astype(np.int)
df = DataFrame(index = wvl)
for band in srf_dict:
bandname = band if not self.format_bandnames else ('B%s' % band if len(band) == 2 else 'B0%s' % band)
df = df.join(Series(srf_dict[band][:,1],
index=np.array(srf_dict[band][:,0]*scale_factor)
.astype(np.int), name=bandname))
df = df.fillna(0)
wvl = df.index.astype(np.float) if self.wvl_unit == 'nanometers' else df.index/1000.
self._set_attrs(wvl=wvl, srfs=df.to_dict(orient='series'))
return self
def instrument(self,bands):
return {
'rspf':np.vstack([self[band] for band in bands]),
'wvl_rsp':np.copy(self.srfs_wvl),
'wvl_inst':np.copy(self.wvl),
'sol_irr':None
}
def __call__(self,band):
return self.srfs[band]
def __getitem__(self,band):
return self.srfs[band]
def pickle_SRF_DB(L1A_Instances): def pickle_SRF_DB(L1A_Instances):
list_GMS_identifiers = [i.GMS_identifier for i in L1A_Instances] list_GMS_identifiers = [i.GMS_identifier for i in L1A_Instances]
out_dict = collections.OrderedDict() out_dict = collections.OrderedDict()
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment