Esempio n. 1
0
def geocode(scene,
            dem,
            tempdir,
            outdir,
            targetres,
            scaling='linear',
            func_geoback=1,
            func_interp=2,
            nodata=(0, -99),
            sarSimCC=False,
            osvdir=None,
            allow_RES_OSV=False,
            cleanup=True,
            normalization_method=2,
            export_extra=None):
    """
    general function for geocoding SAR images with GAMMA
    
    Parameters
    ----------
    scene: str or ~pyroSAR.drivers.ID
        the SAR scene to be processed
    dem: str
        the reference DEM in GAMMA format
    tempdir: str
        a temporary directory for writing intermediate files
    outdir: str
        the directory for the final GeoTiff output files
    targetres: int
        the target resolution in meters
    scaling: {'linear', 'db'} or list
        the value scaling of the backscatter values; either 'linear', 'db' or a list of both, i.e. ['linear', 'db']
    func_geoback: {0, 1, 2, 3, 4, 5, 6, 7}
        backward geocoding interpolation mode (see GAMMA command geocode_back)
         - 0: nearest-neighbor
         - 1: bicubic spline (default)
         - 2: bicubic-spline, interpolate log(data)
         - 3: bicubic-spline, interpolate sqrt(data)
         - 4: B-spline interpolation (default B-spline degree: 5)
         - 5: B-spline interpolation sqrt(x) (default B-spline degree: 5)
         - 6: Lanczos interpolation (default Lanczos function order: 5)
         - 7: Lanczos interpolation sqrt(x) (default Lanczos function order: 5)

        NOTE: log and sqrt interpolation modes should only be used with non-negative data!
        
        NOTE: Gamma reccomendation for MLI data: "The interpolation should be performed on
        the square root of the data. A mid-order (3 to 5) B-spline interpolation is recommended."
    func_interp: {0, 1, 2, 3}
        output lookup table values in regions of layover, shadow, or DEM gaps (see GAMMA command gc_map)
         - 0: set to (0., 0.)
         - 1: linear interpolation across these regions
         - 2: actual value
         - 3: nn-thinned
    nodata: tuple
        the nodata values for the output files; defined as a tuple with two values, the first for linear,
        the second for logarithmic scaling
    sarSimCC: bool
        perform geocoding with SAR simulation cross correlation?
        If False, geocoding is performed with the Range-Doppler approach using orbit state vectors
    osvdir: str
        a directory for Orbit State Vector files;
        this is currently only used by for Sentinel-1 where two subdirectories POEORB and RESORB are created;
        if set to None, a subdirectory OSV is created in the directory of the unpacked scene.
    allow_RES_OSV: bool
        also allow the less accurate RES orbit files to be used?
        Otherwise the function will raise an error if no POE file exists
    cleanup: bool
        should all files written to the temporary directory during function execution be deleted after processing?
    normalization_method: {1, 2}
        the topographic normalization approach to be used
         - 1: first geocoding, then terrain flattening
         - 2: first terrain flattening, then geocoding; see `Small 2011 <https://doi.org/10.1109/Tgrs.2011.2120616>`_
    export_extra: list or None
        a list of image file IDs to be exported to outdir
         - format is GeoTiff if the file is geocoded and ENVI otherwise. Non-geocoded images can be converted via Gamma
           command data2tiff yet the output was found impossible to read with GIS software
         - scaling of SAR image products is applied as defined by parameter `scaling`
         - see Notes for ID options
    
    Returns
    -------
    
    Note
    ----
    | intermediate output files
    | DEM products are named <scene identifier>_<ID>, e.g. `S1A__IW___A_20141012T162337_inc_geo`
    | SAR products will additionally contain the polarization, e.g. `S1A__IW___A_20141012T162337_VV_grd_mli`
    | IDs in brackets are only written if selected by `export_extra`
    
    - images in range-Doppler geometry
     
      * **grd**: the ground range detected SAR intensity image
      * **grd_mli**: the multi-looked grd image with approached target resolution
      * specific to normalization method 2:
      
        + **pix_ellip_sigma0**: ellipsoid-based pixel area
        + **pix_area_sigma0**: actual illuminated area as obtained from integrating DEM-facets (command pixel_area)
        + **pix_fine**: refined pixel area normalization factor (pix_ellip_sigma0 / pix_area_sigma0)
        + **grd_mli_pan**: the pixel area normalized MLI (grd_mli * pix_fine)
     
    - images in map geometry
     
      * **dem_seg_geo**: dem subsetted to the extent of the intersect between input DEM and SAR image
      * (**u_geo**): zenith angle of surface normal vector n (angle between z and n)
      * (**v_geo**): orientation angle of n (between x and projection of n in xy plane)
      * **inc_geo**: local incidence angle (between surface normal and look vector)
      * (**psi_geo**): projection angle (between surface normal and image plane normal)
      * **pix_geo**: pixel area normalization factor (command gc_map)
      * **ls_map_geo**: layover and shadow map (in map projection)
      * (**sim_sar_geo**): simulated SAR backscatter image
     
    - additional files
     
      * **lut_init**: initial geocoding lookup table
     
    - files specific to SAR simulation cross-correlation geocoding
     
      * **lut_fine**: refined geocoding lookup table
      * **diffpar**: ISP offset/interferogram parameter file
      * **offs**: offset estimates (fcomplex)
      * **coffs**: culled range and azimuth offset estimates (fcomplex)
      * **coffsets**: culled offset estimates and cross correlation values (text format)
      * **ccp**: cross-correlation of each patch (0.0->1.0) (float)
    
    Examples
    --------
    geocode a Sentinel-1 scene and export the local incidence angle map with it
    
    >>> from pyroSAR.gamma import geocode
    >>> filename = 'S1A_IW_GRDH_1SDV_20180829T170656_20180829T170721_023464_028DE0_F7BD.zip'
    >>> geocode(scene=filename, dem='demfile', outdir='outdir', targetres=20, scaling='db',
    >>>         export_extra=['dem_seg_geo', 'inc_geo', 'ls_map_geo'])
    
    .. figure:: figures/gamma_geocode.png
        :scale: 25%
        :align: center
        
        Workflow diagram for function geocode using normalization method 2 for processing a Sentinel-1 Ground Range
        Detected (GRD) scene to radiometrically terrain corrected (RTC) backscatter.
    """
    if normalization_method == 2 and func_interp != 2:
        raise RuntimeError(
            'parameter func_interp must be set to 2 if normalization_method is set to 2; '
            'see documentation of Gamma command pixel_area')

    if isinstance(scene, ID):
        scene = identify(scene.scene)
    elif isinstance(scene, str):
        scene = identify(scene)
    else:
        raise RuntimeError("'scene' must be of type str or pyroSAR.ID")

    if scene.sensor not in ['S1A', 'S1B']:
        raise IOError(
            'this method is currently only available for Sentinel-1. Please stay tuned...'
        )

    if sarSimCC:
        raise IOError(
            'geocoding with cross correlation offset refinement is still in the making. Please stay tuned...'
        )

    if export_extra is not None and not isinstance(export_extra, list):
        raise TypeError(
            "parameter 'export_extra' must either be None or a list")

    for dir in [tempdir, outdir]:
        if not os.path.isdir(dir):
            os.makedirs(dir)

    if scene.is_processed(outdir):
        print('scene {} already processed'.format(scene.outname_base()))
        return

    scaling = [scaling] if isinstance(
        scaling, str) else scaling if isinstance(scaling, list) else []
    scaling = union(scaling, ['db', 'linear'])
    if len(scaling) == 0:
        raise IOError('wrong input type for parameter scaling')

    if scene.compression is not None:
        print('unpacking scene..')
        try:
            scene.unpack(tempdir)
        except RuntimeError:
            print('scene was attempted to be processed before, exiting')
            return
    else:
        scene.scene = os.path.join(tempdir, os.path.basename(scene.file))
        os.makedirs(scene.scene)

    shellscript = os.path.join(scene.scene,
                               scene.outname_base() + '_commands.sh')

    path_log = os.path.join(scene.scene, 'logfiles')
    if not os.path.isdir(path_log):
        os.makedirs(path_log)

    if scene.sensor in ['S1A', 'S1B']:
        print('removing border noise..')
        scene.removeGRDBorderNoise()

    print('converting scene to GAMMA format..')
    convert2gamma(scene,
                  scene.scene,
                  logpath=path_log,
                  outdir=scene.scene,
                  shellscript=shellscript)

    if scene.sensor in ['S1A', 'S1B']:
        print('updating orbit state vectors..')
        if allow_RES_OSV:
            osvtype = ['POE', 'RES']
        else:
            osvtype = 'POE'
        try:
            correctOSV(id=scene,
                       osvdir=osvdir,
                       osvType=osvtype,
                       logpath=path_log,
                       outdir=scene.scene,
                       shellscript=shellscript)
        except RuntimeError:
            print('orbit state vector correction failed for scene {}'.format(
                scene.scene))
            return

    calibrate(scene,
              scene.scene,
              logpath=path_log,
              outdir=scene.scene,
              shellscript=shellscript)

    images = [
        x for x in scene.getGammaImages(scene.scene)
        if x.endswith('_grd') or x.endswith('_slc_cal')
    ]

    products = list(images)

    print('multilooking..')
    for image in images:
        multilook(infile=image,
                  outfile=image + '_mli',
                  targetres=targetres,
                  logpath=path_log,
                  outdir=scene.scene,
                  shellscript=shellscript)

    images = [x + '_mli' for x in images]
    products.extend(images)

    master = images[0]

    # create output names for files to be written
    # appreciated files will be written
    # depreciated files will be set to '-' in the GAMMA function call and are thus not written
    n = Namespace(scene.scene, scene.outname_base())
    n.appreciate(
        ['dem_seg_geo', 'lut_init', 'pix_geo', 'inc_geo', 'ls_map_geo'])
    n.depreciate(['sim_sar_geo', 'u_geo', 'v_geo', 'psi_geo'])

    # if sarSimCC:
    #     n.appreciate(['ccp', 'lut_fine'])

    if export_extra is not None:
        n.appreciate(export_extra)

    ovs_lat, ovs_lon = ovs(dem + '.par', targetres)

    master_par = ISPPar(master + '.par')

    gc_map_args = {
        'DEM_par': dem + '.par',
        'DEM': dem,
        'DEM_seg_par': n.dem_seg_geo + '.par',
        'DEM_seg': n.dem_seg_geo,
        'lookup_table': n.lut_init,
        'lat_ovr': ovs_lat,
        'lon_ovr': ovs_lon,
        'sim_sar': n.sim_sar_geo,
        'u': n.u_geo,
        'v': n.v_geo,
        'inc': n.inc_geo,
        'psi': n.psi_geo,
        'pix': n.pix_geo,
        'ls_map': n.ls_map_geo,
        'frame': 8,
        'ls_mode': func_interp,
        'logpath': path_log,
        'shellscript': shellscript,
        'outdir': scene.scene
    }

    print('creating DEM products..')
    if master_par.image_geometry == 'GROUND_RANGE':
        gc_map_args.update({'GRD_par': master + '.par'})
        diff.gc_map_grd(**gc_map_args)
    else:
        gc_map_args.update({'MLI_par': master + '.par', 'OFF_par': '-'})
        diff.gc_map(**gc_map_args)

    for item in [
            'dem_seg_geo', 'sim_sar_geo', 'u_geo', 'v_geo', 'psi_geo',
            'pix_geo', 'inc_geo', 'ls_map_geo'
    ]:
        if n.isappreciated(item):
            mods = {'data_type': 1} if item == 'ls_map_geo' else None
            par2hdr(n.dem_seg_geo + '.par', n.get(item) + '.hdr', mods)

    sim_width = ISPPar(n.dem_seg_geo + '.par').width

    if sarSimCC:
        raise IOError(
            'geocoding with cross correlation offset refinement is still in the making. Please stay tuned...'
        )
    else:
        lut_final = n.lut_init

    ######################################################################
    # normalization and backward geocoding approach 1 ####################
    ######################################################################
    print('geocoding and normalization..')
    if normalization_method == 1:
        method_suffix = 'geo_norm'
        for image in images:
            diff.geocode_back(data_in=image,
                              width_in=master_par.range_samples,
                              lookup_table=lut_final,
                              data_out=image + '_geo',
                              width_out=sim_width,
                              interp_mode=func_geoback,
                              logpath=path_log,
                              outdir=scene.scene,
                              shellscript=shellscript)
            par2hdr(n.dem_seg_geo + '.par', image + '_geo.hdr')
            lat.product(data_1=image + '_geo',
                        data_2=n.pix_geo,
                        product=image + '_geo_pan',
                        width=sim_width,
                        bx=1,
                        by=1,
                        logpath=path_log,
                        outdir=scene.scene,
                        shellscript=shellscript)
            par2hdr(n.dem_seg_geo + '.par', image + '_geo_pan.hdr')
            lat.sigma2gamma(pwr1=image + '_geo_pan',
                            inc=n.inc_geo,
                            gamma=image + '_{}'.format(method_suffix),
                            width=sim_width,
                            logpath=path_log,
                            outdir=scene.scene,
                            shellscript=shellscript)
            par2hdr(n.dem_seg_geo + '.par',
                    image + '_{}.hdr'.format(method_suffix))
            products.extend([image + '_geo', image + '_geo_pan'])
    ######################################################################
    # normalization and backward geocoding approach 2 ####################
    ######################################################################
    elif normalization_method == 2:
        method_suffix = 'norm_geo'
        # newer versions of Gamma enable creating the ratio of ellipsoid based
        # pixel area and DEM-facet pixel area directly with command pixel_area
        if hasarg(diff.pixel_area, 'sigma0_ratio'):
            n.appreciate(['pix_fine'])
            n.depreciate(['pix_area_sigma0'])
            diff.pixel_area(MLI_par=master + '.par',
                            DEM_par=n.dem_seg_geo + '.par',
                            DEM=n.dem_seg_geo,
                            lookup_table=lut_final,
                            ls_map=n.ls_map_geo,
                            inc_map=n.inc_geo,
                            pix_sigma0=n.pix_area_sigma0,
                            sigma0_ratio=n.pix_fine,
                            logpath=path_log,
                            outdir=scene.scene,
                            shellscript=shellscript)
            par2hdr(master + '.par', n.pix_fine + '.hdr')
        else:
            n.appreciate(['pix_area_sigma0', 'pix_ellip_sigma0', 'pix_fine'])
            # actual illuminated area as obtained from integrating DEM-facets (pix_area_sigma0 | pix_area_gamma0)
            diff.pixel_area(MLI_par=master + '.par',
                            DEM_par=n.dem_seg_geo + '.par',
                            DEM=n.dem_seg_geo,
                            lookup_table=lut_final,
                            ls_map=n.ls_map_geo,
                            inc_map=n.inc_geo,
                            pix_sigma0=n.pix_area_sigma0,
                            logpath=path_log,
                            outdir=scene.scene,
                            shellscript=shellscript)
            par2hdr(master + '.par', n.pix_area_sigma0 + '.hdr')
            # ellipsoid-based pixel area (ellip_pix_sigma0)
            isp.radcal_MLI(
                MLI=master,
                MLI_par=master + '.par',
                OFF_par='-',
                CMLI=master + '_cal',
                refarea_flag=
                1,  # calculate sigma0, scale area by sin(inc_ang)/sin(ref_inc_ang)
                pix_area=n.pix_ellip_sigma0,
                logpath=path_log,
                outdir=scene.scene,
                shellscript=shellscript)
            par2hdr(master + '.par', n.pix_ellip_sigma0 + '.hdr')
            par2hdr(master + '.par', master + '_cal.hdr')
            # ratio of ellipsoid based pixel area and DEM-facet pixel area
            lat.ratio(d1=n.pix_ellip_sigma0,
                      d2=n.pix_area_sigma0,
                      ratio=n.pix_fine,
                      width=master_par.range_samples,
                      bx=1,
                      by=1,
                      logpath=path_log,
                      outdir=scene.scene,
                      shellscript=shellscript)
            par2hdr(master + '.par', n.pix_fine + '.hdr')
        for image in images:
            # sigma0 = MLI * ellip_pix_sigma0 / pix_area_sigma0
            # gamma0 = MLI * ellip_pix_sigma0 / pix_area_gamma0
            lat.product(data_1=image,
                        data_2=n.pix_fine,
                        product=image + '_pan',
                        width=master_par.range_samples,
                        bx=1,
                        by=1,
                        logpath=path_log,
                        outdir=scene.scene,
                        shellscript=shellscript)
            par2hdr(master + '.par', image + '_pan.hdr')
            diff.geocode_back(data_in=image + '_pan',
                              width_in=master_par.range_samples,
                              lookup_table=lut_final,
                              data_out=image + '_pan_geo',
                              width_out=sim_width,
                              interp_mode=func_geoback,
                              logpath=path_log,
                              outdir=scene.scene,
                              shellscript=shellscript)
            par2hdr(n.dem_seg_geo + '.par', image + '_pan_geo.hdr')
            lat.sigma2gamma(pwr1=image + '_pan_geo',
                            inc=n.inc_geo,
                            gamma=image + '_{}'.format(method_suffix),
                            width=sim_width,
                            logpath=path_log,
                            outdir=scene.scene,
                            shellscript=shellscript)
            par2hdr(n.dem_seg_geo + '.par',
                    image + '_{}.hdr'.format(method_suffix))
            products.extend([image + '_pan', image + '_pan_geo'])
    else:
        raise RuntimeError('unknown option for normalization_method')
    ######################################################################
    print('conversion to (dB and) geotiff..')

    def exporter(data_in, outdir, nodata, scale='linear', dtype=2):
        if scale == 'db':
            if re.search('_geo', os.path.basename(data_in)):
                width = sim_width
                refpar = n.dem_seg_geo + '.par'
            else:
                width = master_par.range_samples
                refpar = master + '.par'
            lat.linear_to_dB(data_in=data_in,
                             data_out=data_in + '_db',
                             width=width,
                             inverse_flag=0,
                             null_value=nodata,
                             logpath=path_log,
                             outdir=scene.scene,
                             shellscript=shellscript)
            par2hdr(refpar, data_in + '_db.hdr')
            data_in += '_db'
        if re.search('_geo', os.path.basename(data_in)):
            outfile = os.path.join(outdir, os.path.basename(data_in) + '.tif')
            disp.data2geotiff(DEM_par=n.dem_seg_geo + '.par',
                              data=data_in,
                              type=dtype,
                              GeoTIFF=outfile,
                              nodata=nodata,
                              logpath=path_log,
                              outdir=scene.scene,
                              shellscript=shellscript)

        else:
            outfile = os.path.join(outdir, os.path.basename(data_in))
            shutil.copyfile(data_in, outfile)
            shutil.copyfile(data_in + '.hdr', outfile + '.hdr')

    for image in images:
        for scale in scaling:
            exporter(data_in=image + '_{}'.format(method_suffix),
                     scale=scale,
                     dtype=2,
                     nodata=dict(zip(('linear', 'db'), nodata))[scale],
                     outdir=outdir)

    if scene.sensor in ['S1A', 'S1B']:
        shutil.copyfile(
            os.path.join(scene.scene, 'manifest.safe'),
            os.path.join(outdir,
                         scene.outname_base() + '_manifest.safe'))

    if export_extra is not None:
        print('exporting extra products..')
        for key in export_extra:
            # SAR image products
            product_match = [x for x in products if x.endswith(key)]
            if len(product_match) > 0:
                for product in product_match:
                    for scale in scaling:
                        exporter(data_in=product,
                                 outdir=outdir,
                                 scale=scale,
                                 dtype=2,
                                 nodata=dict(zip(('linear', 'db'),
                                                 nodata))[scale])
            # ancillary (DEM) products
            elif n.isfile(key) and key not in ['lut_init']:
                filename = n[key]
                dtype = 5 if key == 'ls_map_geo' else 2
                nodata = 0
                exporter(filename, outdir, dtype=dtype, nodata=nodata)
            else:
                print('cannot not export file {}'.format(key))

    shutil.copyfile(shellscript,
                    os.path.join(outdir, os.path.basename(shellscript)))

    if cleanup:
        print('cleaning up temporary files..')
        shutil.rmtree(scene.scene)
