Example #1
0
# -*- coding: utf-8 -*-
"""
Created on Fri Jan 12 16:20:15 2018

@author: pyang
"""
from geoarray import GeoArray
from arosics import COREG
#print(dir(GeoArray))
#im_reference = r'C:\DEV\FuelMapping\Arc_Version_Test\Hill_Country_Pilot\AC_Images\S2A_MSIL2A_20170130T171541_N0204_R112_T14RMT_20170130T171741.SAFE\GRANULE\L2A_T14RMT_A008403_20170130T171541\IMG_DATA\R10m\L2A_T14RMT_20170130T171541_B02_10m.jp2'
#im_reference = r'C:\DEV\FuelMapping\registration\Sample_Images\L2A_T14RMT_20170430T171301_B04_10m__shifted_to__L2A_T14RMT_20171022T171339_B04_10m.tif'
#im_target    = '/path/to/your/tgt_image.bsq'
im_reference = r'c:\DEV\FuelMapping\registration\Multiband_Images\S2B_MSIL2A_T14RMT_N0205_20171022_10m.tif'
geoArr  = GeoArray(im_reference)
#print(help(geoArr))
#CR = COREG(im_reference, im_target, wp=(354223, 5805559), ws=(256,256))
#CR.calculate_spatial_shifts()
#for single band image
#im_reference = r'C:\DEV\FuelMapping\registration\Sample_Images\L2A_T14RMT_20171022T171339_B04_10m.jp2'
#im_target = r'C:\DEV\FuelMapping\registration\Sample_Images\L2A_T14RMT_20170430T171301_B04_10m.jp2'
#shiftedfn = im_target[0:-4] + "_pyshifted"  + '.tif'
#print(shiftedfn)
##print(help(CRL.correct_shifts()))
#for full band image
#im_reference = r'c:\DEV\FuelMapping\registration\Multiband_Images\S2B_MSIL2A_T14RMT_N0205_20171022_10m.tif'
#im_target = r'c:\DEV\FuelMapping\registration\Multiband_Images\S2A_MSIL2A_T14RMT_N0205_20170430_10m.tif'
#shiftedfn = im_target[0:-4] + "_pyfullbandshifted"  + '.tif'
#CRL = COREG(im_reference,im_target,shiftedfn,fmt_out='GTiff')
#CRL.correct_shifts()
#shiftedarray.save(shiftedfn,fmt='GTiff',creationOptions="WRITE_METADATA=YES")
#
Example #2
0
    def correct_shifts(self) -> collections.OrderedDict:
        if not self.q:
            print('Correcting geometric shifts...')

        t_start = time.time()

        if not self.warping_needed:
            """NO RESAMPLING NEEDED"""

            self.is_shifted = True
            self.is_resampled = False
            xmin, ymin, xmax, ymax = self._get_out_extent()

            if not self.q:
                print(
                    "NOTE: The detected shift is corrected by updating the map info of the target image only, i.e., "
                    "without any resampling. Set the 'align_grids' parameter to True if you need the target and the "
                    "reference coordinate grids to be aligned.")

            if self.cliptoextent:
                # TODO validate results
                # TODO -> output extent does not seem to be the requested one! (only relevant if align_grids=False)
                # get shifted array
                shifted_geoArr = GeoArray(self.im2shift[:],
                                          tuple(self.updated_gt),
                                          self.shift_prj)

                # clip with target extent
                #  NOTE: get_mapPos() does not perform any resampling as long as source and target projection are equal
                self.arr_shifted, self.updated_gt, self.updated_projection = \
                    shifted_geoArr.get_mapPos((xmin, ymin, xmax, ymax),
                                              self.shift_prj,
                                              fillVal=self.nodata,
                                              band2get=self.band2process)

                self.updated_map_info = geotransform2mapinfo(
                    self.updated_gt, self.updated_projection)

            else:
                # array keeps the same; updated gt and prj are taken from coreg_info
                self.arr_shifted = self.im2shift[:, :, self.band2process] \
                    if self.band2process is not None else self.im2shift[:]

            out_geoArr = GeoArray(self.arr_shifted,
                                  self.updated_gt,
                                  self.updated_projection,
                                  q=self.q)
            out_geoArr.nodata = self.nodata  # equals self.im2shift.nodata after __init__()
            out_geoArr.metadata = self.im2shift.metadata[[self.band2process]] \
                if self.band2process is not None else self.im2shift.metadata

            self.GeoArray_shifted = out_geoArr

            if self.path_out:
                out_geoArr.save(self.path_out, fmt=self.fmt_out)

        else:  # FIXME equal_prj==False ist noch NICHT implementiert
            """RESAMPLING NEEDED"""
            # FIXME avoid reading the whole band if clip_extent is passed

            in_arr = self.im2shift[:, :, self.band2process] \
                if self.band2process is not None and self.im2shift.ndim == 3 else self.im2shift[:]

            if not self.GCPList:
                # apply XY-shifts to input image gt 'shift_gt' in order to correct the shifts before warping
                self.shift_gt[0], self.shift_gt[3] = self.updated_gt[
                    0], self.updated_gt[3]

            # get resampled array
            out_arr, out_gt, out_prj = \
                warp_ndarray(in_arr, self.shift_gt, self.shift_prj, self.ref_prj,
                             rspAlg=_dict_rspAlg_rsp_Int[self.rspAlg],
                             in_nodata=self.nodata,
                             out_nodata=self.nodata,
                             out_gsd=self.out_gsd,
                             out_bounds=self._get_out_extent(),  # always returns an extent snapped to the target grid
                             gcpList=self.GCPList,
                             # polynomialOrder=str(3),
                             # options='-refine_gcps 500 1.9',
                             # warpOptions=['-refine_gcps 500 1.9'],
                             # options='-wm 10000',# -order 3',
                             # options=['-order 3'],
                             # options=['GDAL_CACHEMAX 800 '],
                             # warpMemoryLimit=125829120, # 120MB
                             CPUs=self.CPUs,
                             progress=self.progress,
                             q=self.q)

            out_geoArr = GeoArray(out_arr, out_gt, out_prj, q=self.q)
            out_geoArr.nodata = self.nodata  # equals self.im2shift.nodata after __init__()
            out_geoArr.metadata = self.im2shift.metadata[[self.band2process]] \
                if self.band2process is not None else self.im2shift.metadata

            self.arr_shifted = out_arr
            self.updated_gt = out_gt
            self.updated_projection = out_prj
            self.updated_map_info = geotransform2mapinfo(out_gt, out_prj)
            self.GeoArray_shifted = out_geoArr
            self.is_shifted = True
            self.is_resampled = True

            if self.path_out:
                out_geoArr.save(self.path_out,
                                fmt=self.fmt_out,
                                creationOptions=self.out_creaOpt)

        # validation
        if not is_coord_grid_equal(
                self.updated_gt, *self.out_grid, tolerance=1.e8):
            raise RuntimeError(
                'DESHIFTER output dataset has not the desired target pixel grid. Target grid '
                'was %s. Output geotransform is %s.' %
                (str(self.out_grid), str(self.updated_gt)))
        # TODO to be continued (extent, map info, ...)

        if self.v:
            print('Time for shift correction: %.2fs' % (time.time() - t_start))
        return self.deshift_results
