pygeotools 1.1.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
pygeotools/__init__.py ADDED
@@ -0,0 +1,8 @@
1
+ #! /usr/bin/env python
2
+
3
+ #This allows the user to call libraries directly
4
+
5
+ #For example:
6
+ #from pygeotools import malib
7
+
8
+ #from .lib import *
@@ -0,0 +1,116 @@
1
+ #! /usr/bin/env python
2
+
3
+ #David Shean
4
+ #dshean@gmail.com
5
+
6
+ #Utility to mask input raster using the mask from another raster
7
+ #Mask dataset can be a standard raster with nodata value specified or a binary mask
8
+ #If a binary mask, values should be:
9
+ #True (1) for masked, False (0) for valid - consistent with np.ma
10
+
11
+ import sys, os
12
+ import argparse
13
+
14
+ import numpy as np
15
+ from osgeo import gdal
16
+
17
+ from pygeotools.lib import iolib
18
+ from pygeotools.lib import warplib
19
+
20
+ def getparser():
21
+ parser = argparse.ArgumentParser(description="Apply existing mask to input raster")
22
+ #Should add support for similar arguments as in warplib - arbitrary extent, res, etc
23
+ parser.add_argument('-extent', type=str, default='raster', \
24
+ choices=['raster','mask','intersection','union'], help='Desired output extent')
25
+ parser.add_argument('-invert', action='store_true', help='Invert input mask')
26
+ parser.add_argument('-mask_val', type=float, default=None, \
27
+ help='If input mask_fn is classified raster, specify value to use as mask')
28
+ parser.add_argument('-out_fn', type=str, default=None, help='Output filename')
29
+ parser.add_argument('src_fn', type=str, help='Input raster filename')
30
+ parser.add_argument('mask_fn', type=str, help='Input mask filename (can be existing raster with ndv, or binary mask)')
31
+ return parser
32
+
33
+ def main():
34
+ parser = getparser()
35
+ args = parser.parse_args()
36
+
37
+ src_fn = args.src_fn
38
+ if not iolib.fn_check(src_fn):
39
+ sys.exit("Unable to find src_fn: %s" % src_fn)
40
+
41
+ mask_fn = args.mask_fn
42
+ if not iolib.fn_check(mask_fn):
43
+ sys.exit("Unable to find mask_fn: %s" % mask_fn)
44
+
45
+ #Determine output extent, default is input raster extent
46
+ extent = args.extent
47
+ if extent == 'raster':
48
+ extent = src_fn
49
+ elif extent == 'mask':
50
+ extent = mask_fn
51
+ else:
52
+ #This is a hack for intersection computation
53
+ src_ds_list = [gdal.Open(fn, gdal.GA_ReadOnly) for fn in [src_fn, mask_fn]]
54
+ #t_srs = geolib.get_ds_srs(src_ds_list[0])
55
+ extent = warplib.parse_extent(extent, src_ds_list, src_fn)
56
+
57
+ #Set resampling algorithm appropriately
58
+ r='cubic'
59
+ mask_val=args.mask_val
60
+ if mask_val is not None:
61
+ r='near'
62
+
63
+ print("Warping mask_fn")
64
+ mask_ds = warplib.memwarp_multi_fn([mask_fn,], res=src_fn, extent=extent, t_srs=src_fn, r=r)[0]
65
+
66
+ print("Loading mask array")
67
+ mask_ma_full = iolib.ds_getma(mask_ds)
68
+ mask_ds = None
69
+
70
+ print("Extracting mask")
71
+ if mask_val is not None:
72
+ #Use specified value
73
+ mask = ~((mask_ma_full == mask_val).data)
74
+ elif mask_ma_full.std() != 0:
75
+ #Input mask filename is a raster, or other masked array
76
+ #Just need to extract mask
77
+ mask = np.ma.getmaskarray(mask_ma_full)
78
+ else:
79
+ #Input mask filename is a mask, use directly
80
+ #If input mask values are zero, valid values are nonzero
81
+ #Bool True == 1, so need to invert
82
+ if mask_ma_full.fill_value == 0:
83
+ mask = ~((mask_ma_full.data).astype(bool))
84
+ else:
85
+ mask = (mask_ma_full.data).astype(bool)
86
+
87
+ #Free up memory
88
+ mask_ma_full = None
89
+
90
+ #Add dilation step for buffer
91
+
92
+ #newmask = np.logical_or(np.ma.getmaskarray(src_ma_full), mask)
93
+
94
+ if args.invert:
95
+ print("Inverting mask")
96
+ mask = ~(mask)
97
+
98
+ print("Loading src array and applying updated mask")
99
+ if extent == src_fn:
100
+ src_ds = gdal.Open(src_fn)
101
+ else:
102
+ src_ds = warplib.memwarp_multi_fn([src_fn,], res=src_fn, extent=extent, t_srs=src_fn)[0]
103
+
104
+ #Now load source array with new mask
105
+ src_ma_full = np.ma.array(iolib.ds_getma(src_ds), mask=mask)
106
+ mask = None
107
+
108
+ if args.out_fn is not None:
109
+ src_fn_masked = args.out_fn
110
+ else:
111
+ src_fn_masked = os.path.splitext(src_fn)[0]+'_masked.tif'
112
+ print("Writing out masked version of input raster: %s" % src_fn_masked )
113
+ iolib.writeGTiff(src_ma_full, src_fn_masked, src_ds, create=True)
114
+
115
+ if __name__ == '__main__':
116
+ main()
@@ -0,0 +1,64 @@
1
+ #! /usr/bin/env python
2
+
3
+ #David Shean
4
+ #dshean@gmail.com
5
+
6
+ #Clip input raster to polygons in input shapefile
7
+ #Finally ported clip_raster_by_shp.sh to Python
8
+
9
+ #TODO: Handle same arbitrary res/extent/t_srs as in warplib (isolate/generalize those functions)
10
+
11
+ import os
12
+ import sys
13
+ import argparse
14
+
15
+ import numpy as np
16
+ from osgeo import ogr
17
+
18
+ from pygeotools.lib import iolib
19
+ from pygeotools.lib import geolib
20
+
21
+ def getparser():
22
+ parser = argparse.ArgumentParser(description="Clip input raster by input shp polygons")
23
+ #Should add support for similar arguments as in warplib - arbitrary extent, res, etc
24
+ parser.add_argument('-extent', type=str, default='raster', choices=['raster','shp','intersection','union'],
25
+ help='Desired output extent')
26
+ parser.add_argument('-bbox', action='store_true', help='Clip raster to shp bounding box, but dont mask')
27
+ parser.add_argument('-pad', type=float, default=None, help='Padding around shp extent, in raster units')
28
+ parser.add_argument('-invert', action='store_true', help='Invert the input polygons before clipping')
29
+ parser.add_argument('-out_fn', type=str, default=None, help='Output raster filename (default: *_shpclip.tif)')
30
+ parser.add_argument('r_fn', type=str, help='Input raster filename')
31
+ parser.add_argument('shp_fn', type=str, help='Input shp filename')
32
+ return parser
33
+
34
+ def main():
35
+ parser = getparser()
36
+ args = parser.parse_args()
37
+
38
+ r_fn = args.r_fn
39
+ if not os.path.exists(r_fn):
40
+ sys.exit("Unable to find r_fn: %s" % r_fn)
41
+
42
+ shp_fn = args.shp_fn
43
+ #Convenience shortcut to clip to glacier polygons (global shp)
44
+ #Requires demcoreg package: https://github.com/dshean/demcoreg
45
+ if shp_fn == 'RGI' or shp_fn == 'rgi':
46
+ from demcoreg.dem_mask import get_glacier_poly
47
+ rgi_fn = get_glacier_poly()
48
+ shp_fn = rgi_fn
49
+
50
+ if not os.path.exists(shp_fn):
51
+ sys.exit("Unable to find shp_fn: %s" % shp_fn)
52
+
53
+ #Do the clipping
54
+ r, r_ds = geolib.raster_shpclip(r_fn, shp_fn, extent=args.extent, bbox=args.bbox, pad=args.pad, invert=args.invert)
55
+
56
+ #Write out
57
+ out_fn = args.out_fn
58
+ if out_fn is None:
59
+ out_fn = os.path.splitext(r_fn)[0]+'_shpclip.tif'
60
+ #Note: passing r_fn here as the src_ds
61
+ iolib.writeGTiff(r, out_fn, r_ds)
62
+
63
+ if __name__ == "__main__":
64
+ main()
pygeotools/copyproj.py ADDED
@@ -0,0 +1,9 @@
1
+ #! /usr/bin/env python
2
+
3
+ import sys
4
+ from pygeotools.lib import geolib
5
+
6
+ src_fn = sys.argv[1]
7
+ dst_fn = sys.argv[2]
8
+
9
+ geolib.copyproj(src_fn, dst_fn)
pygeotools/filter.py ADDED
@@ -0,0 +1,143 @@
1
+ #! /usr/bin/env python
2
+ """
3
+ Command-line wrapper around raster filters in filtlib
4
+ """
5
+
6
+ #Note: currently need to specify fn first, as -param accepts arbitrary number of arguments
7
+ #Need better way to record params than in filename - write history to header?
8
+ #Precision on float
9
+
10
+ import sys
11
+ import os
12
+ import argparse
13
+
14
+ import numpy as np
15
+
16
+ from pygeotools.lib import iolib
17
+ from pygeotools.lib import malib
18
+ from pygeotools.lib import filtlib
19
+ from pygeotools.lib import warplib
20
+
21
+ def getparser():
22
+ filter_choices = ['range', 'absrange', 'perc', 'gauss', 'med', 'highpass', 'sigma', 'mad', 'dz']
23
+ parser = argparse.ArgumentParser(description='Filter input raster')
24
+ parser.add_argument('fn', help='Input filename (img1.tif)')
25
+ parser.add_argument('--stats', action='store_true', help='Print stats before and after filtering')
26
+ parser.add_argument('-outdir', default=None, help='Output directory')
27
+ #Should implement subparser here to handle different number of args for different filter types
28
+ #https://docs.python.org/2/library/argparse.html#sub-commands
29
+ #Can call functions directly
30
+ #Could specify sequence of filters here
31
+ #Should accept arbitrary number of ordered filter operations as cli argument
32
+ parser.add_argument('-filt', nargs=1, default='gauss', choices=filter_choices, help='Filter type (default: %(default)s)')
33
+ #size is a param
34
+ #parser.add_argument('-size', type=int, default=7, help='Filter size in pixels (default: %(default)s)')
35
+ parser.add_argument('-param', nargs='+', default=None, help='Filter parameter list (e.g., size, min max, ref_fn min max)')
36
+ return parser
37
+
38
+ def main():
39
+ parser = getparser()
40
+ args = parser.parse_args()
41
+
42
+ fn = args.fn
43
+ if not iolib.fn_check(fn):
44
+ sys.exit("Unable to locate input file: %s" % fn)
45
+
46
+ #Need some checks on these
47
+ param = args.param
48
+
49
+ print("Loading input raster into masked array")
50
+ ds = iolib.fn_getds(fn)
51
+ #Currently supports only single band operations
52
+ r = iolib.ds_getma(ds, 1)
53
+
54
+ #May need to cast input ma as float32 so np.nan filling works
55
+ #r = r.astype(np.float32)
56
+ #Want function that checks and returns float32 if necessary
57
+ #Should filter, then return original dtype
58
+
59
+ r_fltr = r
60
+
61
+ #Loop through all specified input filters
62
+ #for filt in args.filt:
63
+ filt = args.filt[0]
64
+
65
+ if len(param) == 1:
66
+ param = param[0]
67
+ param_str = ''
68
+
69
+ if filt == 'range':
70
+ #Range filter
71
+ param = [float(i) for i in param[1:]]
72
+ r_fltr = filtlib.range_fltr(r_fltr, param)
73
+ param_str = '_{0:0.2f}-{1:0.2f}'.format(*param)
74
+ elif filt == 'absrange':
75
+ #Range filter of absolute values
76
+ param = [float(i) for i in param[1:]]
77
+ r_fltr = filtlib.absrange_fltr(r_fltr, param)
78
+ param_str = '_{0:0.2f}-{1:0.2f}'.format(*param)
79
+ elif filt == 'perc':
80
+ #Percentile filter
81
+ param = [float(i) for i in param[1:]]
82
+ r_fltr = filtlib.perc_fltr(r, perc=param)
83
+ param_str = '_{0:0.2f}-{1:0.2f}'.format(*param)
84
+ elif filt == 'med':
85
+ #Median filter
86
+ param = int(param)
87
+ r_fltr = filtlib.rolling_fltr(r_fltr, f=np.nanmedian, size=param)
88
+ #r_fltr = filtlib.median_fltr(r_fltr, fsize=param, origmask=True)
89
+ #r_fltr = filtlib.median_fltr_skimage(r_fltr, radius=4, origmask=True)
90
+ param_str = '_%ipx' % param
91
+ elif filt == 'gauss':
92
+ #Gaussian filter (default)
93
+ param = int(param)
94
+ r_fltr = filtlib.gauss_fltr_astropy(r_fltr, size=param, origmask=False, fill_interior=False)
95
+ param_str = '_%ipx' % param
96
+ elif filt == 'highpass':
97
+ #High pass filter
98
+ param = int(param)
99
+ r_fltr = filtlib.highpass(r_fltr, size=param)
100
+ param_str = '_%ipx' % param
101
+ elif filt == 'sigma':
102
+ #n*sigma filter, remove outliers
103
+ param = int(param)
104
+ r_fltr = filtlib.sigma_fltr(r_fltr, n=param)
105
+ param_str = '_n%i' % param
106
+ elif filt == 'mad':
107
+ #n*mad filter, remove outliers
108
+ #Maybe better to use a percentile filter
109
+ param = int(param)
110
+ r_fltr = filtlib.mad_fltr(r_fltr, n=param)
111
+ param_str = '_n%i' % param
112
+ elif filt == 'dz':
113
+ #Difference filter, need to specify ref_fn and range
114
+ #Could let the user compute their own dz, then just run a standard range or absrange filter
115
+ ref_fn = param[0]
116
+ ref_ds = warplib.memwarp_multi_fn([ref_fn,], res=ds, extent=ds, t_srs=ds)[0]
117
+ ref = iolib.ds_getma(ref_ds)
118
+ param = [float(i) for i in param[1:]]
119
+ r_fltr = filtlib.dz_fltr_ma(r, ref, rangelim=param)
120
+ #param_str = '_{0:0.2f}-{1:0.2f}'.format(*param)
121
+ param_str = '_{0:0.0f}_{1:0.0f}'.format(*param)
122
+ else:
123
+ sys.exit("No filter type specified")
124
+
125
+ #Compute and print stats before/after
126
+ if args.stats:
127
+ print("Input stats:")
128
+ malib.print_stats(r)
129
+ print("Filtered stats:")
130
+ malib.print_stats(r_fltr)
131
+
132
+ #Write out
133
+ dst_fn = os.path.splitext(fn)[0]+'_%sfilt%s.tif' % (filt, param_str)
134
+ if args.outdir is not None:
135
+ outdir = args.outdir
136
+ if not os.path.exists(outdir):
137
+ os.makedirs(outdir)
138
+ dst_fn = os.path.join(outdir, os.path.split(dst_fn)[-1])
139
+ print("Writing out filtered raster: %s" % dst_fn)
140
+ iolib.writeGTiff(r_fltr, dst_fn, ds)
141
+
142
+ if __name__ == '__main__':
143
+ main()
@@ -0,0 +1,3 @@
1
+ #! /usr/bin/env python
2
+
3
+ __all__=['geolib','malib','timelib','warplib','iolib','filtlib']