Esempio n. 2
0
    def envidict(self):
        """
        export relevant metadata to a ENVI HDR file compliant format
        
        Returns
        -------
        dict
        """
        out = dict(bands=1,
                   header_offset=0,
                   file_type='ENVI Standard',
                   interleave='bsq',
                   sensor_type='Unknown',
                   byte_order=1,
                   wavelength_units='Unknown')

        out['samples'] = getattr(
            self,
            union(['width', 'range_samples', 'samples'], self.keys)[0])
        out['lines'] = getattr(
            self,
            union(['nlines', 'azimuth_lines', 'lines'], self.keys)[0])

        dtypes_lookup = {
            'FCOMPLEX': 6,
            'FLOAT': 4,
            'REAL*4': 4,
            'INTEGER*2': 2,
            'SHORT': 12
        }
        dtype = getattr(self,
                        union(['data_format', 'image_format'], self.keys)[0])

        if dtype == 'SCOMPLEX':
            raise TypeError(
                'unsupported data type: SCOMPLEX (2x16 bit complex)')

        out['data_type'] = dtypes_lookup[dtype]

        if out['data_type'] == 6:
            out['complex_function'] = 'Power'
        # projections = ['AEAC', 'EQA', 'LCC', 'LCC2', 'OMCH', 'PC', 'PS', 'SCH', 'TM', 'UTM']
        if hasattr(self, 'DEM_projection'):
            if self.DEM_projection == 'UTM':
                hem = 'North' if float(self.false_northing) == 0 else 'South'
                out['map_info'] = [
                    'UTM', '1.0000', '1.0000', self.corner_east,
                    self.corner_north,
                    str(abs(float(self.post_east))),
                    str(abs(float(self.post_north))), self.projection_zone,
                    hem, 'WGS-84', 'units=Meters'
                ]
            elif self.DEM_projection == 'EQA':
                out['map_info'] = [
                    'Geographic Lat/Lon', '1.0000', '1.0000', self.corner_lon,
                    self.corner_lat,
                    str(abs(float(self.post_lon))),
                    str(abs(float(self.post_lat))), 'WGS-84', 'units=Degrees'
                ]
            else:
                raise RuntimeError('unsupported projection')
        return out