Example #3
0
    def __init__(self, im2shift: Union[GeoArray, str], coreg_results: dict,
                 **kwargs) -> None:
        """Get an instance of DESHIFTER.

        :param im2shift:
            path of an image to be de-shifted or alternatively a GeoArray object

        :param dict coreg_results:
            the results of the co-registration as given by COREG.coreg_info or COREG_LOCAL.coreg_info

        :keyword int path_out:
             /output/directory/filename for coregistered results

        :keyword str fmt_out:
            raster file format for output file. ignored if path_out is None. can be any GDAL
            compatible raster file format (e.g. 'ENVI', 'GTIFF'; default: ENVI)

        :keyword list out_crea_options:
            GDAL creation options for the output image, e.g., ["QUALITY=20", "REVERSIBLE=YES", "WRITE_METADATA=YES"]

        :keyword int band2process:
            The index of the band to be processed within the given array (starts with 1),
            default = None (all bands are processed)

        :keyword float nodata:
            no data value of the image to be de-shifted

        :keyword float out_gsd:
            output pixel size in units of the reference coordinate system (default = pixel size of the input array),
            given values are overridden by match_gsd=True

        :keyword bool align_grids:
            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

        :keyword bool match_gsd:
            True: match the input pixel size to the reference pixel size, default = False

        :keyword list target_xyGrid:
            a list with an x-grid and a y-grid like [[15,45], [15,45]].
            This overrides 'out_gsd', 'align_grids' and 'match_gsd'.

        :keyword int min_points_local_corr:
            number of valid tie points, below which a global shift correction is performed instead of a local
            correction (global X/Y shift is then computed as the mean shift of the remaining points)
            (default: 5 tie points)

        :keyword str resamp_alg:
            the resampling algorithm to be used if neccessary
            (valid algorithms: nearest, bilinear, cubic, cubic_spline, lanczos, average, mode, max, min, med, q1, q3)

        :keyword bool cliptoextent:
            True: clip the input image to its actual bounds while deleting possible no data areas outside of the actual
            bounds, default = False

        :keyword list clipextent:
            xmin, ymin, xmax, ymax - if given the calculation of the actual bounds is skipped.
            The given coordinates are automatically snapped to the output grid.

        :keyword int CPUs:
            number of CPUs to use (default: None, which means 'all CPUs available')

        :keyword bool progress:
            show progress bars (default: True)

        :keyword bool v:
            verbose mode (default: False)

        :keyword bool q:
            quiet mode (default: False)
        """
        # private attributes
        self._grids_alignable = None

        # store args / kwargs
        self.init_args = dict([
            x for x in locals().items()
            if x[0] != "self" and not x[0].startswith('__')
        ])
        self.init_kwargs = self.init_args['kwargs']

        # unpack args
        self.im2shift = im2shift if isinstance(
            im2shift, GeoArray) else GeoArray(im2shift)
        self.GCPList = coreg_results[
            'GCPList'] if 'GCPList' in coreg_results else None
        self.ref_gt = coreg_results['reference geotransform']
        self.ref_grid = coreg_results['reference grid']
        self.ref_prj = coreg_results['reference projection']

        # unpack kwargs
        self.path_out = kwargs.get('path_out', None)
        self.fmt_out = kwargs.get('fmt_out', 'ENVI')
        self.out_creaOpt = kwargs.get('out_crea_options', [])
        self.band2process = kwargs.get('band2process',
                                       None)  # starts with 1 # FIXME why?
        self.band2process = \
            self.band2process - 1 if self.band2process is not None else None  # internally handled as band index
        self.nodata = kwargs.get('nodata', self.im2shift.nodata)
        self.align_grids = kwargs.get('align_grids', False)
        self.min_points_local_corr = kwargs.get('min_points_local_corr', 5)
        self.rspAlg = kwargs.get('resamp_alg',
                                 'cubic')  # TODO accept also integers
        self.cliptoextent = kwargs.get('cliptoextent', False)
        self.clipextent = kwargs.get('clipextent', None)
        self.CPUs = kwargs.get('CPUs', None)
        self.v = kwargs.get('v', False)
        self.q = kwargs.get('q',
                            False) if not self.v else False  # overridden by v
        self.progress = kwargs.get(
            'progress', True) if not self.q else False  # overridden by q

        self.im2shift.nodata = kwargs.get('nodata', self.im2shift.nodata)
        self.im2shift.q = self.q
        self.shift_prj = self.im2shift.projection
        self.shift_gt = list(self.im2shift.geotransform)

        # in case of local shift correction and local coreg results contain less points than min_points_local_corr:
        # force global correction based on mean X/Y shifts
        if 'GCPList' in coreg_results and len(
                coreg_results['GCPList']) < self.min_points_local_corr:
            warnings.warn(
                'Only %s valid tie point(s) could be identified. A local shift correction is therefore not '
                'reasonable and could cause artifacts in the output image. The target image is '
                'corrected globally with the mean X/Y shift of %.3f/%.3f pixels.'
                % (len(self.GCPList), coreg_results['mean_shifts_px']['x'],
                   coreg_results['mean_shifts_px']['y']))
            self.GCPList = None
            coreg_results['updated map info'] = coreg_results[
                'updated map info means']

        # in case of global shift correction -> the updated map info from coreg_results already has the final map info
        # BUT: this will be updated in correct_shifts() if clipextent is given or warping is needed
        if not self.GCPList:
            mapI = coreg_results['updated map info']
            self.updated_map_info = mapI or geotransform2mapinfo(
                self.shift_gt, self.shift_prj)
            self.updated_gt = mapinfo2geotransform(
                self.updated_map_info) or self.shift_gt
            self.original_map_info = coreg_results['original map info']
        self.updated_projection = self.ref_prj

        self.out_grid = self._get_out_grid(
        )  # needs self.ref_grid, self.im2shift
        self.out_gsd = [
            abs(self.out_grid[0][1] - self.out_grid[0][0]),
            abs(self.out_grid[1][1] - self.out_grid[1][0])
        ]  # xgsd, ygsd

        # assertions
        assert self.rspAlg in _dict_rspAlg_rsp_Int.keys(), \
            "'%s' is not a supported resampling algorithm." % self.rspAlg
        if self.band2process is not None:
            assert self.im2shift.bands - 1 >= self.band2process >= 0, \
                "The %s '%s' has %s %s. So 'band2process' must be %s%s. Got %s." \
                % (self.im2shift.__class__.__name__, self.im2shift.basename, self.im2shift.bands,
                   'bands' if self.im2shift.bands > 1 else 'band', 'between 1 and ' if self.im2shift.bands > 1 else '',
                   self.im2shift.bands, self.band2process + 1)

        # set defaults for general class attributes
        self.is_shifted = False  # this is not included in COREG.coreg_info
        self.is_resampled = False  # this is not included in COREG.coreg_info
        self.tracked_errors = []
        self.arr_shifted = None  # set by self.correct_shifts
        self.GeoArray_shifted = None  # set by self.correct_shifts
