Commit 64c82449 authored by Daniel Scheffler's avatar Daniel Scheffler

Merge branch 'master' into coreg_baseclass

parents 02cb054f fdfeb162
Pipeline #3334 failed with stages
in 3 minutes and 53 seconds
......@@ -20,8 +20,10 @@ test_arosics:
stage: test
script:
- 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
- pip install "py_tools_ds>=0.13.7" # FIXME remove as soon as docker runner has been updated
- make nosetests
- make docs
artifacts:
......@@ -37,8 +39,10 @@ test_styles:
stage: test
script:
- 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
# - pip install "pycodestyle>=2.0.0,!=2.4.0" # TODO remove as soon as docker runner is recreated
- make lint
artifacts:
paths:
......@@ -52,11 +56,11 @@ test_arosics_install:
stage: test
script:
- source /root/miniconda3/bin/activate
- export GDAL_DATA=/root/miniconda3/share/gdal
- conda create -y -q --name arosics python=3
- source activate arosics
- conda create -y -q --name arosics_testinstall python=3
- source activate arosics_testinstall
# 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 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
- python setup.py install
# test if its importable
......@@ -107,6 +111,7 @@ deploy_pypi:
- test_arosics
script: # Configure the PyPI credentials, then push the package, and cleanup the creds.
- source /root/miniconda3/bin/activate
- source activate ci_env
- mkdir -p public/images/
- cp -r docs/images/* public/images/
- printf "[distutils]\nindex-servers =\n pypi\n\n" >> ~/.pypirc
......
......@@ -4,7 +4,7 @@ import os
import time
import warnings
from copy import copy
from typing import Iterable
from typing import Iterable, Union, Tuple # noqa F401
# custom
try:
......@@ -133,7 +133,7 @@ class COREG(object):
- if None (default), the method correct_shifts() does not write 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', 'GeoTIFF'; default: ENVI). Refer to
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"]
......@@ -337,11 +337,22 @@ class COREG(object):
'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))
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
path_im_ref = im_ref.filePath if isinstance(im_ref, GeoArray) else im_ref
path_im_tgt = im_tgt.filePath if isinstance(im_tgt, GeoArray) else im_tgt
# get input paths
def get_input_path(im):
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'
......@@ -430,34 +441,17 @@ class COREG(object):
if not self.q:
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':
# resample target image to reference image
self.shift.arr = self.shift[:, :, self.shift.band4match] # resample the needed band only
self.shift = apply_subset_bandnames_metadata(self.shift)
if self.shift.bands > 1:
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.band4match = 0 # after resampling there is only one band in the GeoArray
else:
# resample reference image to target image
# FIXME in case of different projections this will change the projection of the reference image!
self.ref.arr = self.ref[:, :, self.ref.band4match] # resample the needed band only
self.ref = apply_subset_bandnames_metadata(self.ref)
if self.ref.bands > 1:
self.ref = self.ref.get_subset(zslice=slice(self.ref.band4match, self.ref.band4match + 1))
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
......@@ -467,14 +461,8 @@ class COREG(object):
# TODO different colors for polygons
assert self.overlap_poly, 'Please calculate the overlap polygon first.'
try:
import folium
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'.")
import folium
import geojson
refPoly = reproject_shapelyGeometry(self.ref.poly, self.ref.epsg, 4326)
shiftPoly = reproject_shapelyGeometry(self.shift.poly, self.shift.epsg, 4326)
......@@ -608,7 +596,6 @@ class COREG(object):
PLT.subplot_3dsurface(scps.astype(np.float32))
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
trueCornerLonLat.
......@@ -711,7 +698,8 @@ class COREG(object):
# Check, ob match Fenster größer als anderes Fenster
if not (matchBox.mapPoly.within(otherBox.mapPoly) or matchBox.mapPoly == otherBox.mapPoly):
# 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
t_start = time.time()
......@@ -720,7 +708,8 @@ class COREG(object):
xLarger, yLarger = otherBox.is_larger_DimXY(overlapWin.boundsIm)
matchBox.buffer_imXY(-1 if xLarger else 0, -1 if yLarger else 0)
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:
# happens e.g in case of a triangular footprint
......@@ -838,7 +827,7 @@ class COREG(object):
@staticmethod
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) -
separately for X- and Y-dimension.
......@@ -981,7 +970,7 @@ class COREG(object):
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
# 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
old_center_YX = np.array(im0.shape) / 2
new_center_YX = [old_center_YX[0] + y_intshift, old_center_YX[1] + x_intshift]
......
......@@ -4,7 +4,6 @@ import warnings
import os
from copy import copy
from six import PY2
from importlib import util
# custom
try:
......@@ -17,7 +16,8 @@ except ImportError:
pyfftw = None
import numpy as np
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 .CoReg import COREG
......@@ -59,7 +59,7 @@ class COREG_LOCAL(object):
- 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', 'GeoTIFF'; default: ENVI). Refer to
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"]
......@@ -318,7 +318,7 @@ class COREG_LOCAL(object):
def CoRegPoints_table(self):
"""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
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
......@@ -339,7 +339,7 @@ class COREG_LOCAL(object):
backgroundIm='tgt', hide_filtered=True, figsize=None, title='', vector_scale=1.,
savefigPath='', savefigDPI=96, showFig=True, vmin=None, vmax=None, return_map=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.
:param shapes2plot: <str> 'points': plot points representing values of 'attribute2plot' onto the map
......@@ -373,11 +373,11 @@ class COREG_LOCAL(object):
fig, ax, map2show = backgroundIm.show_map(figsize=figsize, nodataVal=self.nodata[1], return_map=True,
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)
# 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
outlierCols = [c for c in self.CoRegPoints_table.columns if 'OUTLIER' in c]
......@@ -393,7 +393,7 @@ class COREG_LOCAL(object):
# vmin = min(GDF[GDF[attribute2plot] != self.outFillVal][attribute2plot])
# vmax = max(GDF[GDF[attribute2plot] != self.outFillVal][attribute2plot])
# 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':
# import matplotlib.colors as mcolors
# colors1 = plt.cm.RdYlGn_r(np.linspace(0., 1, 128))
......@@ -405,7 +405,7 @@ class COREG_LOCAL(object):
# palette = plt.cm.hsv
import cmocean
palette = cmocean.cm.delta
palette = getattr(cmocean.cm, 'delta')
# GDF['color'] = [*GDF[attribute2plot].map(lambda val: palette(norm(val)))]
# add tie point grid to map
......@@ -428,20 +428,20 @@ class COREG_LOCAL(object):
if self.tieP_filter_level > 0:
# flag level 1 outliers
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,
label='reliability')
ax.scatter(GDF_filt['plt_X'], GDF_filt['plt_Y'], c='b', marker=marker, s=250, alpha=1.0,
label='reliability')
if self.tieP_filter_level > 1:
# flag level 2 outliers
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:
# flag level 3 outliers
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,
label='RANSAC')
ax.scatter(GDF_filt['plt_X'], GDF_filt['plt_Y'], c='y', marker=marker, s=250, alpha=1.0,
label='RANSAC')
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
if not GDF.empty:
......@@ -453,34 +453,30 @@ class COREG_LOCAL(object):
if shapes2plot == 'vectors':
# plot shift vectors
# doc: https://matplotlib.org/devdocs/api/_as_gen/matplotlib.axes.Axes.quiver.html
plt.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[attribute2plot].clip(vmin, vmax), # sets the colors
scale=1200 / vector_scale, # larger values decrease the arrow length
width=.0015, # arrow width (in relation to plot width)
# linewidth=1, # maybe use this to mark outliers instead of scatter points
cmap=palette,
pivot='middle' # position the middle point of the arrows onto the tie point location
)
mappable = None
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[attribute2plot].clip(vmin, vmax), # sets the colors
scale=1200 / vector_scale, # larger values decrease the arrow length
width=.0015, # arrow width (in relation to plot width)
# linewidth=1, # maybe use this to mark outliers instead of scatter points
cmap=palette,
pivot='middle' # position the middle point of the arrows onto the tie point location
)
elif shapes2plot == 'points':
# plot tie points
points = plt.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,
vmin=vmin, vmax=vmax)
mappable = points
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,
vmin=vmin, vmax=vmax)
else:
raise ValueError("The parameter 'shapes2plot' must be set to 'vectors' or 'points'. Received %s."
% shapes2plot)
# add colorbar
divider = make_axes_locatable(plt.gca())
# create axis on the right; size =2% of ax; padding = 0.1 inch
cax = divider.append_axes("right", size="2%", pad=0.1)
plt.colorbar(mappable, cax=cax)
p = ax.get_position().get_points().flatten() # [left, bottom, right, top]
cax = fig.add_axes([p[2] + 0.02, p[1], 0.02, p[3] - p[1]]) # [left, bottom, width, height]
ColorbarBase(cax, cmap=palette, norm=Normalize(vmin=vmin, vmax=vmax), orientation='vertical')
else:
if not self.q:
......@@ -501,13 +497,9 @@ class COREG_LOCAL(object):
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!'
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 geojson
from folium import plugins
from folium.raster_layers import ImageOverlay
lon_min, lat_min, lon_max, lat_max = \
reproject_shapelyGeometry(self.im2shift.box.mapPoly, self.im2shift.projection, 4326).bounds
......@@ -525,7 +517,7 @@ class COREG_LOCAL(object):
# create map
map_osm = folium.Map(location=[center_lat, center_lon]) # ,zoom_start=3)
# import matplotlib
plugins.ImageOverlay(
ImageOverlay(
colormap=lambda x: (1, 0, 0, x), # TODO a colormap must be given
# colormap=matplotlib.cm.gray, # does not work
image=image2plot, bounds=[[lat_min, lon_min], [lat_max, lon_max]],
......
......@@ -3,6 +3,7 @@
import collections
import time
import warnings
import numpy as np
# internal modules
from geoarray import GeoArray
......@@ -34,7 +35,7 @@ class DESHIFTER(object):
:Keyword Arguments:
- path_out(str): /output/directory/filename for coregistered results
- 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', 'GeoTIFF'; default: ENVI)
compatible raster file format (e.g. 'ENVI', 'GTIFF'; default: ENVI)
- out_crea_options(list): GDAL creation options for the output image,
e.g. ["QUALITY=20", "REVERSIBLE=YES", "WRITE_METADATA=YES"]
- band2process (int): The index of the band to be processed within the given array (starts with 1),
......@@ -246,10 +247,11 @@ class DESHIFTER(object):
# snap clipextent to output grid
# (in case of odd input coords the output coords are moved INSIDE the input array)
xmin, ymin, xmax, ymax = self.clipextent
xmin = find_nearest(self.out_grid[0], xmin, roundAlg='on', extrapolate=True)
ymin = find_nearest(self.out_grid[1], ymin, roundAlg='on', extrapolate=True)
xmax = find_nearest(self.out_grid[0], xmax, roundAlg='off', extrapolate=True)
ymax = find_nearest(self.out_grid[1], ymax, roundAlg='off', 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
xmin = find_nearest(self.out_grid[0], xmin, roundAlg='on', extrapolate=True, tolerance=x_tol)
ymin = find_nearest(self.out_grid[1], ymin, roundAlg='on', extrapolate=True, tolerance=y_tol)
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
def correct_shifts(self):
......@@ -382,7 +384,7 @@ def deshift_image_using_coreg_info(im2shift, coreg_results, path_out=None, fmt_o
:param path_out: /output/directory/filename for coregistered results. If None, no output is written - only
the shift corrected results are returned.
:param 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', 'GeoTIFF'; default: ENVI)
compatible raster file format (e.g. 'ENVI', 'GTIFF'; default: ENVI)
:param q: quiet mode (default: False)
:return:
"""
......
......@@ -368,13 +368,14 @@ class Tie_Point_Grid(object):
bar.print_progress((i + 1) / len(GDF) * 100)
results[i, :] = self._get_spatial_shifts(coreg_kwargs)
# merge results with GDF
records = GeoDataFrame(np.array(results, np.object),
# merge results with GDF
records = GeoDataFrame(results,
columns=['POINT_ID', 'X_WIN_SIZE', 'Y_WIN_SIZE', 'X_SHIFT_PX', 'Y_SHIFT_PX', 'X_SHIFT_M',
'Y_SHIFT_M', 'ABS_SHIFT', 'ANGLE', 'SSIM_BEFORE', 'SSIM_AFTER',
'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))
if not self.q:
......@@ -608,11 +609,16 @@ class Tie_Point_Grid(object):
"""
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)
GDF2pass = GDF2pass.replace(False, 0) # replace all booleans where column dtype is not np.bool but np.object
GDF2pass = GDF2pass.replace(True, 1)
GDF2pass = GDF2pass.replace(False, 0).copy() # replace booleans where column dtype is not np.bool but np.object
GDF2pass = GDF2pass.replace(True, 1).copy()
for col in GDF2pass.columns:
if GDF2pass[col].dtype == np.bool:
GDF2pass[col] = GDF2pass[col].astype(int)
......
......@@ -10,10 +10,11 @@ from arosics.CoReg_local import COREG_LOCAL
from arosics.DeShifter import DESHIFTER
from arosics.Tie_Point_Grid import Tie_Point_Grid
from .version import __version__, __versionalias__ # noqa (E402 + F401)
__author__ = """Daniel Scheffler"""
__email__ = 'daniel.scheffler@gfz-potsdam.de'
__version__ = '0.8.4'
__versionalias__ = '2018-03-08_01'
__all__ = ['COREG',
'COREG_LOCAL',
'DESHIFTER',
......
__version__ = '0.8.13'
__versionalias__ = '2018-12-04_01'
......@@ -63,9 +63,9 @@ def run_local_coreg(args):
min_reliability=args.min_reliability,
rs_max_outlier=args.rs_max_outlier,
rs_tolerance=args.rs_tolerance,
# align_grids = args.align_grids,
# match_gsd = args.match_gsd,
# out_gsd = args.out_gsd,
# align_grids=args.align_grids,
# match_gsd=args.match_gsd,
# out_gsd=args.out_gsd,
resamp_alg_calc=args.rsp_alg_deshift,
resamp_alg_deshift=args.rsp_alg_calc,
data_corners_ref=args.cor0,
......@@ -147,7 +147,7 @@ def get_arosics_argparser():
gop_p('-fmt_out', nargs='?', type=str, default='ENVI',
help="raster file format for output file. ignored if path_out is None. can "
"be any GDAL compatible raster file format (e.g. 'ENVI', 'GeoTIFF'; default: ENVI)")
"be any GDAL compatible raster file format (e.g. 'ENVI', 'GTIFF'; default: ENVI)")
gop_p('-br', nargs='?', type=int, default=1,
help='band of reference image to be used for matching (starts with 1; default: 1)')
......@@ -195,7 +195,7 @@ def get_arosics_argparser():
gop_p('-mask_ref', nargs='?', type=str, metavar='file path', default=None,
help="path to a 2D boolean mask file for the reference image where all bad data pixels (e.g. clouds) are "
"marked with True or 1 and the remaining pixels with False or 0. Must have the same geographic extent "
"and projection like the refernce image. The mask is used to check if the chosen matching window "
"and projection like the reference image. 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.")
gop_p('-mask_tgt', nargs='?', type=str, metavar='file path', default=None,
......
geoarray>=0.6.16
py_tools_ds>=0.12.1
geoarray>=0.8.0
py_tools_ds>=0.13.7
cmocean
numpy
gdal
......@@ -9,3 +9,5 @@ matplotlib
geopandas
plotly
six
folium>=0.6.0
geojson
......@@ -8,4 +8,3 @@ coverage==4.1
Sphinx==1.4.8
cryptography==1.7
PyYAML==3.11
cmocean
plotly
six
folium>=0.6.0
geojson
......@@ -13,8 +13,12 @@ with open('README.rst') as readme_file:
with open('HISTORY.rst') as history_file:
history = history_file.read()
requirements = ['numpy', 'gdal', 'shapely', 'scikit-image', 'matplotlib', 'geopandas', 'geoarray>=0.6.16',
'py_tools_ds>=0.12.1', 'plotly', 'cmocean', 'six',
version = {}
with open("arosics/version.py") as version_file:
exec(version_file.read(), version)
requirements = ['numpy', 'gdal', 'shapely', 'scikit-image', 'matplotlib', 'geopandas', 'geoarray>=0.8.0',
'py_tools_ds>=0.13.7', 'plotly', 'cmocean', 'six', 'folium>=0.6.0', 'geojson'
# 'pykrige' # conda install --yes -c conda-forge pykrige
# 'pyfftw', # conda install --yes -c conda-forge pyfftw=0.10.4 ; \
# 'basemap', # conda install --yes -c conda-forge basemap; \
......@@ -28,7 +32,7 @@ test_requirements = requirements + ['coverage', 'nose', 'nose-htmloutput', 'redn
setup(
name='arosics',
version='0.8.4',
version=version['__version__'],
description="An Automated and Robust Open-Source Image Co-Registration Software for Multi-Sensor Satellite Data",
long_description=readme + '\n\n' + history,
author="Daniel Scheffler",
......@@ -53,6 +57,7 @@ setup(
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
],
test_suite='tests',
tests_require=test_requirements,
......
......@@ -2,7 +2,7 @@
context_dir="./context"
dockerfile="arosics_ci.docker"
tag="arosics_ci:0.6.10"
tag="arosics_ci:0.8.7"
gitlab_runner="arosics_gitlab_CI_runner"
echo "#### Build runner docker image"
......
FROM gms_base_centos:pinned_v0.1
FROM gms_base_centos:0.2
# copy some needed stuff to /root
COPY *.yml /root/
# update the ci_env environment (that already contains all packages installed via 'docker_pyenvs' repo)
RUN /bin/bash -i -c "\
source /root/miniconda3/bin/activate ; \
conda env update -n root -f /root/environment_arosics.yml"
source activate ci_env; \
conda env update -n ci_env -f /root/environment_arosics.yml"
......@@ -9,6 +9,7 @@ dependencies:
- pyqt
- numpy
- gdal
- conda-forge::libgdal # force to use conda-forge for libgdal to avoid package version incompatiblies due to mixed channels
- scikit-image
- rasterio
- pyproj
......@@ -33,10 +34,11 @@ dependencies:
- sphinx-argparse
- six
- spectral
- folium>=0.6.0
- geojson
- flake8
- pycodestyle
- pycodestyle<2.4.0 # fixes ImportError: module 'pycodestyle' has no attribute 'break_around_binary_operator'
- pylint
- pydocstyle
- nose
- nose2
- nose-htmloutput
......@@ -44,5 +46,5 @@ dependencies:
- rednose
- cmocean
- plotly
- geoarray>=0.6.16
- py_tools_ds>=0.12.1
- geoarray>=0.8.0
- py_tools_ds>=0.13.7
......@@ -21,7 +21,7 @@ test_cases = dict(
footprint_poly_tgt='POLYGON ((341890 5866490, 356180 5866490, 356180 5834970, 335440 5834970, '
'335490 5845270, 341890 5866490))',
progress=False,
v=0),
v=False),
wp_inside=(344720, 5848485), # inside of overlap
wp_covering_nodata=(339611, 5856426), # close to the image edge of the input images -> win>64px covers nodata
wp_close_to_edge=(353810, 5840516), # close to the image edge of the input images -> win>64px covers nodata
......
......@@ -6,6 +6,7 @@
import unittest
import shutil
import os
import numpy as np
# custom
from .cases import test_cases
......@@ -102,6 +103,38 @@ class CompleteWorkflow_INTER1_S2A_S2A(unittest.TestCase):
footprint_poly_tgt=None))
self.assertTrue(CR.success)
def test_shift_calculation_with_float_coords(self):
"""Test with default parameters - should compute X/Y shifts properly ad 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, 10.1, 0.0, 5862000.0000001, 0.0, -10.1]
tgt = GeoArray(self.tgt_path)
tgt.to_mem()
tgt.filePath