Esempio n. 3
0
def test_union():
    assert anc.union([1], [1]) == [1]
Esempio n. 4
0
def geocode(scene, dem, tempdir, outdir, targetres, scaling='linear', func_geoback=2,
            func_interp=0, nodata=(0, -99), sarSimCC=False, osvdir=None, allow_RES_OSV=False, cleanup=True):
    """
    general function for geocoding SAR images with GAMMA
    
    Parameters
    ----------
    scene: str or ~pyroSAR.drivers.ID
        the SAR scene to be processed
    dem: str
        the reference DEM in GAMMA format
    tempdir: str
        a temporary directory for writing intermediate files
    outdir: str
        the directory for the final GeoTiff output files
    targetres: int
        the target resolution in meters
    scaling: {'linear', 'db'} or list
        the value scaling of the backscatter values; either 'linear', 'db' or a list of both, i.e. ['linear', 'db']
    func_geoback: {0, 1, 2, 3}
        backward geocoding interpolation mode (see GAMMA command geocode_back)
         * 0: nearest-neighbor
         * 1: bicubic spline
         * 2: bicubic-log spline, interpolates log(data)
         * 3: bicubic-sqrt spline, interpolates sqrt(data)

        NOTE: bicubic-log spline and bicubic-sqrt spline modes should only be used with non-negative data!
    func_interp: {0, 1, 2, 3}
        output lookup table values in regions of layover, shadow, or DEM gaps (see GAMMA command gc_map)
         * 0: set to (0., 0.)
         * 1: linear interpolation across these regions
         * 2: actual value
         * 3: nn-thinned
    nodata: tuple
        the nodata values for the output files; defined as a tuple with two values, the first for linear,
        the second for logarithmic scaling
    sarSimCC: bool
        perform geocoding with SAR simulation cross correlation?
        If False, geocoding is performed with the Range-Doppler approach using orbit state vectors
    osvdir: str
        a directory for Orbit State Vector files;
        this is currently only used by for Sentinel-1 where two subdirectories POEORB and RESORB are created;
        if set to None, a subdirectory OSV is created in the directory of the unpacked scene.
    allow_RES_OSV: bool
        also allow the less accurate RES orbit files to be used?
        Otherwise the function will raise an error if no POE file exists
    cleanup: bool
        should all files written to the temporary directory during function execution be deleted after processing?
    
    Returns
    -------
    
    Note
    ----
    intermediate output files (named <master_MLI>_<suffix>):
     * dem_seg: dem subsetted to the extent of the SAR image
     * lut: rough geocoding lookup table
     * lut_fine: fine geocoding lookup table
     * sim_map: simulated SAR backscatter image in DEM geometry
     * sim_sar: simulated SAR backscatter image in SAR geometry
     * u: zenith angle of surface normal vector n (angle between z and n)
     * v: orientation angle of n (between x and projection of n in xy plane)
     * inc: local incidence angle (between surface normal and look vector)
     * psi: projection angle (between surface normal and image plane normal)
     * pix: pixel area normalization factor
     * ls_map: layover and shadow map (in map projection)
     * diffpar: ISP offset/interferogram parameter file
     * offs: offset estimates (fcomplex)
     * coffs: culled range and azimuth offset estimates (fcomplex)
     * coffsets: culled offset estimates and cross correlation values (text format)
     * ccp: cross-correlation of each patch (0.0->1.0) (float)
    
    """
    
    scene = scene if isinstance(scene, ID) else identify(scene)
    
    if scene.sensor not in ['S1A', 'S1B']:
        raise IOError('this method is currently only available for Sentinel-1. Please stay tuned...')
    
    if sarSimCC:
        raise IOError('geocoding with cross correlation offset refinement is still in the making. Please stay tuned...')
    
    for dir in [tempdir, outdir]:
        if not os.path.isdir(dir):
            os.makedirs(dir)
    
    if scene.is_processed(outdir):
        print('scene {} already processed'.format(scene.outname_base()))
        return
    
    scaling = [scaling] if isinstance(scaling, str) else scaling if isinstance(scaling, list) else []
    scaling = union(scaling, ['db', 'linear'])
    if len(scaling) == 0:
        raise IOError('wrong input type for parameter scaling')
    
    if scene.compression is not None:
        print('unpacking scene..')
        try:
            scene.unpack(tempdir)
        except RuntimeError:
            print('scene was attempted to be processed before, exiting')
            return
    else:
        scene.scene = os.path.join(tempdir, os.path.basename(scene.file))
        os.makedirs(scene.scene)
    
    logdir = os.path.join(scene.scene, 'logfiles')
    if not os.path.isdir(logdir):
        os.makedirs(logdir)
    
    if scene.sensor in ['S1A', 'S1B']:
        print('removing border noise..')
        scene.removeGRDBorderNoise()
    
    print('converting scene to GAMMA format..')
    convert2gamma(scene, scene.scene)
    
    if scene.sensor in ['S1A', 'S1B']:
        print('updating orbit state vectors..')
        if allow_RES_OSV:
            osvtype = ['POE', 'RES']
        else:
            osvtype = 'POE'
        try:
            correctOSV(id=scene, osvdir=osvdir, logpath=logdir, osvType=osvtype)
        except RuntimeError:
            return
    
    calibrate(scene, scene.scene)
    
    images = [x for x in scene.getGammaImages(scene.scene) if x.endswith('_grd') or x.endswith('_slc_cal')]
    
    print('multilooking..')
    for image in images:
        multilook(image, image + '_mli', targetres)
    
    images = [x + '_mli' for x in images]
    
    master = images[0]
    
    # create output names for files to be written
    # appreciated files will be written
    # depreciated files will be set to '-' in the GAMMA function call and are thus not written
    n = Namespace(scene.scene, scene.outname_base())
    n.appreciate(['dem_seg', 'lut_coarse', 'lut_fine', 'pix', 'ccp', 'inc', 'ls_map'])
    n.depreciate(['sim_map', 'u', 'v', 'psi'])
    
    # if sarSimCC:
    #     n.appreciate(['ls_map'])
    
    ovs_lat, ovs_lon = ovs(dem + '.par', targetres)
    
    path_log = os.path.join(scene.scene, 'logfiles')
    if not os.path.isdir(path_log):
        os.makedirs(path_log)
    
    master_par = ISPPar(master + '.par')
    
    gc_map_args = [dem + '.par', dem, n.dem_seg + '.par', n.dem_seg, n.lut_coarse,
                   ovs_lat, ovs_lon, n.sim_map, n.u, n.v, n.inc, n.psi, n.pix, n.ls_map,
                   8, func_interp]
    
    print('SAR image simulation from DEM..')
    if master_par.image_geometry == 'GROUND_RANGE':
        process(['gc_map_grd', master + '.par'] + gc_map_args, logpath=path_log)
    else:
        process(['gc_map', master + '.par', '-'] + gc_map_args, logpath=path_log)
    
    for item in ['dem_seg', 'sim_map', 'u', 'v', 'psi', 'pix', 'inc']:
        if n.isappreciated(item):
            par2hdr(n.dem_seg + '.par', n.get(item) + '.hdr')
    
    sim_width = ISPPar(n.dem_seg + '.par').width
    
    if sarSimCC:
        raise IOError('geocoding with cross correlation offset refinement is still in the making. Please stay tuned...')
    else:
        lut_final = n.lut_coarse
    
    ######################################################################
    # normalization and backward geocoding approach 1 ####################
    ######################################################################
    print('geocoding and normalization..')
    for image in images:
        process(
            ['geocode_back', image, master_par.range_samples, lut_final, image + '_geo', sim_width, '-', func_geoback],
            logpath=path_log)
        process(['product', image + '_geo', n.pix, image + '_geo_pan', sim_width, 1, 1, 0], logpath=path_log)
        process(['lin_comb', 1, image + '_geo_pan', 0, math.cos(math.radians(master_par.incidence_angle)),
                 image + '_geo_pan_flat', sim_width], logpath=path_log)
        process(['sigma2gamma', image + '_geo_pan_flat', n.inc, image + '_geo_norm', sim_width], logpath=path_log)
        par2hdr(n.dem_seg + '.par', image + '_geo_norm.hdr')
    ######################################################################
    # normalization and backward geocoding approach 2 ####################
    ######################################################################
    # process(['pixel_area', master+'.par', dem_seg+'.par', dem_seg, lut_fine, ls_map, inc, pixel_area_fine], logpath=path_log)
    # process(['radcal_MLI', master, master+'.par', '-', master+'_cal', '-', 0, 0, 1, 0.0, '-', ellipse_pixel_area], logpath=path_log)
    # process(['ratio', ellipse_pixel_area, pixel_area_fine, ratio_sigma0, master_par.range_samples, 1, 1], logpath=path_log)
    #
    # for image in images:
    #     process(['product', image, ratio_sigma0, image+'_pan', master_par.range_samples, 1, 1], logpath=path_log)
    #     process(['geocode_back', image+'_pan', master_par.range_samples, lut_fine, image+'_pan_geo', sim_width, 0, func_geoback], logpath=path_log)
    #     process(['lin_comb', 1, image+'_pan_geo', 0, math.cos(math.radians(master_par.incidence_angle)), image+'_pan_geo_flat', sim_width], logpath=path_log)
    #     process(['sigma2gamma', image+'_pan_geo_flat', inc, image+'_geo_norm', sim_width], logpath=path_log)
    #     par2hdr(dem_seg+'.par', image+'_geo_norm.hdr')
    ######################################################################
    print('conversion to (dB and) geotiff..')
    for image in images:
        for scale in scaling:
            if scale == 'db':
                nodata_out = nodata[1]
                process(['linear_to_dB', image + '_geo_norm', image + '_geo_norm_db', sim_width, 0, nodata_out],
                        logpath=path_log)
                par2hdr(n.dem_seg + '.par', image + '_geo_norm_db.hdr')
            else:
                nodata_out = nodata[0]
            suffix = {'linear': '', 'db': '_db'}[scale]
            infile = image + '_geo_norm{}'.format(suffix)
            outfile = os.path.join(outdir, os.path.basename(image) + '_geo_norm{}.tif'.format(suffix))
            
            process(['data2geotiff', n.dem_seg + '.par', infile, 2, outfile, nodata_out], logpath=path_log)
    
    if scene.sensor in ['S1A', 'S1B']:
        shutil.copyfile(os.path.join(scene.scene, 'manifest.safe'),
                        os.path.join(outdir, scene.outname_base() + '_manifest.safe'))
    if cleanup:
        print('cleaning up temporary files..')
        shutil.rmtree(scene.scene)