Example #4
0
    def __init__(self,
                 im_ref,
                 im_tgt,
                 grid_res,
                 max_points=None,
                 window_size=(256, 256),
                 path_out=None,
                 fmt_out='ENVI',
                 out_crea_options=None,
                 projectDir=None,
                 r_b4match=1,
                 s_b4match=1,
                 max_iter=5,
                 max_shift=5,
                 tieP_filter_level=3,
                 min_reliability=60,
                 rs_max_outlier=10,
                 rs_tolerance=2.5,
                 align_grids=True,
                 match_gsd=False,
                 out_gsd=None,
                 target_xyGrid=None,
                 resamp_alg_deshift='cubic',
                 resamp_alg_calc='cubic',
                 footprint_poly_ref=None,
                 footprint_poly_tgt=None,
                 data_corners_ref=None,
                 data_corners_tgt=None,
                 outFillVal=-9999,
                 nodata=(None, None),
                 calc_corners=True,
                 binary_ws=True,
                 force_quadratic_win=True,
                 mask_baddata_ref=None,
                 mask_baddata_tgt=None,
                 CPUs=None,
                 progress=True,
                 v=False,
                 q=False,
                 ignore_errors=True):
        """Get an instance of COREG_LOCAL.

        :param im_ref(str | GeoArray):  source path of reference image (any GDAL compatible image format is supported)
        :param im_tgt(str | GeoArray):  source path of image to be shifted (any GDAL compatible image format is
                                        supported)
        :param grid_res:                tie point grid resolution in pixels of the target image (x-direction)
        :param max_points(int):         maximum number of points used to find coregistration tie points
                                        NOTE: Points are selected randomly from the given point grid (specified by
                                        'grid_res'). If the point does not provide enough points, all available points
                                        are chosen.
        :param window_size(tuple):      custom matching window size [pixels] (default: (256,256))
        :param path_out(str):           target path of the coregistered image
                                            - if None (default), no output is written to disk
                                            - if 'auto': /dir/of/im1/<im1>__shifted_to__<im0>.bsq
        :param fmt_out(str):            raster file format for output file. ignored if path_out is None. Can be any GDAL
                                        compatible raster file format (e.g. 'ENVI', 'GTIFF'; default: ENVI). Refer to
                                        http://www.gdal.org/formats_list.html to get a full list of supported formats.
        :param out_crea_options(list):  GDAL creation options for the output image,
                                        e.g. ["QUALITY=80", "REVERSIBLE=YES", "WRITE_METADATA=YES"]
        :param projectDir(str):         name of a project directory where to store all the output results. If given,
                                        name is inserted into all automatically generated output paths.
        :param r_b4match(int):          band of reference image to be used for matching (starts with 1; default: 1)
        :param s_b4match(int):          band of shift image to be used for matching (starts with 1; default: 1)
        :param max_iter(int):           maximum number of iterations for matching (default: 5)
        :param max_shift(int):          maximum shift distance in reference image pixel units (default: 5 px)
        :param tieP_filter_level(int):  filter tie points used for shift correction in different levels (default: 3).
                                        NOTE: lower levels are also included if a higher level is chosen
                                            - Level 0: no tie point filtering
                                            - Level 1: Reliablity filtering - filter all tie points out that have a low
                                                reliability according to internal tests
                                            - Level 2: SSIM filtering - filters all tie points out where shift
                                                correction does not increase image similarity within matching window
                                                (measured by mean structural similarity index)
                                            - Level 3: RANSAC outlier detection
        :param min_reliability(float):  Tie point filtering: minimum reliability threshold, below which tie points are
                                        marked as false-positives (default: 60%)
                                        - accepts values between 0% (no reliability) and 100 % (perfect reliability)
                                        HINT: decrease this value in case of poor signal-to-noise ratio of your input
                                              data
        :param rs_max_outlier(float):   RANSAC tie point filtering: proportion of expected outliers (default: 10%)
        :param rs_tolerance(float):     RANSAC tie point filtering: percentage tolerance for max_outlier_percentage
                                                (default: 2.5%)
        :param out_gsd (float):         output pixel size in units of the reference coordinate system (default = pixel
                                        size of the input array), given values are overridden by match_gsd=True
        :param 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 = True
        :param match_gsd (bool):        True: match the input pixel size to the reference pixel size,
                                        default = False
        :param target_xyGrid(list):     a list with a target x-grid and a target y-grid like [[15,45], [15,45]]
                                        This overrides 'out_gsd', 'align_grids' and 'match_gsd'.
        :param resamp_alg_deshift(str)  the resampling algorithm to be used for shift correction (if neccessary)
                                        valid algorithms: nearest, bilinear, cubic, cubic_spline, lanczos, average,
                                                          mode, max, min, med, q1, q3
                                        default: cubic
        :param resamp_alg_calc(str)     the resampling algorithm to be used for all warping processes during calculation
                                        of spatial shifts
                                        (valid algorithms: nearest, bilinear, cubic, cubic_spline, lanczos, average,
                                                           mode, max, min, med, q1, q3)
                                        default: cubic (highly recommended)
        :param footprint_poly_ref(str): footprint polygon of the reference image (WKT string or
                                        shapely.geometry.Polygon),
                                        e.g. 'POLYGON ((299999 6000000, 299999 5890200, 409799 5890200, 409799 6000000,
                                                        299999 6000000))'
        :param footprint_poly_tgt(str): footprint polygon of the image to be shifted (WKT string or
                                        shapely.geometry.Polygon)
                                        e.g. 'POLYGON ((299999 6000000, 299999 5890200, 409799 5890200, 409799 6000000,
                                                        299999 6000000))'
        :param data_corners_ref(list):  map coordinates of data corners within reference image.
                                        ignored if footprint_poly_ref is given.
        :param data_corners_tgt(list):  map coordinates of data corners within image to be shifted.
                                        ignored if footprint_poly_tgt is given.
        :param outFillVal(int):         if given the generated tie point grid is filled with this value in case
                                        no match could be found during co-registration (default: -9999)
        :param nodata(tuple):           no data values for reference image and image to be shifted
        :param calc_corners(bool):      calculate true positions of the dataset corners in order to get a useful
                                        matching window position within the actual image overlap
                                        (default: True; deactivated if 'data_corners_im0' and 'data_corners_im1' are
                                        given)
        :param binary_ws(bool):         use binary X/Y dimensions for the matching window (default: True)
        :param force_quadratic_win(bool):   force a quadratic matching window (default: 1)
        :param mask_baddata_ref(str | BadDataMask):
                                        path to a 2D boolean mask file (or an instance of BadDataMask) for the
                                        reference image where all bad data pixels (e.g. clouds) are marked with
                                        True and the remaining pixels with False. Must have the same geographic
                                        extent and projection like 'im_ref'. The mask is used to check if the
                                        chosen matching window position is valid in the sense of useful data.
                                        Otherwise this window position is rejected.
        :param mask_baddata_tgt(str | BadDataMask):
                                        path to a 2D boolean mask file (or an instance of BadDataMask) for the
                                        image to be shifted where all bad data pixels (e.g. clouds) are marked
                                        with True and the remaining pixels with False. Must have the same
                                        geographic extent and projection like 'im_ref'. The mask is used to
                                        check if the chosen matching window position is valid in the sense of
                                        useful data. Otherwise this window position is rejected.
        :param CPUs(int):               number of CPUs to use during calculation of tie point grid
                                        (default: None, which means 'all CPUs available')
        :param progress(bool):          show progress bars (default: True)
        :param v(bool):                 verbose mode (default: False)
        :param q(bool):                 quiet mode (default: False)
        :param ignore_errors(bool):     Useful for batch processing. (default: False)
        """
        # assertions / input validation
        assert gdal.GetDriverByName(
            fmt_out), "'%s' is not a supported GDAL driver." % fmt_out
        if match_gsd and out_gsd:
            warnings.warn(
                "'-out_gsd' is ignored because '-match_gsd' is set.\n")
        if out_gsd:
            assert isinstance(out_gsd, list) and len(
                out_gsd) == 2, 'out_gsd must be a list with two values.'
        if PY2 and (CPUs is None or (isinstance(CPUs, int) and CPUs > 1)):
            CPUs = 1
            warnings.warn(
                'Multiprocessing is currently not supported for Python 2. Using singleprocessing.'
            )

        self.params = dict([
            x for x in locals().items()
            if x[0] != "self" and not x[0].startswith('__')
        ])

        self.imref = GeoArray(im_ref, nodata=nodata[0], progress=progress, q=q)
        self.im2shift = GeoArray(im_tgt,
                                 nodata=nodata[1],
                                 progress=progress,
                                 q=q)
        self.path_out = path_out  # updated by self.set_outpathes
        self.fmt_out = fmt_out
        self.out_creaOpt = out_crea_options
        self._projectDir = projectDir
        self.grid_res = grid_res
        self.max_points = max_points
        self.window_size = window_size
        self.max_shift = max_shift
        self.max_iter = max_iter
        self.tieP_filter_level = tieP_filter_level
        self.min_reliability = min_reliability
        self.rs_max_outlier = rs_max_outlier
        self.rs_tolerance = rs_tolerance
        self.align_grids = align_grids
        self.match_gsd = match_gsd
        self.out_gsd = out_gsd
        self.target_xyGrid = target_xyGrid
        self.rspAlg_DS = resamp_alg_deshift  # TODO convert integers to strings
        self.rspAlg_calc = resamp_alg_calc
        self.calc_corners = calc_corners
        self.nodata = nodata
        self.outFillVal = outFillVal
        self.bin_ws = binary_ws
        self.force_quadratic_win = force_quadratic_win
        self.CPUs = CPUs
        self.path_verbose_out = ''  # TODO
        self.v = v
        self.q = q if not v else False  # overridden by v
        self.progress = progress if not q else False  # overridden by v
        self.ignErr = ignore_errors  # FIXME this is not yet implemented for COREG_LOCAL

        assert self.tieP_filter_level in range(
            4), 'Invalid tie point filter level.'
        assert isinstance(self.imref, GeoArray) and isinstance(self.im2shift, GeoArray), \
            'Something went wrong with the creation of GeoArray instances for reference or target image. The created ' \
            'instances do not seem to belong to the GeoArray class. If you are working in Jupyter Notebook, reset ' \
            'the kernel and try again.'

        COREG.__dict__['_set_outpathes'](self, self.imref, self.im2shift)
        # make sure that the output directory of coregistered image is the project directory if a project directory is
        # given
        if path_out and projectDir and os.path.basename(self.path_out):
            self.path_out = os.path.join(self.projectDir,
                                         os.path.basename(self.path_out))

        gdal.AllRegister()

        try:
            # ignore_errors must be False because in case COREG init fails, coregistration for the whole scene fails
            self.COREG_obj = COREG(
                self.imref,
                self.im2shift,
                ws=window_size,
                footprint_poly_ref=footprint_poly_ref,
                footprint_poly_tgt=footprint_poly_tgt,
                data_corners_ref=data_corners_ref,
                data_corners_tgt=data_corners_tgt,
                resamp_alg_calc=self.rspAlg_calc,
                calc_corners=calc_corners,
                r_b4match=r_b4match,
                s_b4match=s_b4match,
                max_iter=max_iter,
                max_shift=max_shift,
                nodata=nodata,
                mask_baddata_ref=None,  # see below
                mask_baddata_tgt=None,
                CPUs=self.CPUs,
                force_quadratic_win=self.force_quadratic_win,
                binary_ws=self.bin_ws,
                progress=self.progress,
                v=v,
                q=q,
                ignore_errors=False)
        except Exception:
            warnings.warn(
                '\nFirst attempt to check if functionality of co-registration failed. Check your '
                'input data and parameters. The following error occurred:',
                stacklevel=3)
            raise

        if pyfftw:
            self.check_if_fftw_works()

        # add bad data mask
        # (mask is not added during initialization of COREG object in order to avoid bad data area errors there)
        if mask_baddata_ref is not None:
            self.COREG_obj.ref.mask_baddata = mask_baddata_ref
        if mask_baddata_tgt is not None:
            self.COREG_obj.shift.mask_baddata = mask_baddata_tgt

        self._tiepoint_grid = None  # set by self.tiepoint_grid
        self._CoRegPoints_table = None  # set by self.CoRegPoints_table
        self._coreg_info = None  # set by self.coreg_info
        self.deshift_results = None  # set by self.correct_shifts()
        self._success = None  # set by self.success property
Example #5
0
    def test_shift_calculation_nonquadratic_pixels(self):
        """Test with default parameters - should compute X/Y shifts properly and write the de-shifted target image."""

        # overwrite gt and prj
        ref = GeoArray(self.ref_path)
        ref.to_mem()
        ref.filePath = None
        ref.gt = [330000.00000001, 5.8932, 0.0, 5862000.0000001, 0.0, -10.1]
        tgt = GeoArray(self.tgt_path)
        tgt.to_mem()
        tgt.filePath = None
        tgt.gt = [335440.0000001, 5.8933, 0.0, 5866490.0000001, 0.0, -10.1]

        CR = self.run_shift_detection_correction(
            ref, tgt,
            **dict(self.coreg_kwargs,
                   wp=(341500.0, 5861440.0),
                   footprint_poly_ref=None,
                   footprint_poly_tgt=None))
        self.assertTrue(CR.success)
Example #6
0
    def test_shift_calculation_with_image_coords_only(self):
        """Test with default parameters - should compute X/Y shifts properly and write the de-shifted target image."""
        # FIXME fails when executed alone

        # overwrite gt and prj
        ref = GeoArray(self.ref_path)
        ref.to_mem()
        ref.filePath = None
        ref.gt = [0, 1, 0, 0, 0, -1]
        ref.prj = ''
        tgt = GeoArray(self.tgt_path)
        tgt.to_mem()
        tgt.filePath = None
        tgt.gt = [0, 1, 0, 0, 0, -1]
        tgt.prj = ''

        CR = self.run_shift_detection_correction(
            ref, tgt,
            **dict(self.coreg_kwargs,
                   wp=(1200, -1600),
                   footprint_poly_ref=None,
                   footprint_poly_tgt=None))
        self.assertTrue(CR.success)
