Commit f1d361c8 authored by Daniel Scheffler's avatar Daniel Scheffler
Browse files

Revised arosics_cli.py. Fixed issue #14.

parent ac0841ef
Pipeline #1793 passed with stages
in 3 minutes and 3 seconds
......@@ -4,6 +4,7 @@ import os
import time
import warnings
from copy import copy
from typing import Iterable
# custom
try:
......@@ -215,8 +216,8 @@ class COREG(object):
if data_corners_tgt and not isinstance(data_corners_tgt[0], list): # group if not [[x,y],[x,y]..]
data_corners_tgt = [data_corners_tgt[i:i + 2] for i in range(0, len(data_corners_tgt), 2)]
if nodata:
assert isinstance(nodata, tuple) and len(nodata) == 2, \
"'nodata' must be a tuple with two values. Got %s with length %s." % (type(nodata), len(nodata))
assert isinstance(nodata, Iterable) and len(nodata) == 2, \
"'nodata' must be an iterable with two values. Got %s with length %s." % (type(nodata), len(nodata))
for rspAlg in [resamp_alg_deshift, resamp_alg_calc]:
assert rspAlg in _dict_rspAlg_rsp_Int.keys(), "'%s' is not a supported resampling algorithm." % rspAlg
if resamp_alg_calc in ['average', 5] and (v or not q):
......
......@@ -16,32 +16,33 @@ __author__ = "Daniel Scheffler"
def run_global_coreg(args):
COREG_obj = COREG(args.path_ref,
args.path_tgt,
path_out = args.path_out,
fmt_out = args.fmt_out,
r_b4match = args.br,
s_b4match = args.bs,
wp = args.wp,
ws = args.ws,
max_iter = args.max_iter,
max_shift = args.max_shift,
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,
data_corners_tgt = args.cor1,
nodata = args.nodata,
calc_corners = args.calc_cor,
CPUs = None if args.mp else 1,
force_quadratic_win = args.quadratic_win,
binary_ws = args.bin_ws,
mask_baddata_ref = args.mask_ref,
mask_baddata_tgt = args.mask_tgt,
v = args.v,
path_verbose_out = args.vo,
q = args.q,
ignore_errors = args.ignore_errors)
path_out=args.path_out,
fmt_out=args.fmt_out,
r_b4match=args.br,
s_b4match=args.bs,
wp=args.wp,
ws=args.ws,
max_iter=args.max_iter,
max_shift=args.max_shift,
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,
data_corners_tgt=args.cor1,
nodata=args.nodata,
calc_corners=args.calc_cor,
CPUs=None if args.mp else 1,
force_quadratic_win=args.quadratic_win,
binary_ws=args.bin_ws,
mask_baddata_ref=args.mask_ref,
mask_baddata_tgt=args.mask_tgt,
progress=args.progress,
v=args.v,
path_verbose_out=args.vo,
q=args.q,
ignore_errors=args.ignore_errors)
COREG_obj.correct_shifts()
......@@ -49,36 +50,36 @@ def run_global_coreg(args):
def run_local_coreg(args):
CRL = COREG_LOCAL(args.path_ref,
args.path_tgt,
path_out = args.path_out,
fmt_out = args.fmt_out,
grid_res = args.grid_res,
max_points = args.max_points,
r_b4match = args.br,
s_b4match = args.bs,
window_size = args.ws,
max_iter = args.max_iter,
max_shift = args.max_shift,
tieP_filter_level = args.tieP_filter_level,
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,
resamp_alg_calc = args.rsp_alg_deshift,
resamp_alg_deshift = args.rsp_alg_calc,
data_corners_ref = args.cor0,
data_corners_tgt = args.cor1,
nodata = args.nodata,
calc_corners = args.calc_cor,
mask_baddata_ref = args.mask_ref,
mask_baddata_tgt = args.mask_tgt,
CPUs = None if args.mp else 1,
path_out=args.path_out,
fmt_out=args.fmt_out,
grid_res=args.grid_res,
max_points=args.max_points,
r_b4match=args.br,
s_b4match=args.bs,
window_size=args.ws,
max_iter=args.max_iter,
max_shift=args.max_shift,
tieP_filter_level=args.tieP_filter_level,
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,
resamp_alg_calc=args.rsp_alg_deshift,
resamp_alg_deshift=args.rsp_alg_calc,
data_corners_ref=args.cor0,
data_corners_tgt=args.cor1,
nodata=args.nodata,
calc_corners=args.calc_cor,
mask_baddata_ref=args.mask_ref,
mask_baddata_tgt=args.mask_tgt,
CPUs=None if args.mp else 1,
force_quadratic_win=args.quadratic_win,
binary_ws = args.bin_ws,
progress = args.progress,
v = args.v,
q = args.q,
binary_ws=args.bin_ws,
progress=args.progress,
v=args.v,
q=args.q,
)
CRL.correct_shifts()
......@@ -130,128 +131,149 @@ def get_arosics_argparser():
parser.add_argument('--version', action='version', version=__version__)
subparsers = parser.add_subparsers()
# TODO add option to apply coreg results to multiple files
### SUBPARSER FOR COREG
parse_coreg_global = subparsers.add_parser('global',
description= 'Detects and corrects global X/Y shifts between a target and refernce image. Geometric shifts are '
'calculated at a specific (adjustable) image position. Correction performs a global shifting in '
'X- or Y direction.',
help="detect and correct global X/Y shifts (sub argument parser) - "
"use '>>> python /path/to/arosics/bin/arosics_cli.py global -h' for documentation and usage hints")
gloArg = parse_coreg_global.add_argument
gloArg('path_ref', type=str, help='source path of reference image (any GDAL compatible image format is supported)')
gloArg('path_tgt', type=str, help='source path of image to be shifted (any GDAL compatible image format is supported)')
gloArg('-o', nargs='?', dest='path_out', type=str, default='auto',
help="target path of the coregistered image (default: /dir/of/im1/<im1>__shifted_to__<im0>.bsq)")
#####################
# GENERAL ARGUMENTS #
#####################
gloArg('-fmt_out', nargs='?', type=str, 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)", default='ENVI')
general_opts_parser = argparse.ArgumentParser(add_help=False)
gop_p = general_opts_parser.add_argument
gop_p('path_ref', type=str, help='source path of reference image (any GDAL compatible image format is supported)')
gloArg('-br', nargs='?', type=int,
help='band of reference image to be used for matching (starts with 1; default: 1)', default=1)
gop_p('path_tgt', type=str,
help='source path of image to be shifted (any GDAL compatible image format is supported)')
gloArg('-bs', nargs='?', type=int,
help='band of shift image to be used for matching (starts with 1; default: 1)', default=1)
gop_p('-o', nargs='?', dest='path_out', type=str, default='auto',
help="target path of the coregistered image If 'auto' (default: /dir/of/im1/<im1>__shifted_to__<im0>.bsq)")
gloArg('-wp', nargs=2, metavar=('X', 'Y'), type=float,
help="custom matching window position as map values in the same projection like the reference image "
"(default: central position of image overlap)", default=(None,None))
gloArg('-ws', nargs=2, metavar=('X size', 'Y size'), type=float,
help="custom matching window size [pixels] (default: (256,256))", default=(256,256))
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)")
gloArg('-max_iter', nargs='?', type=int, help="maximum number of iterations for matching (default: 5)", default=5)
gop_p('-br', nargs='?', type=int, default=1,
help='band of reference image to be used for matching (starts with 1; default: 1)')
gloArg('-max_shift', nargs='?', type=int,
help="maximum shift distance in reference image pixel units (default: 5 px)", default=5)
gop_p('-bs', nargs='?', type=int, default=1,
help='band of shift image to be used for matching (starts with 1; default: 1)')
gloArg('-align_grids', nargs='?', type=int, choices=[0, 1],
help='align the coordinate grids of the output image to the reference image (default: 0)', default=0)
gop_p('-ws', nargs=2, metavar=('X size', 'Y size'), type=int, default=(256, 256),
help="custom matching window size [pixels] (default: (256,256))")
gloArg('-match_gsd', nargs='?', type=int, choices=[0, 1],
help='match the output pixel size to the pixel size of the reference image (default: 0)', default=0)
gop_p('-max_iter', nargs='?', type=int, default=5, help="maximum number of iterations for matching (default: 5)")
gloArg('-out_gsd', nargs=2, type=float, help='xgsd ygsd: set the output pixel size in map units'\
'(default: original pixel size of the image to be shifted)', metavar=('xgsd','ygsd'))
gop_p('-max_shift', nargs='?', type=int, default=5,
help="maximum shift distance in reference image pixel units (default: 5 px)")
gloArg('-rsp_alg_deshift', nargs='?', type=int, choices=list(range(12)), default=2,
gop_p('-rsp_alg_deshift', nargs='?', type=int, choices=list(range(12)), default=2,
help="the resampling algorithm to be used for shift correction (if neccessary) "
"(valid algorithms: 0=nearest neighbour, 1=bilinear, 2=cubic, 3=cubic_spline, 4=lanczos, 5=average, "
"6=mode, 7=max, 8=min, 9=med, 10=q1, 11=q3), default: 2")
gloArg('-rsp_alg_calc', nargs='?', type=int, choices=list(range(12)), default=2,
gop_p('-rsp_alg_calc', nargs='?', type=int, choices=list(range(12)), default=2,
help="the resampling algorithm to be used for all warping processes during calculation of spatial shifts "
"(valid algorithms: 0=nearest neighbour, 1=bilinear, 2=cubic, 3=cubic_spline, 4=lanczos, 5=average, "
"6=mode, 7=max, 8=min, 9=med, 10=q1, 11=q3), default: 2 (highly recommended)")
# TODO implement footprint_poly_ref, footprint_poly_tgt
gloArg('-cor0', nargs=8, type=float, help="map coordinates of data corners within reference image: ",
gop_p('-cor0', nargs=8, type=float, help="map coordinates of data corners within reference image: ",
metavar=tuple("UL-X UL-Y UR-X UR-Y LR-X LR-Y LL-X LL-Y".split(' ')), default=None)
gloArg('-cor1', nargs=8, type=float, help="map coordinates of data corners within image to be shifted: ",
gop_p('-cor1', nargs=8, type=float, help="map coordinates of data corners within image to be shifted: ",
metavar=tuple("UL-X UL-Y UR-X UR-Y LR-X LR-Y LL-X LL-Y".split(' ')), default=None)
gloArg('-nodata', nargs=2, type=float, metavar=('im0', 'im1'),
help='no data values for reference image and image to be shifted', default=(None,None))
gloArg('-calc_cor', nargs='?', type=int, choices=[0, 1], default=1,
gop_p('-calc_cor', nargs='?', type=int, choices=[0, 1], default=1,
help="calculate true positions of the dataset corners in order to get a useful matching window position "
"within the actual image overlap (default: 1; deactivated if '-cor0' and '-cor1' are given")
gloArg('-bin_ws', nargs='?', type=int,
help='use binary X/Y dimensions for the matching window (default: 1)', default=1, choices=[0, 1])
gop_p('-nodata', nargs=2, type=float, metavar=('im0', 'im1'),
help='no data values for reference image and image to be shifted', default=(None, None))
gop_p('-bin_ws', nargs='?', type=int,
help='use binary X/Y dimensions for the matching window (default: 1)', choices=[0, 1], default=1)
gloArg('-quadratic_win', nargs='?', type=int,
help='force a quadratic matching window (default: 1)', default=1, choices=[0, 1])
gop_p('-quadratic_win', nargs='?', type=int,
help='force a quadratic matching window (default: 1)', choices=[0, 1], default=1)
gloArg('-mask_ref', nargs='?', type=str, default=None, metavar='file path',
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 "
"position is valid in the sense of useful data. Otherwise this window position is rejected.")
gloArg('-mask_tgt', nargs='?', type=str, default=None, metavar='file path',
gop_p('-mask_tgt', nargs='?', type=str, metavar='file path', default=None,
help="path to a 2D boolean mask file for the image to be shifted 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 the image to be shifted. 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.")
gloArg('-mp', nargs='?', type=int, help='enable multiprocessing (default: 1)', default=1, choices=[0, 1])
gop_p('-mp', nargs='?', type=int, help='enable multiprocessing (default: 1)', choices=[0, 1], default=1)
gloArg('-v', nargs='?', type=int, help='verbose mode (default: 0)', default=0, choices=[0, 1])
gop_p('-progress', nargs='?', type=int, help='show progress bars (default: 1)', default=1, choices=[0, 1])
gloArg('-vo', nargs='?', type=str, choices=[0, 1], help='an optional output directory for outputs of verbose mode'
'(if not given, no outputs are written to disk)', default=0, )
gop_p('-v', nargs='?', type=int, help='verbose mode (default: 0)', choices=[0, 1], default=0)
gloArg('-q', nargs='?', type=int, help='quiet mode (default: 0)', default=0, choices=[0, 1])
gop_p('-q', nargs='?', type=int, help='quiet mode (default: 0)', choices=[0, 1], default=0)
gloArg('-ignore_errors', nargs='?', type=int, help='Useful for batch processing. (default: 0) In case of error '
'COREG.success == False and COREG.x_shift_px/COREG.y_shift_px is None', default=0, choices=[0,1])
gop_p('-ignore_errors', nargs='?', type=int, choices=[0, 1], default=0,
help='Useful for batch processing. (default: 0) In case of error '
'COREG(_LOCAL).success == False and COREG(_LOCAL).x_shift_px/COREG(_LOCAL).y_shift_px is None')
parse_coreg_global.set_defaults(func=run_global_coreg)
# TODO implement footprint_poly_ref, footprint_poly_tgt
##############
# SUBPARSERS #
##############
subparsers = parser.add_subparsers()
# TODO add option to apply coreg results to multiple files
#######################
# SUBPARSER FOR COREG #
#######################
parse_coreg_global = subparsers.add_parser(
'global', parents=[general_opts_parser], formatter_class=argparse.ArgumentDefaultsHelpFormatter,
description='Detects and corrects global X/Y shifts between a target and refernce image. Geometric shifts are '
'calculated at a specific (adjustable) image position. Correction performs a global shifting in '
'X- or Y direction.',
help="detect and correct global X/Y shifts (sub argument parser) - "
"use '>>> python /path/to/arosics/bin/arosics_cli.py global -h' for documentation and usage hints")
gloArg = parse_coreg_global.add_argument
### SUBPARSER FOR COREG LOCAL
parse_coreg_local = subparsers.add_parser('local',
description= 'Applies the algorithm to detect spatial shifts to the whole overlap area of the input images. '
gloArg('-wp', nargs=2, metavar=('X', 'Y'), type=float,
help="custom matching window position as map values in the same projection like the reference image "
"(default: central position of image overlap)", default=(None, None))
gloArg('-align_grids', nargs='?', type=int, choices=[0, 1],
help='align the coordinate grids of the output image to the reference image (default: 0)', default=0)
gloArg('-match_gsd', nargs='?', type=int, choices=[0, 1],
help='match the output pixel size to the pixel size of the reference image (default: 0)', default=0)
gloArg('-out_gsd', nargs=2, type=float, metavar=('xgsd', 'ygsd'),
help='xgsd ygsd: set the output pixel size in map units (default: original pixel size of the image to be '
'shifted)')
gloArg('-vo', nargs='?', type=str, choices=[0, 1], help='an optional output directory for outputs of verbose mode'
'(if not given, no outputs are written to disk)',
default=0, )
parse_coreg_global.set_defaults(func=run_global_coreg)
#############################
# SUBPARSER FOR COREG LOCAL #
#############################
parse_coreg_local = subparsers.add_parser(
'local', parents=[general_opts_parser], formatter_class=argparse.ArgumentDefaultsHelpFormatter,
description='Applies the algorithm to detect spatial shifts to the whole overlap area of the input images. '
'Spatial shifts are calculated for each point in grid of which the parameters can be adjusted '
'using keyword arguments. Shift correction performs a polynomial transformation using the '
'calculated shifts of each point in the grid as GCPs. Thus this class can be used to correct ' \
'calculated shifts of each point in the grid as GCPs. Thus this class can be used to correct '
'for locally varying geometric distortions of the target image.',
help="detect and correct local shifts (sub argument parser)"
"use '>>> python /path/to/arosics/bin/arosics_cli.py local -h' for documentation and usage hints")
locArg = parse_coreg_local.add_argument
locArg('path_ref', type=str, help='source path of reference image (any GDAL compatible image format is supported)')
locArg('path_tgt', type=str, help='source path of image to be shifted (any GDAL compatible image format is supported)')
locArg('grid_res', type=int, help='tie point grid resolution in pixels of the target image')
......@@ -260,27 +282,8 @@ def get_arosics_argparser():
"from the given point grid (specified by 'grid_res'). If the point does not provide enough points, all "
"available points are chosen.")
locArg('-o', nargs='?', type=str, dest='path_out', default='auto',
help="target path of the coregistered image. If 'auto' (default): /dir/of/im1/<im1>__shifted_to__<im0>.bsq")
locArg('-fmt_out', nargs='?', type=str, 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)", default='ENVI')
locArg('-projectDir', nargs='?', type=str, help=None, default=None)
locArg('-ws', nargs=2, type=int, help='custom matching window size [pixels] (default: (256,256))')
locArg('-br', nargs='?', type=int,
help='band of reference image to be used for matching (starts with 1; default: 1)', default=1)
locArg('-bs', nargs='?', type=int,
help='band of shift image to be used for matching (starts with 1; default: 1)', default=1)
locArg('-max_iter', nargs='?', type=int, help="maximum number of iterations for matching (default: 5)", default=5)
locArg('-max_shift', nargs='?', type=int,
help="maximum shift distance in reference image pixel units (default: 5 px)", default=5)
locArg('-tieP_filter_level', nargs='?', type=int, default=3, choices=[0, 1, 2, 3],
help="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 "
......@@ -300,57 +303,6 @@ def get_arosics_argparser():
locArg('-rs_tolerance', nargs='?', type=float, default=2.5,
help="RANSAC tie point filtering: percentage tolerance for max_outlier_percentage (default: 2.5 percent)")
# TODO implement footprint_poly_ref, footprint_poly_tgt
locArg('-rsp_alg_deshift', nargs='?', type=int, choices=list(range(12)), default=2,
help="the resampling algorithm to be used for shift correction (if neccessary) "
"(valid algorithms: 0=nearest neighbour, 1=bilinear, 2=cubic, 3=cubic_spline, 4=lanczos, 5=average, "
"6=mode, 7=max, 8=min, 9=med, 10=q1, 11=q3), default: 2")
locArg('-rsp_alg_calc', nargs='?', type=int, choices=list(range(12)), default=2,
help="the resampling algorithm to be used for all warping processes during calculation of spatial shifts "
"(valid algorithms: 0=nearest neighbour, 1=bilinear, 2=cubic, 3=cubic_spline, 4=lanczos, 5=average, "
"6=mode, 7=max, 8=min, 9=med, 10=q1, 11=q3), default: 2 (highly recommended)")
locArg('-cor0', nargs=8, type=float, help="map coordinates of data corners within reference image: ",
metavar=tuple("UL-X UL-Y UR-X UR-Y LR-X LR-Y LL-X LL-Y".split(' ')), default=None)
locArg('-cor1', nargs=8, type=float, help="map coordinates of data corners within image to be shifted: ",
metavar=tuple("UL-X UL-Y UR-X UR-Y LR-X LR-Y LL-X LL-Y".split(' ')), default=None)
locArg('-nodata', nargs=2, type=float, metavar=('im0', 'im1'),
help='no data values for reference image and image to be shifted', default=(None,None))
locArg('-calc_cor', nargs='?', type=int, choices=[0, 1], default=1,
help="calculate true positions of the dataset corners in order to get a useful matching window position "
"within the actual image overlap (default: 1; deactivated if '-cor0' and '-cor1' are given")
locArg('-mp', nargs='?', type=int, help='enable multiprocessing (default: 1)', default=1, choices=[0, 1])
locArg('-bin_ws', nargs='?', type=int,
help='use binary X/Y dimensions for the matching window (default: 1)', default=1, choices=[0, 1])
locArg('-quadratic_win', nargs='?', type=int,
help='force a quadratic matching window (default: 1)', default=1, choices=[0, 1])
locArg('-mask_ref', nargs='?', type=str, default=None, metavar='file path',
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 "
"position is valid in the sense of useful data. Otherwise this window position is rejected.")
locArg('-mask_tgt', nargs='?', type=str, default=None, metavar='file path',
help="path to a 2D boolean mask file for the image to be shifted 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 the image to be shifted. 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.")
locArg('-progress', nargs='?', type=int, help='show progress bars (default: 1)', default=1, choices=[0, 1])
locArg('-v', nargs='?', type=int, help='verbose mode (default: 0)', default=0, choices=[0, 1])
locArg('-q', nargs='?', type=int, help='quiet mode (default: 0)', default=0, choices=[0, 1])
parse_coreg_local.set_defaults(func=run_local_coreg)
return parser
......@@ -370,22 +322,23 @@ if __name__ == '__main__':
wfa('/misc/hy5/scheffler/tmp/crlf', '%s\t%s\t%s\t%s\n' % (dt.now(), getuser(), gethostname(), ' '.join(sys.argv)))
parser = get_arosics_argparser()
parsed_args = parser.parse_args()
argparser = get_arosics_argparser()
parsed_args = argparser.parse_args()
if len(sys.argv) == 1:
# no arguments provided
print('======================================================================\n'
'# AROSICS v%s #' % __version__+'\n'
print(
'======================================================================\n'
'# AROSICS v%s #' % __version__ + '\n'
'# An Automated and Robust Open-Source Image Co-Registration Software #\n'
'# for Multi-Sensor Satellite Data #\n'
'# - python implementation by Daniel Scheffler #\n'
'======================================================================\n')
parser.print_help()
argparser.print_help()
else:
t0 = time.time()
parsed_args.func(parsed_args)
print('\ntotal processing time: %.2fs' %(time.time()-t0))
print('\ntotal processing time: %.2fs' % (time.time() - t0))
else:
warnings.warn("The script 'arosics_cli.py' provides a command line argument parser for AROSICS and is not to be "
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment