Commit c6f4146e authored by Mathias Peters's avatar Mathias Peters
Browse files

Merge branch 'master' into dev

parents 3bed1115 31828c1a
...@@ -523,7 +523,6 @@ class L1A_object(GMS_object): ...@@ -523,7 +523,6 @@ class L1A_object(GMS_object):
if rasObj.get_projection_type() == 'UTM': if rasObj.get_projection_type() == 'UTM':
self.MetaObj.CornerTieP_UTM = rasObj.get_corner_coordinates('UTM') self.MetaObj.CornerTieP_UTM = rasObj.get_corner_coordinates('UTM')
self.meta_odict = self.MetaObj.to_odict() # important in order to keep geotransform/projection
if CFG.inmem_serialization: if CFG.inmem_serialization:
self.delete_tempFiles() # these files are needed later in Python execution mode self.delete_tempFiles() # these files are needed later in Python execution mode
self.MetaObj.Dataname = previous_dataname # /vsi.. pointing directly to raw data archive (which exists) self.MetaObj.Dataname = previous_dataname # /vsi.. pointing directly to raw data archive (which exists)
......
...@@ -277,7 +277,7 @@ class L1B_object(L1A_object): ...@@ -277,7 +277,7 @@ class L1B_object(L1A_object):
def get_spatial_reference_scene(self): def get_spatial_reference_scene(self):
boundsLonLat = corner_coord_to_minmax(self.trueDataCornerLonLat) boundsLonLat = corner_coord_to_minmax(self.trueDataCornerLonLat)
footprint_poly = HLP_F.CornerLonLat_to_shapelyPoly(self.trueDataCornerLonLat) footprint_poly = HLP_F.CornerLonLat_to_shapelyPoly(self.trueDataCornerLonLat)
RSF = Scene_finder(boundsLonLat, self.acq_datetime, self.meta_odict['coordinate system string'], RSF = Scene_finder(boundsLonLat, self.acq_datetime, self.MetaObj.projection,
footprint_poly, self.scene_ID, footprint_poly, self.scene_ID,
min_overlap=CFG.spatial_ref_min_overlap, min_overlap=CFG.spatial_ref_min_overlap,
min_cloudcov=CFG.spatial_ref_min_cloudcov, min_cloudcov=CFG.spatial_ref_min_cloudcov,
...@@ -486,8 +486,9 @@ class L1B_object(L1A_object): ...@@ -486,8 +486,9 @@ class L1B_object(L1A_object):
ref_obj = GMS_object.from_disk((path_gmsFile, ['cube', None])) ref_obj = GMS_object.from_disk((path_gmsFile, ['cube', None]))
# get spectral characteristics # get spectral characteristics
ref_cwl, shift_cwl = [[float(i) for i in GMS_obj.meta_odict['wavelength']] for GMS_obj in [ref_obj, self]] ref_cwl = [float(ref_obj.MetaObj.CWL[bN]) for bN in ref_obj.MetaObj.LayerBandsAssignment]
ref_fwhm, shift_fwhm = [[float(i) for i in GMS_obj.meta_odict['bandwidths']] for GMS_obj in [ref_obj, self]] shift_cwl = [float(self.MetaObj.CWL[bN]) for bN in self.MetaObj.LayerBandsAssignment]
shift_fwhm = [float(self.MetaObj.FWHM[bN]) for bN in self.MetaObj.LayerBandsAssignment]
# exclude cirrus/oxygen band of Landsat-8/Sentinel-2 # exclude cirrus/oxygen band of Landsat-8/Sentinel-2
shift_bbl, ref_bbl = [False] * len(shift_cwl), [False] * len(ref_cwl) # bad band lists shift_bbl, ref_bbl = [False] * len(shift_cwl), [False] * len(ref_cwl) # bad band lists
...@@ -561,7 +562,7 @@ class L1B_object(L1A_object): ...@@ -561,7 +562,7 @@ class L1B_object(L1A_object):
max_shift=CFG.coreg_max_shift_allowed, max_shift=CFG.coreg_max_shift_allowed,
ws=CFG.coreg_window_size, ws=CFG.coreg_window_size,
data_corners_ref=[[x, y] for x, y in self.spatRef_scene.polyUTM.convex_hull.exterior.coords], data_corners_ref=[[x, y] for x, y in self.spatRef_scene.polyUTM.convex_hull.exterior.coords],
data_corners_tgt=[transform_any_prj(EPSG2WKT(4326), self.meta_odict['coordinate system string'], x, y) data_corners_tgt=[transform_any_prj(EPSG2WKT(4326), self.MetaObj.projection, x, y)
for x, y in HLP_F.reorder_CornerLonLat(self.trueDataCornerLonLat)], for x, y in HLP_F.reorder_CornerLonLat(self.trueDataCornerLonLat)],
nodata=(get_outFillZeroSaturated(geoArr_ref.dtype)[0], nodata=(get_outFillZeroSaturated(geoArr_ref.dtype)[0],
get_outFillZeroSaturated(geoArr_shift.dtype)[0]), get_outFillZeroSaturated(geoArr_shift.dtype)[0]),
...@@ -690,10 +691,10 @@ class L1B_object(L1A_object): ...@@ -690,10 +691,10 @@ class L1B_object(L1A_object):
# update geoinformations and array shape related attributes # update geoinformations and array shape related attributes
self.logger.info("Updating geoinformations of '%s' attribute..." % attrname) self.logger.info("Updating geoinformations of '%s' attribute..." % attrname)
if attrname == 'arr': if attrname == 'arr':
self.meta_odict['map info'] = DS.updated_map_info self.MetaObj.map_info = DS.updated_map_info
self.meta_odict['coordinate system string'] = EPSG2WKT(WKT2EPSG(DS.updated_projection)) self.MetaObj.projection = EPSG2WKT(WKT2EPSG(DS.updated_projection))
self.shape_fullArr = DS.arr_shifted.shape self.shape_fullArr = DS.arr_shifted.shape
self.meta_odict['lines'], self.meta_odict['samples'] = DS.arr_shifted.shape[:2] self.MetaObj.rows, self.MetaObj.cols = DS.arr_shifted.shape[:2]
else: else:
self.masks_meta['map info'] = DS.updated_map_info self.masks_meta['map info'] = DS.updated_map_info
self.masks_meta['coordinate system string'] = EPSG2WKT(WKT2EPSG(DS.updated_projection)) self.masks_meta['coordinate system string'] = EPSG2WKT(WKT2EPSG(DS.updated_projection))
...@@ -705,7 +706,7 @@ class L1B_object(L1A_object): ...@@ -705,7 +706,7 @@ class L1B_object(L1A_object):
geoArr.arr, geoArr.gt, geoArr.prj = \ geoArr.arr, geoArr.gt, geoArr.prj = \
DS.GeoArray_shifted.arr, DS.GeoArray_shifted.gt, DS.GeoArray_shifted.prj DS.GeoArray_shifted.arr, DS.GeoArray_shifted.gt, DS.GeoArray_shifted.prj
# setattr(self,attrname, DS.GeoArray_shifted) # NOTE: don't set array earlier because setter will also # setattr(self,attrname, DS.GeoArray_shifted) # NOTE: don't set array earlier because setter will also
# # update arr.gt/.prj/.nodata from meta_odict # # update arr.gt/.prj/.nodata from MetaObj
self.resamp_needed = False self.resamp_needed = False
self.coreg_needed = False self.coreg_needed = False
......
...@@ -64,8 +64,8 @@ class L1C_object(L1B_object): ...@@ -64,8 +64,8 @@ class L1C_object(L1B_object):
self.logger.info('Calculating LonLat array...') self.logger.info('Calculating LonLat array...')
self._lonlat_arr = \ self._lonlat_arr = \
GEOP.get_lonlat_coord_array(self.shape_fullArr, self.arr_pos, GEOP.get_lonlat_coord_array(self.shape_fullArr, self.arr_pos,
mapinfo2geotransform(self.meta_odict['map info']), mapinfo2geotransform(self.MetaObj.map_info),
self.meta_odict['coordinate system string'], self.MetaObj.projection,
meshwidth=10, # for faster processing meshwidth=10, # for faster processing
nodata_mask=None, # dont overwrite areas outside the image with nodata nodata_mask=None, # dont overwrite areas outside the image with nodata
outFill=get_outFillZeroSaturated(np.float32)[0])[0] outFill=get_outFillZeroSaturated(np.float32)[0])[0]
...@@ -87,17 +87,18 @@ class L1C_object(L1B_object): ...@@ -87,17 +87,18 @@ class L1C_object(L1B_object):
""" """
if self._VZA_arr is None: if self._VZA_arr is None:
self.logger.info('Calculating viewing zenith array...') self.logger.info('Calculating viewing zenith array...')
if 'ViewingAngle_arrProv' in self.meta_odict and self.meta_odict['ViewingAngle_arrProv']: if self.MetaObj.ViewingAngle_arrProv:
# Sentinel-2 # Sentinel-2
self._VZA_arr = GEOP.adjust_acquisArrProv_to_shapeFullArr(self.meta_odict['ViewingAngle_arrProv'], self._VZA_arr = GEOP.adjust_acquisArrProv_to_shapeFullArr(
self.shape_fullArr, {k: v.tolist() for k, v in self.MetaObj.ViewingAngle_arrProv.items()},
meshwidth=10, # for faster processing self.shape_fullArr,
subset=None, meshwidth=10, # for faster processing
bandwise=0) subset=None,
bandwise=0)
else: else:
self._VZA_arr = GEOP.calc_VZA_array(self.shape_fullArr, self.arr_pos, self.fullSceneCornerPos, self._VZA_arr = GEOP.calc_VZA_array(self.shape_fullArr, self.arr_pos, self.fullSceneCornerPos,
float(self.meta_odict['ViewingAngle']), float(self.MetaObj.ViewingAngle),
float(self.meta_odict['FieldOfView']), float(self.MetaObj.FOV),
self.logger, self.logger,
nodata_mask=None, # dont overwrite areas outside image with nodata nodata_mask=None, # dont overwrite areas outside image with nodata
outFill=get_outFillZeroSaturated(np.float32)[0], outFill=get_outFillZeroSaturated(np.float32)[0],
...@@ -120,13 +121,14 @@ class L1C_object(L1B_object): ...@@ -120,13 +121,14 @@ class L1C_object(L1B_object):
""" """
if self._VAA_arr is None: if self._VAA_arr is None:
self.logger.info('Calculating viewing azimuth array...') self.logger.info('Calculating viewing azimuth array...')
if 'IncidenceAngle_arrProv' in self.meta_odict and self.meta_odict['IncidenceAngle_arrProv']: if self.MetaObj.IncidenceAngle_arrProv:
# Sentinel-2 # Sentinel-2
self._VAA_arr = GEOP.adjust_acquisArrProv_to_shapeFullArr(self.meta_odict['IncidenceAngle_arrProv'], self._VAA_arr = GEOP.adjust_acquisArrProv_to_shapeFullArr(
self.shape_fullArr, {k: v.tolist() for k, v in self.MetaObj.IncidenceAngle_arrProv.items()},
meshwidth=10, # for faster processing self.shape_fullArr,
subset=None, meshwidth=10, # for faster processing
bandwise=0) subset=None,
bandwise=0)
else: else:
# only a mean VAA is available # only a mean VAA is available
if self.VAA_mean is None: if self.VAA_mean is None:
...@@ -156,11 +158,11 @@ class L1C_object(L1B_object): ...@@ -156,11 +158,11 @@ class L1C_object(L1B_object):
self._SZA_arr, self._SAA_arr = \ self._SZA_arr, self._SAA_arr = \
GEOP.calc_SZA_SAA_array( GEOP.calc_SZA_SAA_array(
self.shape_fullArr, self.arr_pos, self.shape_fullArr, self.arr_pos,
self.meta_odict['AcqDate'], self.MetaObj.AcqDate,
self.meta_odict['AcqTime'], self.MetaObj.AcqTime,
self.fullSceneCornerPos, self.fullSceneCornerPos,
self.fullSceneCornerLonLat, self.fullSceneCornerLonLat,
self.meta_odict['overpass duraction sec'], self.MetaObj.overpassDurationSec,
self.logger, self.logger,
meshwidth=10, meshwidth=10,
nodata_mask=None, # dont overwrite areas outside the image with nodata nodata_mask=None, # dont overwrite areas outside the image with nodata
...@@ -360,7 +362,7 @@ class AtmCorr(object): ...@@ -360,7 +362,7 @@ class AtmCorr(object):
# float32! -> conversion to np.float16 will convert -9999 to -10000 # float32! -> conversion to np.float16 will convert -9999 to -10000
arr2pass = inObj.arr[:, :, bandIdx].astype(np.float32) arr2pass = inObj.arr[:, :, bandIdx].astype(np.float32)
arr2pass[arr2pass == inObj.arr.nodata] = np.nan # set nodata values to np.nan arr2pass[arr2pass == inObj.arr.nodata] = np.nan # set nodata values to np.nan
data_dict[bandN] = (arr2pass / inObj.meta_odict['ScaleFactor']).astype(np.float16) data_dict[bandN] = (arr2pass / inObj.MetaObj.ScaleFactor).astype(np.float16)
else: else:
inObj.logger.warning("Band '%s' cannot be included into atmospheric correction because it " inObj.logger.warning("Band '%s' cannot be included into atmospheric correction because it "
"exists multiple times." % bandN) "exists multiple times." % bandN)
...@@ -472,14 +474,14 @@ class AtmCorr(object): ...@@ -472,14 +474,14 @@ class AtmCorr(object):
del self.logger # otherwise each input object would have multiple fileHandlers del self.logger # otherwise each input object would have multiple fileHandlers
metadata = dict( metadata = dict(
U=self.inObjs[0].meta_odict['EarthSunDist'], U=self.inObjs[0].MetaObj.EarthSunDist,
SENSING_TIME=self.inObjs[0].acq_datetime, SENSING_TIME=self.inObjs[0].acq_datetime,
# SENSING_TIME=datetime.strptime('2015-08-12 10:40:21 +0000', '%Y-%m-%d %H:%M:%S %z'), # SENSING_TIME=datetime.strptime('2015-08-12 10:40:21 +0000', '%Y-%m-%d %H:%M:%S %z'),
viewing_zenith=self._meta_get_viewing_zenith(), viewing_zenith=self._meta_get_viewing_zenith(),
viewing_azimuth=self._meta_get_viewing_azimuth(), viewing_azimuth=self._meta_get_viewing_azimuth(),
relative_viewing_azimuth=self._meta_get_relative_viewing_azimuth(), relative_viewing_azimuth=self._meta_get_relative_viewing_azimuth(),
sun_mean_azimuth=self.inObjs[0].meta_odict['SunAzimuth'], sun_mean_azimuth=self.inObjs[0].MetaObj.SunAzimuth,
sun_mean_zenith=90 - self.inObjs[0].meta_odict['SunElevation'], sun_mean_zenith=90 - self.inObjs[0].MetaObj.SunElevation,
solar_irradiance=self._meta_get_solar_irradiance(), solar_irradiance=self._meta_get_solar_irradiance(),
aux_data=self._meta_get_aux_data(), aux_data=self._meta_get_aux_data(),
spatial_samplings=self._meta_get_spatial_samplings() spatial_samplings=self._meta_get_spatial_samplings()
...@@ -950,7 +952,6 @@ class AtmCorr(object): ...@@ -950,7 +952,6 @@ class AtmCorr(object):
inObj.MetaObj.LayerBandsAssignment = out_LBA inObj.MetaObj.LayerBandsAssignment = out_LBA
inObj.LayerBandsAssignment = out_LBA inObj.LayerBandsAssignment = out_LBA
inObj.MetaObj.filter_layerdependent_metadata() inObj.MetaObj.filter_layerdependent_metadata()
inObj.meta_odict = inObj.MetaObj.to_odict() # actually auto-updated by getter
################################################################################## ##################################################################################
# join SURFACE REFLECTANCE as 3D int16 array, scaled to scale factor from config # # join SURFACE REFLECTANCE as 3D int16 array, scaled to scale factor from config #
......
...@@ -61,14 +61,26 @@ class L2B_object(L2A_object): ...@@ -61,14 +61,26 @@ class L2B_object(L2A_object):
method = CFG.spechomo_method method = CFG.spechomo_method
src_dsID = sat_sen_to_datasetid(self.satellite, self.sensor) src_dsID = sat_sen_to_datasetid(self.satellite, self.sensor)
src_cwls = self.meta_odict['wavelength'] src_cwls = [float(self.MetaObj.CWL[bN]) for bN in self.MetaObj.LayerBandsAssignment]
# FIXME exclude or include thermal bands; respect sorted CWLs in context of LayerBandsAssignment # FIXME exclude or include thermal bands; respect sorted CWLs in context of LayerBandsAssignment
tgt_sat, tgt_sen = datasetid_to_sat_sen(CFG.datasetid_spectral_ref) tgt_sat, tgt_sen = datasetid_to_sat_sen(CFG.datasetid_spectral_ref)
# NOTE: get target LBA at L2A, because spectral characteristics of target sensor do not change after AC # NOTE: get target LBA at L2A, because spectral characteristics of target sensor do not change after AC
tgt_LBA = get_LayerBandsAssignment( tgt_LBA = get_LayerBandsAssignment(
GMS_identifier(satellite=tgt_sat, sensor=tgt_sen, subsystem=None, GMS_identifier(satellite=tgt_sat, sensor=tgt_sen, subsystem='',
image_type='RSD', proc_level='L2A', dataset_ID=src_dsID, logger=None)) image_type='RSD', proc_level='L2A', dataset_ID=src_dsID, logger=None))
if CFG.datasetid_spectral_ref is None:
tgt_cwl = CFG.target_CWL
tgt_fwhm = CFG.target_FWHM
else:
# exclude those bands from CFG.target_CWL and CFG.target_FWHM that have been removed after AC
full_LBA = get_LayerBandsAssignment(
GMS_identifier(satellite=tgt_sat, sensor=tgt_sen, subsystem='',
image_type='RSD', proc_level='L1A', dataset_ID=src_dsID, logger=None),
no_thermal=True, no_pan=False, return_fullLBA=True, sort_by_cwl=True, proc_level='L1A')
tgt_cwl = [dict(zip(full_LBA, CFG.target_CWL))[bN] for bN in tgt_LBA]
tgt_fwhm = [dict(zip(full_LBA, CFG.target_FWHM))[bN] for bN in tgt_LBA]
#################################################### ####################################################
# special cases where homogenization is not needed # # special cases where homogenization is not needed #
#################################################### ####################################################
...@@ -93,7 +105,7 @@ class L2B_object(L2A_object): ...@@ -93,7 +105,7 @@ class L2B_object(L2A_object):
if method == 'LI' or CFG.datasetid_spectral_ref is None: if method == 'LI' or CFG.datasetid_spectral_ref is None:
# linear interpolation (if intended by user or in case of custom spectral characteristics of target sensor) # linear interpolation (if intended by user or in case of custom spectral characteristics of target sensor)
# -> no classifier for that case available -> linear interpolation # -> no classifier for that case available -> linear interpolation
im = SpH.interpolate_cube(self.arr, src_cwls, CFG.target_CWL, kind='linear') im = SpH.interpolate_cube(self.arr, src_cwls, tgt_cwl, kind='linear')
if CFG.spechomo_estimate_accuracy: if CFG.spechomo_estimate_accuracy:
self.logger.warning("Unable to compute any error information in case spectral homogenization algorithm " self.logger.warning("Unable to compute any error information in case spectral homogenization algorithm "
...@@ -115,7 +127,7 @@ class L2B_object(L2A_object): ...@@ -115,7 +127,7 @@ class L2B_object(L2A_object):
compute_errors=CFG.spechomo_estimate_accuracy, compute_errors=CFG.spechomo_estimate_accuracy,
bandwise_errors=CFG.spechomo_bandwise_accuracy, bandwise_errors=CFG.spechomo_bandwise_accuracy,
fallback_argskwargs=dict( fallback_argskwargs=dict(
args=dict(source_CWLs=src_cwls, target_CWLs=CFG.target_CWL,), args=dict(source_CWLs=src_cwls, target_CWLs=tgt_cwl,),
kwargs=dict(kind='linear') kwargs=dict(kind='linear')
)) ))
...@@ -124,11 +136,9 @@ class L2B_object(L2A_object): ...@@ -124,11 +136,9 @@ class L2B_object(L2A_object):
################### ###################
self.LayerBandsAssignment = tgt_LBA self.LayerBandsAssignment = tgt_LBA
self.meta_odict['wavelength'] = list(CFG.target_CWL) self.MetaObj.CWL = dict(zip(tgt_LBA, tgt_cwl))
self.meta_odict['bandwidths'] = list(CFG.target_FWHM) self.MetaObj.FWHM = dict(zip(tgt_LBA, tgt_fwhm))
self.meta_odict['bands'] = len(CFG.target_CWL) self.MetaObj.bands = len(tgt_LBA)
if 'band names' in self.meta_odict: # FIXME bug workaround
del self.meta_odict['band names'] # TODO
self.arr = im # type: GeoArray self.arr = im # type: GeoArray
self.spec_homo_errors = errs # type: Union[np.ndarray, None] # int16, None if ~CFG.spechomo_estimate_accuracy self.spec_homo_errors = errs # type: Union[np.ndarray, None] # int16, None if ~CFG.spechomo_estimate_accuracy
......
...@@ -297,8 +297,7 @@ def mask_to_ENVI_Classification(InObj, maskname): ...@@ -297,8 +297,7 @@ def mask_to_ENVI_Classification(InObj, maskname):
rows, cols = classif_array.shape[:2] rows, cols = classif_array.shape[:2]
bands = 1 if classif_array.ndim == 2 else classif_array.shape[2] bands = 1 if classif_array.ndim == 2 else classif_array.shape[2]
mapI, CSS = (InObj.meta_odict['map info'], InObj.meta_odict['coordinate system string']) \ mapI, CSS = InObj.MetaObj.map_info, InObj.MetaObj.projection
if hasattr(InObj, 'meta_odict') and InObj.meta_odict else (InObj.MetaObj.map_info, InObj.MetaObj.projection)
mask_md = {'file type': 'ENVI Classification', 'map info': mapI, 'coordinate system string': CSS, 'lines': rows, mask_md = {'file type': 'ENVI Classification', 'map info': mapI, 'coordinate system string': CSS, 'lines': rows,
'samples': cols, 'bands': bands, 'header offset': 0, 'byte order': 0, 'interleave': 'bsq', 'samples': cols, 'bands': bands, 'header offset': 0, 'byte order': 0, 'interleave': 'bsq',
'data type': 1, 'data ignore value': get_outFillZeroSaturated(classif_array.dtype)[0]} 'data type': 1, 'data ignore value': get_outFillZeroSaturated(classif_array.dtype)[0]}
......
...@@ -180,10 +180,11 @@ class path_generator(object): ...@@ -180,10 +180,11 @@ class path_generator(object):
image = self.get_path_imagedata() image = self.get_path_imagedata()
mask = self.get_path_maskdata() mask = self.get_path_maskdata()
mask_clouds = self.get_path_cloudmaskdata() mask_clouds = self.get_path_cloudmaskdata()
accuracylayers = self.get_path_accuracylayers()
gms_file = self.get_path_gmsfile() gms_file = self.get_path_gmsfile()
log_file = self.get_path_logfile() log_file = self.get_path_logfile()
all_pathes = [image, mask, mask_clouds, gms_file, log_file] all_pathes = [image, mask, mask_clouds, accuracylayers, gms_file, log_file]
warnings.warn( warnings.warn(
'get_pathes_all_procdata() is not yet completely implemented and will not return complete path list!') 'get_pathes_all_procdata() is not yet completely implemented and will not return complete path list!')
......
...@@ -85,7 +85,6 @@ class GMS_object(object): ...@@ -85,7 +85,6 @@ class GMS_object(object):
self._accuracy_layers = None self._accuracy_layers = None
self._dict_LayerOptTherm = None self._dict_LayerOptTherm = None
self._cloud_masking_algorithm = None self._cloud_masking_algorithm = None
self._meta_odict = None
self._coreg_info = None self._coreg_info = None
# defaults # defaults
...@@ -271,13 +270,8 @@ class GMS_object(object): ...@@ -271,13 +270,8 @@ class GMS_object(object):
@property @property
def MetaObj(self): def MetaObj(self):
if self._meta_odict: # TODO if there is no MetaObj -> create MetaObj by reading metadata from disk
# if there is already a meta_odict -> create a new MetaObj from it (ensures synchronization!) # reading from disk should use L1A_P.L1A_object.import_metadata -> so just return None
self._MetaObj = METADATA(self.GMS_identifier).from_odict(self._meta_odict)
del self.meta_odict
elif not self._MetaObj:
# if there is no meta_odict and no MetaObj -> create MetaObj by reading metadata from disk
pass # reading from disk should use L1A_P.L1A_object.import_metadata -> so just return None
return self._MetaObj return self._MetaObj
...@@ -287,9 +281,6 @@ class GMS_object(object): ...@@ -287,9 +281,6 @@ class GMS_object(object):
"Got %s." % type(MetaObj) "Got %s." % type(MetaObj)
self._MetaObj = MetaObj self._MetaObj = MetaObj
# update meta_odict
del self.meta_odict # it is recreated if getter is used the next time
@MetaObj.deleter @MetaObj.deleter
def MetaObj(self): def MetaObj(self):
if hasattr(self, '_MetaObj') and self._MetaObj and hasattr(self._MetaObj, 'logger') and \ if hasattr(self, '_MetaObj') and self._MetaObj and hasattr(self._MetaObj, 'logger') and \
...@@ -299,32 +290,6 @@ class GMS_object(object): ...@@ -299,32 +290,6 @@ class GMS_object(object):
self._MetaObj = None self._MetaObj = None
@property
def meta_odict(self):
if self._MetaObj:
# if there is already a MetaObj -> create new meta_odict from it (ensures synchronization!)
self._meta_odict = self._MetaObj.to_odict()
del self.MetaObj
elif not self._meta_odict:
# if there is no MetaObj and no meta_odict -> use MetaObj getter to read metadata from disk
pass # reading from disk should use L1A_P.L1A_object.import_metadata -> so just return None
self._meta_odict = None
return self._meta_odict
@meta_odict.setter
def meta_odict(self, odict):
assert isinstance(odict, (collections.OrderedDict, dict)), "'meta_odict' can only be set to an instance of " \
"collections.OrderedDict. Got %s." % type(odict)
self._meta_odict = odict
# update MetaObj
del self.MetaObj # it is recreated if getter is used the next time
@meta_odict.deleter
def meta_odict(self):
self._meta_odict = None
@property @property
def pathGen(self): def pathGen(self):
# type: () -> PG.path_generator # type: () -> PG.path_generator
...@@ -403,14 +368,14 @@ class GMS_object(object): ...@@ -403,14 +368,14 @@ class GMS_object(object):
self._coreg_info = { self._coreg_info = {
'corrected_shifts_px': {'x': 0, 'y': 0}, 'corrected_shifts_px': {'x': 0, 'y': 0},
'corrected_shifts_map': {'x': 0, 'y': 0}, 'corrected_shifts_map': {'x': 0, 'y': 0},
'original map info': self.meta_odict['map info'], 'original map info': self.MetaObj.map_info,
'updated map info': None, 'updated map info': None,
'shift_reliability': None, 'shift_reliability': None,
'reference scene ID': None, 'reference scene ID': None,
'reference entity ID': None, 'reference entity ID': None,
'reference geotransform': None, 'reference geotransform': None,
# reference projection must be the own projection in order to avoid overwriting with a wrong EPSG # reference projection must be the own projection in order to avoid overwriting with a wrong EPSG
'reference projection': self.meta_odict['coordinate system string'], 'reference projection': self.MetaObj.projection,
'reference extent': {'rows': None, 'cols': None}, 'reference extent': {'rows': None, 'cols': None},
'reference grid': [list(CFG.spatial_ref_gridx), 'reference grid': [list(CFG.spatial_ref_gridx),
list(CFG.spatial_ref_gridy)], list(CFG.spatial_ref_gridy)],
...@@ -426,7 +391,7 @@ class GMS_object(object): ...@@ -426,7 +391,7 @@ class GMS_object(object):
@property @property
def resamp_needed(self): def resamp_needed(self):
if self._resamp_needed is None: if self._resamp_needed is None:
gt = mapinfo2geotransform(self.meta_odict['map info']) gt = mapinfo2geotransform(self.MetaObj.map_info)
self._resamp_needed = not is_coord_grid_equal(gt, CFG.spatial_ref_gridx, self._resamp_needed = not is_coord_grid_equal(gt, CFG.spatial_ref_gridx,
CFG.spatial_ref_gridy) CFG.spatial_ref_gridy)
return self._resamp_needed return self._resamp_needed
...@@ -454,9 +419,6 @@ class GMS_object(object): ...@@ -454,9 +419,6 @@ class GMS_object(object):
self._arr.prj = self.MetaObj.projection if self.MetaObj.projection else self._arr.projection self._arr.prj = self.MetaObj.projection if self.MetaObj.projection else self._arr.projection
else: else:
self._arr.nodata = DEF_D.get_outFillZeroSaturated(self._arr.dtype)[0] self._arr.nodata = DEF_D.get_outFillZeroSaturated(self._arr.dtype)[0]
if hasattr(self, 'meta_odict') and self.meta_odict:
self._arr.gt = mapinfo2geotransform(self.meta_odict['map info'])
self._arr.prj = self.meta_odict['coordinate system string']
# set bandnames like this: [B01, .., B8A,] # set bandnames like this: [B01, .., B8A,]
if self.LayerBandsAssignment: if self.LayerBandsAssignment:
...@@ -471,6 +433,10 @@ class GMS_object(object): ...@@ -471,6 +433,10 @@ class GMS_object(object):
def arr(self): def arr(self):
self._arr = None self._arr = None
@property
def arr_meta(self):
return self.MetaObj.to_odict()
@property @property
def mask_nodata(self): def mask_nodata(self):
if self._mask_nodata is not None: if self._mask_nodata is not None:
...@@ -760,9 +726,9 @@ class GMS_object(object): ...@@ -760,9 +726,9 @@ class GMS_object(object):
return self._accuracy_layers return self._accuracy_layers
@accuracy_layers.setter @accuracy_layers.setter
def accuracy_layers(self, geoArr_initArgs): def accuracy_layers(self, *geoArr_initArgs):
if geoArr_initArgs[0] is not None: if geoArr_initArgs[0] is not None:
acc_lay = GeoArray(geoArr_initArgs) acc_lay = GeoArray(*geoArr_initArgs)
assert acc_lay.shape[:2] == self.arr.shape[:2],\ assert acc_lay.shape[:2] == self.arr.shape[:2],\
"The 'accuracy_layers' GeoArray can only be instanced with an array of the same dimensions like " \ "The 'accuracy_layers' GeoArray can only be instanced with an array of the same dimensions like " \
"GMS_obj.arr. Got %s." % str(acc_lay.shape) "GMS_obj.arr. Got %s." % str(acc_lay.shape)
...@@ -880,8 +846,11 @@ class GMS_object(object): ...@@ -880,8 +846,11 @@ class GMS_object(object):
# add some selected property values # add some selected property values
for i in ['GMS_identifier', 'LayerBandsAssignment', 'coreg_needed', 'coreg_info', 'resamp_needed', for i in ['GMS_identifier', 'LayerBandsAssignment', 'coreg_needed', 'coreg_info', 'resamp_needed',
'dict_LayerOptTherm', 'georef', 'meta_odict']: 'dict_LayerOptTherm', 'georef', 'MetaObj']:
out_dict[i] = getattr(self, i) if i == 'MetaObj':
out_dict['meta_odict'] = self.MetaObj.to_odict()
else:
out_dict[i] = getattr(self, i)
# remove private attributes # remove private attributes
if remove_privates: if remove_privates:
...@@ -912,7 +881,13 @@ class GMS_object(object): ...@@ -912,7 +881,13 @@ class GMS_object(object):
GMSfileDict = INP_R.GMSfile2dict(path_GMS_file) GMSfileDict = INP_R.GMSfile2dict(path_GMS_file)
# copy all attributes from GMS file (private attributes are not touched since they are not included in GMS file) # copy all attributes from GMS file (private attributes are not touched since they are not included in GMS file)
GMS_obj.meta_odict = GMSfileDict['meta_odict'] # set that first in order to make some getters and setters work
# set MetaObj first in order to make some getters and setters work
GMS_id = GMS_identifier(image_type=GMSfileDict['image_type'], satellite=GMSfileDict['satellite'],
sensor=GMSfileDict['sensor'], subsystem=GMSfileDict['subsystem'],
proc_level=GMSfileDict['proc_level'], dataset_ID=GMSfileDict['dataset_ID'], logger=None)
GMS_obj.MetaObj = METADATA(GMS_id).from_odict(GMSfileDict['meta_odict'])
for key, value in GMSfileDict.items(): for key, value in GMSfileDict.items():
if key in ['GMS_identifier', 'georef', 'dict_LayerOptTherm']: if key in ['GMS_identifier', 'georef', 'dict_LayerOptTherm']:
continue # properties that should better be created on the fly continue # properties that should better be created on the fly
...@@ -1007,12 +982,9 @@ class GMS_object(object): ...@@ -1007,12 +982,9 @@ class GMS_object(object):
bandnames = ['B%s' % i if len(i) == 2 else 'B0%s' % i for i in GMS_obj_merged.LayerBandsAssignment] bandnames = ['B%s' % i if len(i) == 2 else 'B0%s' % i for i in GMS_obj_merged.LayerBandsAssignment]
# update layer-dependent metadata with respect to remaining input GMS objects # update layer-dependent metadata with respect to remaining input GMS objects
GMS_obj_merged.meta_odict.update({ GMS_obj_merged.MetaObj.LayerBandsAssignment = GMS_obj_merged.LayerBandsAssignment
'band names': [('Band %s' % i) for i in GMS_obj_merged.LayerBandsAssignment