Example #7
0
    def to_sensor_geometry(self, lons: np.ndarray, lats: np.ndarray):
        GT = Geometry_Transformer(lons=lons, lats=lats, nprocs=self.CPUs)
        data_sensorgeo = GT.to_sensor_geometry(self.dem)

        return GeoArray(data_sensorgeo)
Example #8
0
def regional_mean(a, region=None):
    """ Average along lon/lat

    input:
        - a: DimArray instance including lat, lon axis
        - region, optional: 
            [lon, lat]: Point
            [lon_ll, lat_ll, lon_ur, lat_ur]: BoxRegion
            or Region instance

    output:
        - GeoArray instance, regional average

    Notes:
    ------
    Will adjust longitude axis over [0, 360] or [-180, 180] as necessary

    Examples:
    ---------
    >>> lon = [0, 50., 100.]
    >>> lat = [0, 50.]
    >>> a = GeoArray([[1, 2, 4],[4, 5, 6]], lon=lon, lat=lat)
    >>> rm = regional_mean(a)
    >>> rm
    3.3767428905946684

    Which just weights data with cos(lat)
    >>> lon2, lat2 = np.meshgrid(lon, lat)
    >>> w = np.cos(np.radians(lat2))
    >>> rm2 = np.sum(a.values*w)/np.sum(w)  
    >>> round(rm2, 4)
    3.3767

    GeoArray detects the weights automatically with name "lat"
    >>> rm3 = a.mean() 
    >>> round(rm3,4)
    3.3767
    >>> a.mean(weights=None)
    3.6666666666666665

    Also works for multi-dimensional data shaped in any kind of order
    >>> a = a.newaxis('z',[0,1,2])
    >>> a = a.transpose(('lon','z','lat'))
    >>> regional_mean(a)
    geoarray: 3 non-null elements (0 null)
    dimensions: 'z'
    0 / z (3): 0 to 2
    array([ 3.37674289,  3.37674289,  3.37674289])
    """
    regobj = regmod.check(region)

    dims = ('lat','lon')

    a = GeoArray(a) # make it a GeoArray to check lon, lat 

    if not set(dims).issubset(a.dims):
        raise ValueError("does not have lon, lat axes: {}".format(a))

    # rearrange dimensions with dims first
    flatdims = [ax.name for ax in a.axes if ax.name not in dims]
    newdims = dims + tuple(flatdims)
    if a.dims != newdims:
        a = a.transpose(newdims)

    # If 2-D return a scalar
    if a.dims == ('lat', 'lon'):
        return regobj.mean(a.lon,a.lat, a.values)

    # flatten all except lat, lon, and make it the first axis
    agrp = a.group(flatdims, insert=0) 
    grpaxis = agrp.axes[0] # grouped axis
    
    # iterate over the first, grouped axis
    results = []
    for i in range(grpaxis.size):
        res = regobj.mean(a.lon,a.lat, agrp.values[i])
        results.append(res)
        
    # flat object
    grp_ave = a._constructor(results, [grpaxis])

    average = grp_ave.ungroup() # now ungroup

    return average