Commit 9d2b1b1a authored by Daniel Scheffler's avatar Daniel Scheffler
Browse files

Merged master branch.

parents feb75808 fdfeb162
Pipeline #3336 passed with stages
in 11 minutes and 29 seconds
...@@ -20,8 +20,10 @@ test_arosics: ...@@ -20,8 +20,10 @@ test_arosics:
stage: test stage: test
script: script:
- source /root/miniconda3/bin/activate - source /root/miniconda3/bin/activate
- export GDAL_DATA=/root/miniconda3/share/gdal - source activate ci_env
- export GDAL_DATA=/root/miniconda3/envs/ci_env/share/gdal
- export PYTHONPATH=$PYTHONPATH:/root # /root <- directory needed later - export PYTHONPATH=$PYTHONPATH:/root # /root <- directory needed later
- pip install "py_tools_ds>=0.13.7" # FIXME remove as soon as docker runner has been updated
- make nosetests - make nosetests
- make docs - make docs
artifacts: artifacts:
...@@ -37,8 +39,10 @@ test_styles: ...@@ -37,8 +39,10 @@ test_styles:
stage: test stage: test
script: script:
- source /root/miniconda3/bin/activate - source /root/miniconda3/bin/activate
- export GDAL_DATA=/root/miniconda3/share/gdal - source activate ci_env
- export GDAL_DATA=/root/miniconda3/envs/ci_env/share/gdal
- export PYTHONPATH=$PYTHONPATH:/root # /root <- directory needed later - export PYTHONPATH=$PYTHONPATH:/root # /root <- directory needed later
# - pip install "pycodestyle>=2.0.0,!=2.4.0" # TODO remove as soon as docker runner is recreated
- make lint - make lint
artifacts: artifacts:
paths: paths:
...@@ -52,11 +56,11 @@ test_arosics_install: ...@@ -52,11 +56,11 @@ test_arosics_install:
stage: test stage: test
script: script:
- source /root/miniconda3/bin/activate - source /root/miniconda3/bin/activate
- export GDAL_DATA=/root/miniconda3/share/gdal - conda create -y -q --name arosics_testinstall python=3
- conda create -y -q --name arosics python=3 - source activate arosics_testinstall
- source activate arosics
# resolve some requirements with conda # resolve some requirements with conda
- conda install --yes -q -c conda-forge numpy gdal scikit-image matplotlib pyproj rasterio shapely geopandas - conda install --yes -q -c conda-forge numpy gdal scikit-image matplotlib pyproj rasterio shapely geopandas
- conda install --yes -q -c conda-forge libgdal ncurses # Fix for libgdal installed from defaults channel causing libkea.so.1.4.7: cannot open shared object file: No such file or directory
# run installer # run installer
- python setup.py install - python setup.py install
# test if its importable # test if its importable
...@@ -107,6 +111,7 @@ deploy_pypi: ...@@ -107,6 +111,7 @@ deploy_pypi:
- test_arosics - test_arosics
script: # Configure the PyPI credentials, then push the package, and cleanup the creds. script: # Configure the PyPI credentials, then push the package, and cleanup the creds.
- source /root/miniconda3/bin/activate - source /root/miniconda3/bin/activate
- source activate ci_env
- mkdir -p public/images/ - mkdir -p public/images/
- cp -r docs/images/* public/images/ - cp -r docs/images/* public/images/
- printf "[distutils]\nindex-servers =\n pypi\n\n" >> ~/.pypirc - printf "[distutils]\nindex-servers =\n pypi\n\n" >> ~/.pypirc
......
...@@ -4,7 +4,7 @@ import os ...@@ -4,7 +4,7 @@ import os
import time import time
import warnings import warnings
from copy import copy from copy import copy
from typing import Iterable from typing import Iterable, Union, Tuple # noqa F401
# custom # custom
try: try:
...@@ -337,11 +337,22 @@ class COREG(object): ...@@ -337,11 +337,22 @@ class COREG(object):
'COREG._set_outpathes() expects two file pathes (string) or two instances of the ' \ 'COREG._set_outpathes() expects two file pathes (string) or two instances of the ' \
'GeoArray class. Received %s and %s.' % (type(im_ref), type(im_tgt)) 'GeoArray class. Received %s and %s.' % (type(im_ref), type(im_tgt))
def get_baseN(path): return os.path.splitext(os.path.basename(path))[0] def get_baseN(path):
return os.path.splitext(os.path.basename(path))[0]
# get input pathes # get input paths
path_im_ref = im_ref.filePath if isinstance(im_ref, GeoArray) else im_ref def get_input_path(im):
path_im_tgt = im_tgt.filePath if isinstance(im_tgt, GeoArray) else im_tgt path = im.filePath if isinstance(im, GeoArray) else im
if isinstance(im, GeoArray) and im.filePath is None and self.path_out == 'auto':
raise ValueError(self.path_out, "The output path must be explicitly set in case the input "
"reference or target image is in-memory (without a reference to a "
"physical file on disk). Received path_out='%s'." % self.path_out)
return path
path_im_ref = get_input_path(im_ref)
path_im_tgt = get_input_path(im_tgt)
if self.path_out: # this also applies to self.path_out='auto' if self.path_out: # this also applies to self.path_out='auto'
...@@ -430,34 +441,17 @@ class COREG(object): ...@@ -430,34 +441,17 @@ class COREG(object):
if not self.q: if not self.q:
print("Equalizing pixel grids and projections of reference and target image...") print("Equalizing pixel grids and projections of reference and target image...")
# noinspection PyProtectedMember
def apply_subset_bandnames_metadata(geoArr_cr):
# TODO: replace that function with geoArr.get_subset(zslice=slice(band4match, band4match+1))
# TODO: as soon as all metadata are passed through get_subset()
zslice = slice(geoArr_cr.band4match, geoArr_cr.band4match+1)
if geoArr_cr._bandnames:
geoArr_cr.bandnames = list(np.array(list(geoArr_cr._bandnames))[zslice])
if geoArr_cr._metadata is not None:
geoArr_cr.metadata = \
geoArr_cr._metadata[list(np.array(range(len(geoArr_cr._metadata.columns)))[zslice])].copy()
return geoArr_cr
if self.grid2use == 'ref': if self.grid2use == 'ref':
# resample target image to reference image # resample target image to reference image
self.shift.arr = self.shift[:, :, self.shift.band4match] # resample the needed band only if self.shift.bands > 1:
self.shift = apply_subset_bandnames_metadata(self.shift) self.shift = self.shift.get_subset(zslice=slice(self.shift.band4match, self.shift.band4match + 1))
self.shift.reproject_to_new_grid(prototype=self.ref, CPUs=self.CPUs) self.shift.reproject_to_new_grid(prototype=self.ref, CPUs=self.CPUs)
self.shift.band4match = 0 # after resampling there is only one band in the GeoArray self.shift.band4match = 0 # after resampling there is only one band in the GeoArray
else: else:
# resample reference image to target image # resample reference image to target image
# FIXME in case of different projections this will change the projection of the reference image! if self.ref.bands > 1:
self.ref.arr = self.ref[:, :, self.ref.band4match] # resample the needed band only self.ref = self.ref.get_subset(zslice=slice(self.ref.band4match, self.ref.band4match + 1))
self.ref = apply_subset_bandnames_metadata(self.ref)
self.ref.reproject_to_new_grid(prototype=self.shift, CPUs=self.CPUs) self.ref.reproject_to_new_grid(prototype=self.shift, CPUs=self.CPUs)
self.ref.band4match = 0 # after resampling there is only one band in the GeoArray self.ref.band4match = 0 # after resampling there is only one band in the GeoArray
...@@ -467,14 +461,8 @@ class COREG(object): ...@@ -467,14 +461,8 @@ class COREG(object):
# TODO different colors for polygons # TODO different colors for polygons
assert self.overlap_poly, 'Please calculate the overlap polygon first.' assert self.overlap_poly, 'Please calculate the overlap polygon first.'
try:
import folium import folium
import geojson import geojson
except ImportError:
folium, geojson = None, None
if not folium or not geojson:
raise ImportError("This method requires the libraries 'folium' and 'geojson'. They can be installed with "
"the shell command 'pip install folium geojson'.")
refPoly = reproject_shapelyGeometry(self.ref.poly, self.ref.epsg, 4326) refPoly = reproject_shapelyGeometry(self.ref.poly, self.ref.epsg, 4326)
shiftPoly = reproject_shapelyGeometry(self.shift.poly, self.shift.epsg, 4326) shiftPoly = reproject_shapelyGeometry(self.shift.poly, self.shift.epsg, 4326)
...@@ -608,7 +596,6 @@ class COREG(object): ...@@ -608,7 +596,6 @@ class COREG(object):
PLT.subplot_3dsurface(scps.astype(np.float32)) PLT.subplot_3dsurface(scps.astype(np.float32))
def _get_opt_winpos_winsize(self): def _get_opt_winpos_winsize(self):
# type: (tuple,tuple) -> None
""" """
Calculates optimal window position and size in reference image units according to DGM, cloud_mask and Calculates optimal window position and size in reference image units according to DGM, cloud_mask and
trueCornerLonLat. trueCornerLonLat.
...@@ -711,7 +698,8 @@ class COREG(object): ...@@ -711,7 +698,8 @@ class COREG(object):
# Check, ob match Fenster größer als anderes Fenster # Check, ob match Fenster größer als anderes Fenster
if not (matchBox.mapPoly.within(otherBox.mapPoly) or matchBox.mapPoly == otherBox.mapPoly): if not (matchBox.mapPoly.within(otherBox.mapPoly) or matchBox.mapPoly == otherBox.mapPoly):
# dann für anderes Fenster kleinstes Fenster finden, das match-Fenster umgibt # dann für anderes Fenster kleinstes Fenster finden, das match-Fenster umgibt
otherBox.boxImYX = get_smallest_boxImYX_that_contains_boxMapYX(matchBox.boxMapYX, otherBox.gt) otherBox.boxImYX = get_smallest_boxImYX_that_contains_boxMapYX(
matchBox.boxMapYX, otherBox.gt, tolerance_ndigits=5) # avoids float coordinate rounding issues
# evtl. kann es sein, dass bei Shift-Fenster-Vergrößerung das shift-Fenster zu groß für den overlap wird # evtl. kann es sein, dass bei Shift-Fenster-Vergrößerung das shift-Fenster zu groß für den overlap wird
t_start = time.time() t_start = time.time()
...@@ -720,7 +708,8 @@ class COREG(object): ...@@ -720,7 +708,8 @@ class COREG(object):
xLarger, yLarger = otherBox.is_larger_DimXY(overlapWin.boundsIm) xLarger, yLarger = otherBox.is_larger_DimXY(overlapWin.boundsIm)
matchBox.buffer_imXY(-1 if xLarger else 0, -1 if yLarger else 0) matchBox.buffer_imXY(-1 if xLarger else 0, -1 if yLarger else 0)
previous_area = otherBox.mapPoly.area previous_area = otherBox.mapPoly.area
otherBox.boxImYX = get_smallest_boxImYX_that_contains_boxMapYX(matchBox.boxMapYX, otherBox.gt) otherBox.boxImYX = get_smallest_boxImYX_that_contains_boxMapYX(
matchBox.boxMapYX, otherBox.gt, tolerance_ndigits=5) # avoids float coordinate rounding issues)
if previous_area == otherBox.mapPoly.area or time.time() - t_start > 1.5: if previous_area == otherBox.mapPoly.area or time.time() - t_start > 1.5:
# happens e.g in case of a triangular footprint # happens e.g in case of a triangular footprint
...@@ -838,7 +827,7 @@ class COREG(object): ...@@ -838,7 +827,7 @@ class COREG(object):
@staticmethod @staticmethod
def _shrink_winsize_to_binarySize(win_shape_YX, target_size=None): def _shrink_winsize_to_binarySize(win_shape_YX, target_size=None):
# type: (tuple, tuple, int , int) -> any # type: (tuple, tuple) -> Union[Tuple[int, int], None]
"""Shrinks a given window size to the closest binary window size (a power of 2) - """Shrinks a given window size to the closest binary window size (a power of 2) -
separately for X- and Y-dimension. separately for X- and Y-dimension.
...@@ -981,7 +970,7 @@ class COREG(object): ...@@ -981,7 +970,7 @@ class COREG(object):
def _get_grossly_deshifted_images(self, im0, im1, x_intshift, y_intshift): def _get_grossly_deshifted_images(self, im0, im1, x_intshift, y_intshift):
# TODO this is also implemented in GeoArray # this should update ref.win.data and shift.win.data # TODO this is also implemented in GeoArray # this should update ref.win.data and shift.win.data
# FIXME avoid that matching window gets smaller although shifting it with the previous win_size would not move # FIXME avoid that matching window gets smaller although shifting it with the previous win_size would not move
# FIXME it into nodata-area # it into nodata-area
# get_grossly_deshifted_im0 # get_grossly_deshifted_im0
old_center_YX = np.array(im0.shape) / 2 old_center_YX = np.array(im0.shape) / 2
new_center_YX = [old_center_YX[0] + y_intshift, old_center_YX[1] + x_intshift] new_center_YX = [old_center_YX[0] + y_intshift, old_center_YX[1] + x_intshift]
......
...@@ -4,7 +4,6 @@ import warnings ...@@ -4,7 +4,6 @@ import warnings
import os import os
from copy import copy from copy import copy
from six import PY2 from six import PY2
from importlib import util
# custom # custom
try: try:
...@@ -17,7 +16,8 @@ except ImportError: ...@@ -17,7 +16,8 @@ except ImportError:
pyfftw = None pyfftw = None
import numpy as np import numpy as np
from matplotlib import pyplot as plt from matplotlib import pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable from matplotlib.colorbar import ColorbarBase
from matplotlib.colors import Normalize
from .Tie_Point_Grid import Tie_Point_Grid from .Tie_Point_Grid import Tie_Point_Grid
from .CoReg import COREG from .CoReg import COREG
...@@ -318,7 +318,7 @@ class COREG_LOCAL(object): ...@@ -318,7 +318,7 @@ class COREG_LOCAL(object):
def CoRegPoints_table(self): def CoRegPoints_table(self):
"""Returns a GeoDataFrame with the columns 'geometry','POINT_ID','X_IM','Y_IM','X_UTM','Y_UTM','X_WIN_SIZE', """Returns a GeoDataFrame with the columns 'geometry','POINT_ID','X_IM','Y_IM','X_UTM','Y_UTM','X_WIN_SIZE',
'Y_WIN_SIZE','X_SHIFT_PX','Y_SHIFT_PX', 'X_SHIFT_M', 'Y_SHIFT_M', 'ABS_SHIFT' and 'ANGLE' containing all 'Y_WIN_SIZE','X_SHIFT_PX','Y_SHIFT_PX', 'X_SHIFT_M', 'Y_SHIFT_M', 'ABS_SHIFT' and 'ANGLE' containing all
information containing all the results frm coregistration for all points in the tie point grid. information containing all the results from coregistration for all points in the tie point grid.
""" """
return self.tiepoint_grid.CoRegPoints_table return self.tiepoint_grid.CoRegPoints_table
...@@ -339,7 +339,7 @@ class COREG_LOCAL(object): ...@@ -339,7 +339,7 @@ class COREG_LOCAL(object):
backgroundIm='tgt', hide_filtered=True, figsize=None, title='', vector_scale=1., backgroundIm='tgt', hide_filtered=True, figsize=None, title='', vector_scale=1.,
savefigPath='', savefigDPI=96, showFig=True, vmin=None, vmax=None, return_map=False, savefigPath='', savefigDPI=96, showFig=True, vmin=None, vmax=None, return_map=False,
zoomable=False): zoomable=False):
# type: (str, str, plt.cm, bool, str, bool, tuple, str, float, str, int, bool, float, float, bool) -> tuple # type: (str, str, plt.cm, bool, str, bool, tuple, str, float, str, int, bool, float, float, bool, bool) -> ...
"""Shows a map of the calculated tie point grid with the target image as background. """Shows a map of the calculated tie point grid with the target image as background.
:param shapes2plot: <str> 'points': plot points representing values of 'attribute2plot' onto the map :param shapes2plot: <str> 'points': plot points representing values of 'attribute2plot' onto the map
...@@ -373,11 +373,11 @@ class COREG_LOCAL(object): ...@@ -373,11 +373,11 @@ class COREG_LOCAL(object):
fig, ax, map2show = backgroundIm.show_map(figsize=figsize, nodataVal=self.nodata[1], return_map=True, fig, ax, map2show = backgroundIm.show_map(figsize=figsize, nodataVal=self.nodata[1], return_map=True,
band=self.COREG_obj.shift.band4match, zoomable=zoomable) band=self.COREG_obj.shift.band4match, zoomable=zoomable)
plt.tick_params(axis='both', which='major', labelsize=40) ax.tick_params(axis='both', which='major', labelsize=40)
# ax.tick_params(axis='both', which='minor', labelsize=8) # ax.tick_params(axis='both', which='minor', labelsize=8)
# fig, ax, map2show = backgroundIm.show_map_utm(figsize=(20,20), nodataVal=self.nodata[1], return_map=True) # fig, ax, map2show = backgroundIm.show_map_utm(figsize=(20,20), nodataVal=self.nodata[1], return_map=True)
plt.title(title or attribute2plot) ax.set_title(title or attribute2plot)
# transform all points of tie point grid to LonLat # transform all points of tie point grid to LonLat
outlierCols = [c for c in self.CoRegPoints_table.columns if 'OUTLIER' in c] outlierCols = [c for c in self.CoRegPoints_table.columns if 'OUTLIER' in c]
...@@ -393,7 +393,7 @@ class COREG_LOCAL(object): ...@@ -393,7 +393,7 @@ class COREG_LOCAL(object):
# vmin = min(GDF[GDF[attribute2plot] != self.outFillVal][attribute2plot]) # vmin = min(GDF[GDF[attribute2plot] != self.outFillVal][attribute2plot])
# vmax = max(GDF[GDF[attribute2plot] != self.outFillVal][attribute2plot]) # vmax = max(GDF[GDF[attribute2plot] != self.outFillVal][attribute2plot])
# norm = mpl_normalize(vmin=vmin, vmax=vmax) # norm = mpl_normalize(vmin=vmin, vmax=vmax)
palette = cmap if cmap is not None else plt.cm.RdYlGn_r palette = cmap if cmap is not None else plt.cm.get_cmap('RdYlGn_r')
if cmap is None and attribute2plot == 'ANGLE': if cmap is None and attribute2plot == 'ANGLE':
# import matplotlib.colors as mcolors # import matplotlib.colors as mcolors
# colors1 = plt.cm.RdYlGn_r(np.linspace(0., 1, 128)) # colors1 = plt.cm.RdYlGn_r(np.linspace(0., 1, 128))
...@@ -405,7 +405,7 @@ class COREG_LOCAL(object): ...@@ -405,7 +405,7 @@ class COREG_LOCAL(object):
# palette = plt.cm.hsv # palette = plt.cm.hsv
import cmocean import cmocean
palette = cmocean.cm.delta palette = getattr(cmocean.cm, 'delta')
# GDF['color'] = [*GDF[attribute2plot].map(lambda val: palette(norm(val)))] # GDF['color'] = [*GDF[attribute2plot].map(lambda val: palette(norm(val)))]
# add tie point grid to map # add tie point grid to map
...@@ -428,20 +428,20 @@ class COREG_LOCAL(object): ...@@ -428,20 +428,20 @@ class COREG_LOCAL(object):
if self.tieP_filter_level > 0: if self.tieP_filter_level > 0:
# flag level 1 outliers # flag level 1 outliers
GDF_filt = GDF[GDF.L1_OUTLIER.__eq__(True)].copy() GDF_filt = GDF[GDF.L1_OUTLIER.__eq__(True)].copy()
plt.scatter(GDF_filt['plt_X'], GDF_filt['plt_Y'], c='b', marker=marker, s=250, alpha=1.0, ax.scatter(GDF_filt['plt_X'], GDF_filt['plt_Y'], c='b', marker=marker, s=250, alpha=1.0,
label='reliability') label='reliability')
if self.tieP_filter_level > 1: if self.tieP_filter_level > 1:
# flag level 2 outliers # flag level 2 outliers
GDF_filt = GDF[GDF.L2_OUTLIER.__eq__(True)].copy() GDF_filt = GDF[GDF.L2_OUTLIER.__eq__(True)].copy()
plt.scatter(GDF_filt['plt_X'], GDF_filt['plt_Y'], c='r', marker=marker, s=150, alpha=1.0, label='SSIM') ax.scatter(GDF_filt['plt_X'], GDF_filt['plt_Y'], c='r', marker=marker, s=150, alpha=1.0, label='SSIM')
if self.tieP_filter_level > 2: if self.tieP_filter_level > 2:
# flag level 3 outliers # flag level 3 outliers
GDF_filt = GDF[GDF.L3_OUTLIER.__eq__(True)].copy() GDF_filt = GDF[GDF.L3_OUTLIER.__eq__(True)].copy()
plt.scatter(GDF_filt['plt_X'], GDF_filt['plt_Y'], c='y', marker=marker, s=250, alpha=1.0, ax.scatter(GDF_filt['plt_X'], GDF_filt['plt_Y'], c='y', marker=marker, s=250, alpha=1.0,
label='RANSAC') label='RANSAC')
if self.tieP_filter_level > 0: if self.tieP_filter_level > 0:
plt.legend(loc=0, scatterpoints=1) ax.legend(loc=0, scatterpoints=1)
# plot all points or vectors on top # plot all points or vectors on top
if not GDF.empty: if not GDF.empty:
...@@ -453,7 +453,7 @@ class COREG_LOCAL(object): ...@@ -453,7 +453,7 @@ class COREG_LOCAL(object):
if shapes2plot == 'vectors': if shapes2plot == 'vectors':
# plot shift vectors # plot shift vectors
# doc: https://matplotlib.org/devdocs/api/_as_gen/matplotlib.axes.Axes.quiver.html # doc: https://matplotlib.org/devdocs/api/_as_gen/matplotlib.axes.Axes.quiver.html
plt.quiver(GDF['plt_X'], GDF['plt_Y'], ax.quiver(GDF['plt_X'], GDF['plt_Y'],
-GDF['X_SHIFT_M'], -GDF['Y_SHIFT_M'], # invert absolute shifts to make arrows point to tgt -GDF['X_SHIFT_M'], -GDF['Y_SHIFT_M'], # invert absolute shifts to make arrows point to tgt
GDF[attribute2plot].clip(vmin, vmax), # sets the colors GDF[attribute2plot].clip(vmin, vmax), # sets the colors
scale=1200 / vector_scale, # larger values decrease the arrow length scale=1200 / vector_scale, # larger values decrease the arrow length
...@@ -462,25 +462,21 @@ class COREG_LOCAL(object): ...@@ -462,25 +462,21 @@ class COREG_LOCAL(object):
cmap=palette, cmap=palette,
pivot='middle' # position the middle point of the arrows onto the tie point location pivot='middle' # position the middle point of the arrows onto the tie point location
) )
mappable = None
elif shapes2plot == 'points': elif shapes2plot == 'points':
# plot tie points # plot tie points
points = plt.scatter(GDF['plt_X'], GDF['plt_Y'], c=GDF[attribute2plot], lw=0, ax.scatter(GDF['plt_X'], GDF['plt_Y'], c=GDF[attribute2plot], lw=0,
cmap=palette, marker='o' if len(GDF) < 10000 else '.', s=50, alpha=1.0, cmap=palette, marker='o' if len(GDF) < 10000 else '.', s=50, alpha=1.0,
vmin=vmin, vmax=vmax) vmin=vmin, vmax=vmax)
mappable = points
else: else:
raise ValueError("The parameter 'shapes2plot' must be set to 'vectors' or 'points'. Received %s." raise ValueError("The parameter 'shapes2plot' must be set to 'vectors' or 'points'. Received %s."
% shapes2plot) % shapes2plot)
# add colorbar # add colorbar
divider = make_axes_locatable(plt.gca()) p = ax.get_position().get_points().flatten() # [left, bottom, right, top]
# create axis on the right; size =2% of ax; padding = 0.1 inch cax = fig.add_axes([p[2] + 0.02, p[1], 0.02, p[3] - p[1]]) # [left, bottom, width, height]
cax = divider.append_axes("right", size="2%", pad=0.1) ColorbarBase(cax, cmap=palette, norm=Normalize(vmin=vmin, vmax=vmax), orientation='vertical')
plt.colorbar(mappable, cax=cax)
else: else:
if not self.q: if not self.q:
...@@ -501,13 +497,9 @@ class COREG_LOCAL(object): ...@@ -501,13 +497,9 @@ class COREG_LOCAL(object):
warnings.warn(UserWarning('This function is still under construction and may not work as expected!')) warnings.warn(UserWarning('This function is still under construction and may not work as expected!'))
assert self.CoRegPoints_table is not None, 'Calculate tie point grid first!' assert self.CoRegPoints_table is not None, 'Calculate tie point grid first!'
if not all([util.find_spec('folium'), util.find_spec('geojson')]):
raise ImportError("This method requires the libraries 'folium' and 'geojson'. They can be installed with "
"the shell command 'pip install folium geojson'.")
import folium import folium
import geojson import geojson
from folium import plugins from folium.raster_layers import ImageOverlay
lon_min, lat_min, lon_max, lat_max = \ lon_min, lat_min, lon_max, lat_max = \
reproject_shapelyGeometry(self.im2shift.box.mapPoly, self.im2shift.projection, 4326).bounds reproject_shapelyGeometry(self.im2shift.box.mapPoly, self.im2shift.projection, 4326).bounds
...@@ -525,7 +517,7 @@ class COREG_LOCAL(object): ...@@ -525,7 +517,7 @@ class COREG_LOCAL(object):
# create map # create map
map_osm = folium.Map(location=[center_lat, center_lon]) # ,zoom_start=3) map_osm = folium.Map(location=[center_lat, center_lon]) # ,zoom_start=3)
# import matplotlib # import matplotlib
plugins.ImageOverlay( ImageOverlay(
colormap=lambda x: (1, 0, 0, x), # TODO a colormap must be given colormap=lambda x: (1, 0, 0, x), # TODO a colormap must be given
# colormap=matplotlib.cm.gray, # does not work # colormap=matplotlib.cm.gray, # does not work
image=image2plot, bounds=[[lat_min, lon_min], [lat_max, lon_max]], image=image2plot, bounds=[[lat_min, lon_min], [lat_max, lon_max]],
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
import collections import collections
import time import time
import warnings import warnings
import numpy as np
# internal modules # internal modules
from geoarray import GeoArray from geoarray import GeoArray
...@@ -246,10 +247,11 @@ class DESHIFTER(object): ...@@ -246,10 +247,11 @@ class DESHIFTER(object):
# snap clipextent to output grid # snap clipextent to output grid
# (in case of odd input coords the output coords are moved INSIDE the input array) # (in case of odd input coords the output coords are moved INSIDE the input array)
xmin, ymin, xmax, ymax = self.clipextent xmin, ymin, xmax, ymax = self.clipextent
xmin = find_nearest(self.out_grid[0], xmin, roundAlg='on', extrapolate=True) x_tol, y_tol = float(np.ptp(self.out_grid[0]) / 10000), float(np.ptp(self.out_grid[1]) / 10000) # 10.000th pix
ymin = find_nearest(self.out_grid[1], ymin, roundAlg='on', extrapolate=True) xmin = find_nearest(self.out_grid[0], xmin, roundAlg='on', extrapolate=True, tolerance=x_tol)
xmax = find_nearest(self.out_grid[0], xmax, roundAlg='off', extrapolate=True) ymin = find_nearest(self.out_grid[1], ymin, roundAlg='on', extrapolate=True, tolerance=y_tol)
ymax = find_nearest(self.out_grid[1], ymax, roundAlg='off', extrapolate=True) xmax = find_nearest(self.out_grid[0], xmax, roundAlg='off', extrapolate=True, tolerance=x_tol)
ymax = find_nearest(self.out_grid[1], ymax, roundAlg='off', extrapolate=True, tolerance=y_tol)
return xmin, ymin, xmax, ymax return xmin, ymin, xmax, ymax
def correct_shifts(self): def correct_shifts(self):
......
...@@ -374,7 +374,8 @@ class Tie_Point_Grid(object): ...@@ -374,7 +374,8 @@ class Tie_Point_Grid(object):
'Y_SHIFT_M', 'ABS_SHIFT', 'ANGLE', 'SSIM_BEFORE', 'SSIM_AFTER', 'Y_SHIFT_M', 'ABS_SHIFT', 'ANGLE', 'SSIM_BEFORE', 'SSIM_AFTER',
'SSIM_IMPROVED', 'RELIABILITY', 'LAST_ERR']) 'SSIM_IMPROVED', 'RELIABILITY', 'LAST_ERR'])
GDF = GDF.merge(records, on='POINT_ID', how="inner") # merge DataFrames (dtype must be equal to records.dtypes; We need np.object due to None values)
GDF = GDF.astype(np.object).merge(records.astype(np.object), on='POINT_ID', how="inner")
GDF = GDF.fillna(int(self.outFillVal)) GDF = GDF.fillna(int(self.outFillVal))
if not self.q: if not self.q:
...@@ -608,11 +609,16 @@ class Tie_Point_Grid(object): ...@@ -608,11 +609,16 @@ class Tie_Point_Grid(object):
""" """
GDF = self.CoRegPoints_table GDF = self.CoRegPoints_table
GDF2pass = GDF if not skip_nodata else GDF[GDF[skip_nodata_col] != self.outFillVal]
if skip_nodata:
GDF2pass = GDF[GDF[skip_nodata_col] != self.outFillVal].copy()
else:
GDF2pass = GDF
GDF2pass.LAST_ERR = GDF2pass.apply(lambda GDF_row: repr(GDF_row.LAST_ERR), axis=1)
# replace boolean values (cannot be written) # replace boolean values (cannot be written)
GDF2pass = GDF2pass.replace(False, 0) # replace all booleans where column dtype is not np.bool but np.object GDF2pass = GDF2pass.replace(False, 0).copy() # replace booleans where column dtype is not np.bool but np.object
GDF2pass = GDF2pass.replace(True, 1) GDF2pass = GDF2pass.replace(True, 1).copy()
for col in GDF2pass.columns: for col in GDF2pass.columns:
if GDF2pass[col].dtype == np.bool: if GDF2pass[col].dtype == np.bool:
GDF2pass[col] = GDF2pass[col].astype(int) GDF2pass[col] = GDF2pass[col].astype(int)
......
...@@ -10,10 +10,11 @@ from arosics.CoReg_local import COREG_LOCAL ...@@ -10,10 +10,11 @@ from arosics.CoReg_local import COREG_LOCAL
from arosics.DeShifter import DESHIFTER from arosics.DeShifter import DESHIFTER
from arosics.Tie_Point_Grid import Tie_Point_Grid from arosics.Tie_Point_Grid import Tie_Point_Grid
from .version import __version__, __versionalias__ # noqa (E402 + F401)
__author__ = """Daniel Scheffler""" __author__ = """Daniel Scheffler"""
__email__ = 'daniel.scheffler@gfz-potsdam.de' __email__ = 'daniel.scheffler@gfz-potsdam.de'
__version__ = '0.8.6'
__versionalias__ = '2018-07-20_01'
__all__ = ['COREG', __all__ = ['COREG',
'COREG_LOCAL', 'COREG_LOCAL',
'DESHIFTER', 'DESHIFTER',
......
__version__ = '0.8.13'
__versionalias__ = '2018-12-04_01'
geoarray>=0.6.16 geoarray>=0.8.0
py_tools_ds>=0.12.1 py_tools_ds>=0.13.7
cmocean cmocean
numpy numpy
gdal gdal
...@@ -9,4 +9,5 @@ matplotlib ...@@ -9,4 +9,5 @@ matplotlib
geopandas geopandas
plotly plotly
six six
importlib folium>=0.6.0
geojson
...@@ -8,4 +8,3 @@ coverage==4.1 ...@@ -8,4 +8,3 @@ coverage==4.1
Sphinx==1.4.8 Sphinx==1.4.8
cryptography==1.7