Esempio n. 5
0
 def __check_dict_keys(keys, reference):
     return len(union(keys, reference)) == len(keys)
Esempio n. 6
0
    def envidict(self, nodata=None):
        """
        export relevant metadata to a ENVI HDR file compliant format
        
        Parameters
        ----------
        nodata: int, float or None
            a no data value to write to the HDR file via attribute 'data ignore value'
        
        Returns
        -------
        dict
            a dictionary containing attributes translated to ENVI HDR naming
        """
        out = dict(bands=1,
                   header_offset=0,
                   file_type='ENVI Standard',
                   interleave='bsq',
                   sensor_type='Unknown',
                   byte_order=1,
                   wavelength_units='Unknown')

        if hasattr(self, 'date'):
            out['acquisition_time'] = self.date + 'Z'

        out['samples'] = getattr(
            self,
            union(['width', 'range_samples', 'samples'], self.keys)[0])
        out['lines'] = getattr(
            self,
            union(['nlines', 'azimuth_lines', 'lines'], self.keys)[0])

        dtypes_lookup = {
            'FCOMPLEX': 6,
            'FLOAT': 4,
            'REAL*4': 4,
            'INTEGER*2': 2,
            'SHORT': 12
        }
        dtype = getattr(self,
                        union(['data_format', 'image_format'], self.keys)[0])

        if dtype not in dtypes_lookup.keys():
            raise TypeError('unsupported data type: {}'.format(dtype))

        out['data_type'] = dtypes_lookup[dtype]

        if nodata is not None:
            out['data_ignore_value'] = nodata

        if out['data_type'] == 6:
            out['complex_function'] = 'Power'
        # projections = ['AEAC', 'EQA', 'LCC', 'LCC2', 'OMCH', 'PC', 'PS', 'SCH', 'TM', 'UTM']
        # the corner coordinates are shifted by 1/2 pixel to the Northeast since GAMMA pixel
        # coordinates are defined for the pixel center while in ENVI it is the upper left
        if hasattr(self, 'DEM_projection'):
            if self.DEM_projection == 'UTM':
                hem = 'North' if float(self.false_northing) == 0 else 'South'
                out['map_info'] = [
                    'UTM', '1.0000', '1.0000',
                    self.corner_east - (abs(self.post_east) / 2),
                    self.corner_north + (abs(self.post_north) / 2),
                    str(abs(float(self.post_east))),
                    str(abs(float(self.post_north))), self.projection_zone,
                    hem, 'WGS-84', 'units=Meters'
                ]
            elif self.DEM_projection == 'EQA':
                out['map_info'] = [
                    'Geographic Lat/Lon', '1.0000', '1.0000',
                    self.corner_lon - (abs(self.post_lon) / 2),
                    self.corner_lat + (abs(self.post_lat) / 2),
                    str(abs(float(self.post_lon))),
                    str(abs(float(self.post_lat))), 'WGS-84', 'units=Degrees'
                ]
            else:
                raise RuntimeError('unsupported projection: {}'.format(
                    self.DEM_projection))
        return out