L2A_P.py 6.22 KB
Newer Older
Daniel Scheffler's avatar
Daniel Scheffler committed
1
# -*- coding: utf-8 -*-
Daniel Scheffler's avatar
GEOP:    
Daniel Scheffler committed
2
3
4
###############################################################################
#
#   Level 2A Processor:
5
#   Spatial homogenization
Daniel Scheffler's avatar
GEOP:    
Daniel Scheffler committed
6
7
8
#
###############################################################################
__author__='Daniel Scheffler'
Daniel Scheffler's avatar
Daniel Scheffler committed
9

10
11
12
import collections
import os
import warnings
Daniel Scheffler's avatar
Daniel Scheffler committed
13

14
15
import numpy as np

16
from geoarray import GeoArray
17
from py_tools_ds.geo.map_info import mapinfo2geotransform
18

19
20
from ..config import GMS_config as CFG
from .L1C_P import L1C_object
21
22


23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
def get_DESHIFTER_configs(dicts_GMS_obj, attrnames2deshift, proc_bandwise=False, paramsFromUsecase=True, **kwargs):
    """
    Get list of argument and keyword argument tuples as input for DESHIFTER class.

    :param dicts_GMS_obj:       list of the copied dictionaries of GMS objects, containing the attribute 'coreg_info'
    :param attrnames2deshift:   list of attribute names of the GMS object containing the array to be shifted (or a path)
    :param proc_bandwise:       True: configurations for each band of the array to be shifted are returned
                                (if DESHIFTER will be called in multiprocessing), default = False
    :param paramsFromUsecase:   True: respect the usecase parameters align_coord_grids, target_gsd and match_gsd when
                                executing DESHIFTER class, default = True

    :Keyword Arguments:
        - band2process (int):   The index of the band to be processed within the given array (starts with 1),
                                default = None (all bands are processed)
        - out_gsd (float):      output pixel size in units of the reference coordinate system (default = pixel size
                                of the input array)
        - align_grids (bool):   True: align the input coordinate grid to the reference (does not affect the
                                output pixel size as long as input and output pixel sizes are compatible
                                (5:30 or 10:30 but not 4:30), default = False
        - match_gsd (bool):     True: match the input pixel size to the reference pixel size,
                                default = False
        - no_resamp (bool):     True: force avoiding of any resampling (shifts are corrected via ENVI map info),
                                default = False
        - cliptoextent (bool):  True: clip the input image to its actual bounds while deleting possible no data
                                areas outside of the actual bounds, default = True
    """
49
50
    # FIXME diese Methode muss target grid festlegen, auch wenn keine Referenz verfügbar ist!

51
52
53
54
55
56
57
58
59
    illegal_kw = [i for i in kwargs if i not in ['align_grids','out_gsd','match_gsd','no_resamp','cliptoextent']]
    assert illegal_kw == [], "'%s' is not a legal keyword argument for L1B_P.get_DESHIFTER_configs()" %illegal_kw[0]

    dicts_GMS_obj     = [dicts_GMS_obj]     if not isinstance(dicts_GMS_obj,list)     else dicts_GMS_obj
    attrnames2deshift = [attrnames2deshift] if not isinstance(attrnames2deshift,list) else attrnames2deshift

    # get general kwargs
    gen_kwargs = collections.OrderedDict()
    if paramsFromUsecase:
60
61
62
        gen_kwargs.update({'align_grids':CFG.usecase.align_coord_grids})
        gen_kwargs.update({'out_gsd'    :CFG.usecase.target_gsd})
        gen_kwargs.update({'match_gsd'  :CFG.usecase.match_gsd})
63
64
65
66
67
68
    else:
        [gen_kwargs.update({kw:kwargs.get(kw)}) for kw in ['align_grids','out_gsd','match_gsd'] if kw in kwargs]
    [gen_kwargs.update({kw:kwargs.get(kw)}) for kw in ['no_resamp','cliptoextent'] if kw in kwargs]

    config_dicts = []
    for obj in dicts_GMS_obj:
69
70
71
72

        # FIXME workaround für fehlende refererence geotransform -> eigentlich müsste nicht gt, sondern target grid berechnet werden
        assert isinstance(obj,dict)
        if not obj['coreg_info']['reference geotransform']:
73
            obj['coreg_info']['reference geotransform']    = mapinfo2geotransform(
74
                                                                obj['coreg_info']['original map info'])
75
76
            obj['coreg_info']['reference geotransform'][1] = CFG.usecase.target_gsd[0]
            obj['coreg_info']['reference geotransform'][5] = -abs(CFG.usecase.target_gsd[1])
77

78
79
        item2add = [obj]
        for attrname in attrnames2deshift:
80
            attrVal      = obj[attrname]
81
            attritem2add = item2add+[attrname]
82
83
84
85
86
87

            if isinstance(attrVal,np.ndarray) or isinstance(attrVal,GeoArray) and attrVal.is_inmem:
                bands = attrVal.shape[2] if attrVal.ndim==3 else None
            elif isinstance(attrVal,GeoArray) and not attrVal.is_inmem:
                if os.path.exists(attrVal):
                    bands = attrVal.bands
88
                else:
89
                    warnings.warn('get_DESHIFTER_configs: Missing file %s. File skipped.' % attrVal)
90
                    continue
91
            elif attrVal is None:
92
93
                continue
            else:
94
                raise Exception('Unexpected attribute type %s in attribute %s.' %(type(attrVal),attrname))
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116

            if proc_bandwise and bands is not None and 'band2process' not in kwargs:
                for bI in range(bands):
                    kwargs2add = collections.OrderedDict()
                    kwargs2add.update({'band2process':bI+1})
                    kwargs2add.update(gen_kwargs)
                    banditem2add = attritem2add+[kwargs2add]
                    config_dicts.append(banditem2add)
            elif 'band2process' in kwargs and kwargs.get('band2process') is not None:
                assert isinstance(kwargs.get('band2process'),int), "'band2process' must contain an integer."
                kwargs2add = collections.OrderedDict({'band2process':kwargs.get('band2process')})
                kwargs2add.update(gen_kwargs)
                attritem2add.append(kwargs2add)
                config_dicts.append(attritem2add)
            else:
                kwargs2add = collections.OrderedDict(gen_kwargs)
                attritem2add.append(kwargs2add)
                config_dicts.append(attritem2add)
    return config_dicts


class L2A_object(L1C_object):
117
118
119
120
121
122
123
    def __init__(self, L1C_obj=None):
        super().__init__()

        if L1C_obj:
            # populate attributes
            [setattr(self, key, value) for key,value in L1C_obj.__dict__.items()]

124
        self.proc_level  = 'L2A'