#dem1_fwd_obs = np.ma.empty_like(dem1) #dem1_fwd_obs[fwd_idx] = dem2[disp_y_abs_fwd.compressed(),disp_x_abs_fwd.compressed()] #Extract values from dem2 for new positions dem1_fwd_obs = dem2[np.ma.filled(disp_y_abs_fwd, 0), np.ma.filled(disp_x_abs_fwd, 0)] dem1_fwd_obs = np.ma.masked_equal(dem1_fwd_obs, dem2.fill_value) #This is necessary b/c we are filling index arrays with 0, so existing nodata pixels will have valid values #NOTE: this was changed on 9/25/15 due to error in the Jak datset, but it didn't cause problems with earlier PIG data disp_m = np.percentile(np.sqrt(disp_x**2 + disp_y**2), 98) #disp_m = 59 disp_m = 29 dem1_smooth = filtlib.gauss_fltr_astropy(dem1, 2 * disp_m) dem2_smooth = filtlib.gauss_fltr_astropy(dem2, 2 * disp_m) #dem1_fwd_obs.mask[:] = disp_x_abs_fwd.mask dem1_fwd_obs = np.ma.array(dem1_fwd_obs, mask=disp_x_abs_fwd.mask) #Expected elevation values assuming steady-state advection along dem1 surface #dem1_fwd_exp = dem1[np.ma.filled(disp_y_abs_fwd,0),np.ma.filled(disp_x_abs_fwd,0)] dem1_fwd_exp = dem1_smooth[np.ma.filled(disp_y_abs_fwd, 0), np.ma.filled(disp_x_abs_fwd, 0)] dem1_fwd_exp = np.ma.masked_equal(dem1_fwd_exp, dem1.fill_value) #dem1_fwd_exp.mask[:] = disp_x_abs_fwd.mask dem1_fwd_exp = np.ma.array(dem1_fwd_exp, mask=disp_x_abs_fwd.mask) #This stores indices for expected feature locations in dem1 disp_x_abs_inv = np.ma.masked_outside(idx[1] - disp_x, 0, dem1.shape[1] - 1)
def warp(src_ds, res=None, extent=None, t_srs=None, r='cubic', driver=mem_drv, dst_fn=None, dst_ndv=None, verbose=True): """Warp an input dataset with predetermined arguments specifying output res/extent/srs This is the function that actually calls gdal.ReprojectImage Parameters ---------- src_ds : gdal.Dataset object Dataset to be warped res : float Desired output resolution extent : list of float Desired output extent in t_srs coordinate system t_srs : osr.SpatialReference() Desired output spatial reference r : str Desired resampling algorithm driver : GDAL Driver to use for warp Either MEM or GTiff dst_fn : str Output filename (for disk warp) dst_ndv : float Desired output NoData Value Returns ------- dst_ds : gdal.Dataset object Warped dataset (either in memory or on disk) """ src_srs = geolib.get_ds_srs(src_ds) if t_srs is None: t_srs = geolib.get_ds_srs(src_ds) src_gt = src_ds.GetGeoTransform() #Note: get_res returns [x_res, y_res] #Could just use gt here and average x_res and y_res src_res = geolib.get_res(src_ds, t_srs=t_srs, square=True)[0] if res is None: res = src_res if extent is None: extent = geolib.ds_geom_extent(src_ds, t_srs=t_srs) #Note: GDAL Lanczos creates block artifacts #Wait for gdalwarp to support gaussian resampling #Want to use Lanczos for downsampling #if src_res < res: # gra = gdal.GRA_Lanczos #See http://blog.codinghorror.com/better-image-resizing/ # Suggests cubic for downsampling, bilinear for upsampling # gra = gdal.GRA_Cubic #Cubic for upsampling #elif src_res >= res: # gra = gdal.GRA_Bilinear gra = parse_rs_alg(r) #At this point, the resolution and extent values must be float #Extent must be list res = float(res) extent = [float(i) for i in extent] #Might want to move this to memwarp_multi, keep memwarp basic w/ gdal.GRA types #Create progress function prog_func = None if verbose: prog_func = gdal.TermProgress if dst_fn is None: #This is a dummy fn if only in mem, but can be accessed later via GetFileList() #Actually, no, doesn't look like the filename survivies dst_fn = '' #Compute output image dimensions dst_nl = int(round((extent[3] - extent[1])/res)) dst_ns = int(round((extent[2] - extent[0])/res)) #dst_nl = int(math.ceil((extent[3] - extent[1])/res)) #dst_ns = int(math.ceil((extent[2] - extent[0])/res)) #dst_nl = int(math.floor((extent[3] - extent[1])/res)) #dst_ns = int(math.floor((extent[2] - extent[0])/res)) if verbose: print('nl: %i ns: %i res: %0.3f' % (dst_nl, dst_ns, res)) #Create output dataset src_b = src_ds.GetRasterBand(1) src_dt = src_b.DataType src_nl = src_ds.RasterYSize src_ns = src_ds.RasterXSize dst_ds = driver.Create(dst_fn, dst_ns, dst_nl, src_ds.RasterCount, src_dt) dst_ds.SetProjection(t_srs.ExportToWkt()) #Might be an issue to use src_gt rotation terms here with arbitrary extent/res dst_gt = [extent[0], res, src_gt[2], extent[3], src_gt[4], -res] dst_ds.SetGeoTransform(dst_gt) #This will smooth the input before downsampling to prevent aliasing, fill gaps #Pretty inefficent, as we need to create another intermediate dataset gauss = False for n in range(1, src_ds.RasterCount+1): if dst_ndv is None: src_b = src_ds.GetRasterBand(n) src_ndv = iolib.get_ndv_b(src_b) dst_ndv = src_ndv b = dst_ds.GetRasterBand(n) b.SetNoDataValue(dst_ndv) b.Fill(dst_ndv) if gauss: from pygeotools.lib import filtlib #src_a = src_b.GetVirtualMemArray() #Compute resampling ratio to determine filter window size res_ratio = float(res)/src_res if verbose: print("Resampling factor: %0.3f" % res_ratio) #Might be more efficient to do iterative gauss filter with size 3, rather than larger windows f_size = math.floor(res_ratio/2.)*2+1 #This is conservative to avoid filling holes with noise #f_size = math.floor(res_ratio/2.)*2-1 if f_size <= 1: continue if verbose: print("Smoothing window size: %i" % f_size) #Create temp dataset to store filtered array - avoid overwriting original temp_ds = driver.Create('', src_ns, src_nl, src_ds.RasterCount, src_dt) temp_ds.SetProjection(src_srs.ExportToWkt()) temp_ds.SetGeoTransform(src_gt) temp_b = temp_ds.GetRasterBand(n) temp_b.SetNoDataValue(dst_ndv) temp_b.Fill(dst_ndv) src_a = iolib.b_getma(src_b) src_a = filtlib.gauss_fltr_astropy(src_a, size=f_size) #Want to run with maskfill, so only fills gaps, without expanding isolated points temp_b.WriteArray(src_a) src_ds = temp_ds #In theory, NN should be fine since we already smoothed. In practice, cubic still provides slightly better results #gra = gdal.GRA_NearestNeighbour """ if not verbose: #Suppress GDAL progress bar orig_stdout = sys.stdout sys.stdout = open(os.devnull, 'w') """ #Note: default maxerror=0.0, second 0.0 argument gdal.ReprojectImage(src_ds, dst_ds, src_srs.ExportToWkt(), t_srs.ExportToWkt(), gra, 0.0, 0.0, prog_func) """ if not verbose: sys.stdout.close() sys.stdout = orig_stdout """ #Note: this is now done in diskwarp #Write out to disk #if driver != mem_drv: # dst_ds.FlushCache() #Return GDAL dataset object in memory return dst_ds
def main(): parser = getparser() args = parser.parse_args() fn = args.fn if not iolib.fn_check(fn): sys.exit("Unable to locate input file: %s" % fn) #Need some checks on these param = args.param print("Loading input raster into masked array") ds = iolib.fn_getds(fn) #Currently supports only single band operations r = iolib.ds_getma(ds, 1) #May need to cast input ma as float32 so np.nan filling works #r = r.astype(np.float32) #Want function that checks and returns float32 if necessary #Should filter, then return original dtype r_fltr = r #Loop through all specified input filters #for filt in args.filt: filt = args.filt[0] if len(param) == 1: param = param[0] param_str = '' if filt == 'range': #Range filter param = [float(i) for i in param[1:]] r_fltr = filtlib.range_fltr(r_fltr, param) param_str = '_{0:0.2f}-{1:0.2f}'.format(*param) elif filt == 'absrange': #Range filter of absolute values param = [float(i) for i in param[1:]] r_fltr = filtlib.absrange_fltr(r_fltr, param) param_str = '_{0:0.2f}-{1:0.2f}'.format(*param) elif filt == 'perc': #Percentile filter param = [float(i) for i in param[1:]] r_fltr = filtlib.perc_fltr(r, perc=param) param_str = '_{0:0.2f}-{1:0.2f}'.format(*param) elif filt == 'med': #Median filter param = int(param) r_fltr = filtlib.rolling_fltr(r_fltr, f=np.nanmedian, size=param) #r_fltr = filtlib.median_fltr(r_fltr, fsize=param, origmask=True) #r_fltr = filtlib.median_fltr_skimage(r_fltr, radius=4, origmask=True) param_str = '_%ipx' % param elif filt == 'gauss': #Gaussian filter (default) param = int(param) r_fltr = filtlib.gauss_fltr_astropy(r_fltr, size=param, origmask=False, fill_interior=False) param_str = '_%ipx' % param elif filt == 'highpass': #High pass filter param = int(param) r_fltr = filtlib.highpass(r_fltr, size=param) param_str = '_%ipx' % param elif filt == 'sigma': #n*sigma filter, remove outliers param = int(param) r_fltr = filtlib.sigma_fltr(r_fltr, n=param) param_str = '_n%i' % param elif filt == 'mad': #n*mad filter, remove outliers #Maybe better to use a percentile filter param = int(param) r_fltr = filtlib.mad_fltr(r_fltr, n=param) param_str = '_n%i' % param elif filt == 'dz': #Difference filter, need to specify ref_fn and range #Could let the user compute their own dz, then just run a standard range or absrange filter ref_fn = param[0] ref_ds = warplib.memwarp_multi_fn([ ref_fn, ], res=ds, extent=ds, t_srs=ds)[0] ref = iolib.ds_getma(ref_ds) param = [float(i) for i in param[1:]] r_fltr = filtlib.dz_fltr_ma(r, ref, rangelim=param) #param_str = '_{0:0.2f}-{1:0.2f}'.format(*param) param_str = '_{0:0.0f}_{1:0.0f}'.format(*param) else: sys.exit("No filter type specified") #Compute and print stats before/after if args.stats: print("Input stats:") malib.print_stats(r) print("Filtered stats:") malib.print_stats(r_fltr) #Write out dst_fn = os.path.splitext(fn)[0] + '_%sfilt%s.tif' % (filt, param_str) if args.outdir is not None: outdir = args.outdir if not os.path.exists(outdir): os.makedirs(outdir) dst_fn = os.path.join(outdir, os.path.split(dst_fn)[-1]) print("Writing out filtered raster: %s" % dst_fn) iolib.writeGTiff(r_fltr, dst_fn, ds)
#Attempt to extract from nearby SNOTEL sites for dem_ts #Attempt to use model #Last resort, use constant value rho_s = 0.5 #rho_s = 0.4 #rho_s = 0.36 #Convert snow depth to swe swe = dz * rho_s if args.filter: print("Filtering SWE map") #Median filter to remove artifacts swe_f = filtlib.rolling_fltr(swe, size=5) #Gaussian filter to smooth over gaps swe_f = filtlib.gauss_fltr_astropy(swe, size=9) swe = swe_f swe_clim = list(malib.calcperc(swe, (1,99))) swe_clim[0] = 0 swe_clim = (0, 8) prism = None nax = 2 figsize = (8, 4) if args.prism: #This is PRISM 30-year normal winter PRECIP prism_fn = '/Users/dshean/data/PRISM_ppt_30yr_normal_800mM2_10-05_winter_cum.tif' if os.path.exists(prism_fn): prism_ds = warplib.memwarp_multi_fn([prism_fn,], extent=dem1_ds, res=dem1_ds, t_srs=dem1_ds, r='cubicspline')[0] #Values are mm, convert to meters
def main(): parser = getparser() args = parser.parse_args() if args.seedmode == 'existing_velocity': if args.vx_fn is None or args.vy_fn is None: parser.error('"-seedmode existing_velocity" requires "-vx_fn" and "-vy_fn"') print('\n%s' % datetime.now()) print('%s UTC\n' % datetime.utcnow()) align = args.align seedmode = args.seedmode spr = args.refinement erode = args.erode #Correlator tile timeout #With proper seeding, correlation should be very fast #timeout = 360 timeout = 1200 threads = args.threads kernel = (args.kernel, args.kernel) #SGM correlator if spr > 3: #kernel = (7,7) kernel = (11,11) erode = 0 #Smooth the output F.tif smoothF = args.filter res = args.tr #Resample input to something easier to work with #res = 4.0 #Open input files fn1 = args.fn1 fn2 = args.fn2 if not iolib.fn_check(fn1) or not iolib.fn_check(fn2): sys.exit("Unable to locate input files") if args.outdir is not None: outdir = args.outdir else: outdir = '%s__%s_vmap_%sm_%ipx_spm%i' % (os.path.splitext(os.path.split(fn1)[1])[0], \ os.path.splitext(os.path.split(fn2)[1])[0], res, kernel[0], spr) #Note, can encounter filename length issues in boost, just use vmap prefix outprefix = '%s/vmap' % (outdir) if not os.path.exists(outdir): os.makedirs(outdir) #Check to see if inputs have geolocation and projection information ds1 = iolib.fn_getds(fn1) ds2 = iolib.fn_getds(fn2) if geolib.srs_check(ds1) and geolib.srs_check(ds2): ds1_clip_fn = os.path.join(outdir, os.path.splitext(os.path.basename(fn1))[0]+'_warp.tif') ds2_clip_fn = os.path.join(outdir, os.path.splitext(os.path.basename(fn2))[0]+'_warp.tif') if not os.path.exists(ds1_clip_fn) or not os.path.exists(ds2_clip_fn): #This should write out files to new subdir ds1_clip, ds2_clip = warplib.diskwarp_multi_fn([fn1, fn2], extent='intersection', res=res, r='average', outdir=outdir) ds1_clip = None ds2_clip = None #However, if inputs have identical extent/res/proj, then link to original files if not os.path.exists(ds1_clip_fn): os.symlink(os.path.abspath(fn1), ds1_clip_fn) if not os.path.exists(ds2_clip_fn): os.symlink(os.path.abspath(fn2), ds2_clip_fn) align = 'None' #Mask support - limit correlation only to rock/ice surfaces, no water/veg #This masks input images - guarantee we won't waste time correlating over vegetation #TODO: Add support to load arbitrary raster or shp mask if args.mask_input: ds1_masked_fn = os.path.splitext(ds1_clip_fn)[0]+'_masked.tif' ds2_masked_fn = os.path.splitext(ds2_clip_fn)[0]+'_masked.tif' if not os.path.exists(ds1_masked_fn) or not os.path.exists(ds2_masked_fn): #Load NLCD or bareground mask from demcoreg.dem_mask import get_lulc_mask ds1_clip = iolib.fn_getds(ds1_clip_fn) lulc_mask_fn = os.path.join(outdir, 'lulc_mask.tif') #if not os.path.exists(nlcd_mask_fn): lulc_mask = get_lulc_mask(ds1_clip, mask_glaciers=False, filter='not_forest') iolib.writeGTiff(lulc_mask, lulc_mask_fn, ds1_clip) ds1_clip = None #Now apply to original images #This could be problematic for huge inputs, see apply_mask.py #lulc_mask = lulc_mask.astype(int) for fn in (ds1_clip_fn, ds2_clip_fn): ds = iolib.fn_getds(fn) a = iolib.ds_getma(ds) a = np.ma.array(a, mask=~(lulc_mask)) if a.count() > 0: out_fn = os.path.splitext(fn)[0]+'_masked.tif' iolib.writeGTiff(a,out_fn,ds) a = None else: sys.exit("No unmasked pixels over bare earth") ds1_clip_fn = ds1_masked_fn ds2_clip_fn = ds2_masked_fn else: ds1_clip_fn = fn1 ds2_clip_fn = fn2 #Now let user specify alignment methods as option - don't hardcode #align = 'Homography' #align = 'AffineEpipolar' ds1 = None ds2 = None #Should have extra kwargs option here stereo_opt = get_stereo_opt(threads=threads, kernel=kernel, timeout=timeout, \ erode=erode, spr=spr, align=align) #Stereo arguments #Latest version of ASP should accept tif without camera models #stereo_args = [ds1_clip_fn, ds2_clip_fn, outprefix] #Nope - still need to provide dummy camera models, and they must be unique files #Use the dummy.tsai file bundled in the vmap repo dummy_tsai = os.path.join(os.path.split(os.path.realpath(__file__))[0], 'dummy.tsai') dummy_tsai2 = os.path.splitext(dummy_tsai)[0]+'2.tsai' if not os.path.exists(dummy_tsai2): dummy_tsai2 = os.symlink(dummy_tsai, os.path.splitext(dummy_tsai)[0]+'2.tsai') stereo_args = [ds1_clip_fn, ds2_clip_fn, dummy_tsai, dummy_tsai2, outprefix] #Run stereo_pprc if not os.path.exists(outprefix+'-R_sub.tif'): run_cmd('stereo_pprc', stereo_opt+stereo_args, msg='0: Preprocessing') #Copy proj info to outputs, this should happen automatically now? for ext in ('L', 'R', 'L_sub', 'R_sub', 'lMask', 'rMask', 'lMask_sub', 'rMask_sub'): geolib.copyproj(ds1_clip_fn, '%s-%s.tif' % (outprefix,ext)) #Prepare seeding for stereo_corr #TODO: these are untested after refactoring if not os.path.exists(outprefix+'_D_sub.tif'): #Don't need to do anything for default seed-mode 1 if seedmode == 'sparse_disp': #Sparse correlation of full-res images stereo_opt.extend(['--corr-seed-mode', '3']) sparse_disp_opt = [] sparse_disp_opt.extend(['--Debug', '--coarse', '512', '--fine', '256', '--no_epipolar_fltr']) sparse_disp_opt.extend(['-P', str(threads)]) sparse_disp_args = [outprefix+'-L.tif', outprefix+'-R.tif', outprefix] run_cmd('sparse_disp', sparse_disp_opt+sparse_disp_args, msg='0.5: D_sub generation') elif seedmode == 'existing_velocity': #User-input low-res velocity maps for seeding #TODO: Add functions that fetch best available velocities for Ant/GrIS or user-defined low-res velocities #Automatically query GoLive velocities here vx_fn = args.vx_fn vy_fn = args.vy_fn #Check for existence #HMA seeding vdir = '/nobackup/deshean/rpcdem/hma/velocity_jpl_amaury_2013-2015' vx_fn = os.path.join(vdir, 'PKH_WRS2_B8_2013_2015_snr5_n1_r170_res12.x_vel.TIF') vy_fn = os.path.join(vdir, 'PKH_WRS2_B8_2013_2015_snr5_n1_r170_res12.y_vel.TIF') if os.path.exists(vx_fn) and os.path.exists(vy_fn): ds1_clip = iolib.fn_getds(ds1_clip_fn) ds1_res = geolib.get_res(ds1_clip, square=True)[0] #Compute L_sub res - use this for output dimensions L_sub_fn = outprefix+'-L_sub.tif' L_sub_ds = gdal.Open(L_sub_fn) L_sub_x_scale = float(ds1_clip.RasterXSize) / L_sub_ds.RasterXSize L_sub_y_scale = float(ds1_clip.RasterYSize) / L_sub_ds.RasterYSize L_sub_scale = np.max([L_sub_x_scale, L_sub_y_scale]) L_sub_res = ds1_res * L_sub_scale #Since we are likely upsampling here, use cubicspline vx_ds_clip, vy_ds_clip = warplib.memwarp_multi_fn([vx_fn, vy_fn], extent=ds1_clip, \ t_srs=ds1_clip, res=L_sub_res, r='cubicspline') ds1_clip = None #Get vx and vy arrays vx = iolib.ds_getma(vx_ds_clip) vy = iolib.ds_getma(vy_ds_clip) #Determine time interval between inputs #Use to scaling of known low-res velocities t_factor = get_t_factor_fn(ds1_clip_fn, ds2_clip_fn, ds=vx_ds_clip) if t_factor is not None: #Compute expected offset in scaled pixels dx = (vx*t_factor)/L_sub_res dy = (vy*t_factor)/L_sub_res #Note: Joughin and Rignot's values are positive y up! #ASP is positive y down, so need to multiply these values by -1 #dy = -(vy*t_factor)/L_sub_res #Should smooth/fill dx and dy #If absolute search window is only 30x30 #Don't seed, just use fixed search window #search_window_area_thresh = 900 search_window_area_thresh = 0 search_window = np.array([dx.min(), dy.min(), dx.max(), dy.max()]) dx_p = calcperc(dx, perc=(0.5, 99.5)) dy_p = calcperc(dy, perc=(0.5, 99.5)) search_window = np.array([dx_p[0], dy_p[0], dx_p[1], dy_p[1]]) search_window_area = (search_window[2]-search_window[0]) * (search_window[3]-search_window[1]) if search_window_area < search_window_area_thresh: stereo_opt.extend(['--corr-seed-mode', '0']) stereo_opt.append('--corr-search') stereo_opt.extend([str(x) for x in search_window]) #pad_perc=0.1 #stereo_opt.extend(['--corr-sub-seed-percent', str(pad_perc)] #Otherwise, generate a D_sub map from low-res velocity else: stereo_opt.extend(['--corr-seed-mode', '3']) #This is relative to the D_sub scaled disparities d_sub_fn = L_sub_fn.split('-L_sub')[0]+'-D_sub.tif' gen_d_sub(d_sub_fn, dx, dy) #If the above didn't generate a D_sub.tif for seeding, run stereo_corr to generate Low-res D_sub.tif if not os.path.exists(outprefix+'-D_sub.tif'): newopt = ['--compute-low-res-disparity-only',] run_cmd('stereo_corr', newopt+stereo_opt+stereo_args, msg='1.1: Low-res Correlation') #Copy projection info to D_sub geolib.copyproj(outprefix+'-L_sub.tif', outprefix+'-D_sub.tif') #Mask D_sub to limit correlation over bare earth surfaces #This _should_ be a better approach than masking input images, but stereo_corr doesn't honor D_sub #Still need to mask input images before stereo_pprc #Left this in here for reference, or if this changes in ASP if False: D_sub_ds = gdal.Open(outprefix+'-D_sub.tif', gdal.GA_Update) #Mask support - limit correlation only to rock/ice surfaces, no water/veg from demcoreg.dem_mask import get_nlcd, mask_nlcd nlcd_fn = get_nlcd() nlcd_ds = warplib.diskwarp_multi_fn([nlcd_fn,], extent=D_sub_ds, res=D_sub_ds, t_srs=D_sub_ds, r='near', outdir=outdir)[0] #validmask = mask_nlcd(nlcd_ds, valid='rock+ice') validmask = mask_nlcd(nlcd_ds, valid='not_forest', mask_glaciers=False) nlcd_mask_fn = os.path.join(outdir, 'nlcd_validmask.tif') iolib.writeGTiff(validmask, nlcd_mask_fn, nlcd_ds) #Now apply to D_sub (band 3 is valid mask) #validmask = validmask.astype(int) for b in (1,2,3): dsub = iolib.ds_getma(D_sub_ds, b) dsub = np.ma.array(dsub, mask=~(validmask)) D_sub_ds.GetRasterBand(b).WriteArray(dsub.filled()) D_sub_ds = None #OK, finally run stereo_corr full-res integer correlation with appropriate seeding if not os.path.exists(outprefix+'-D.tif'): run_cmd('stereo_corr', stereo_opt+stereo_args, msg='1: Correlation') geolib.copyproj(ds1_clip_fn, outprefix+'-D.tif') #Run stereo_rfne if spr > 0: if not os.path.exists(outprefix+'-RD.tif'): run_cmd('stereo_rfne', stereo_opt+stereo_args, msg='2: Refinement') geolib.copyproj(ds1_clip_fn, outprefix+'-RD.tif') d_fn = make_ln(outdir, outprefix, '-RD.tif') else: ln_fn = outprefix+'-RD.tif' if os.path.lexists(ln_fn): os.remove(ln_fn) os.symlink(os.path.split(outprefix)[1]+'-D.tif', ln_fn) #Run stereo_fltr if not os.path.exists(outprefix+'-F.tif'): run_cmd('stereo_fltr', stereo_opt+stereo_args, msg='3: Filtering') geolib.copyproj(ds1_clip_fn, outprefix+'-F.tif') d_fn = make_ln(outdir, outprefix, '-F.tif') if smoothF and not os.path.exists(outprefix+'-F_smooth.tif'): print('Smoothing F.tif') from pygeotools.lib import filtlib #Fill holes and smooth F F_fill_fn = outprefix+'-F_smooth.tif' F_ds = gdal.Open(outprefix+'-F.tif', gdal.GA_ReadOnly) #import dem_downsample_fill #F_fill_ds = dem_downsample_fill.gdalfill_ds(F_fill_ds) print('Creating F_smooth.tif') F_fill_ds = iolib.gtif_drv.CreateCopy(F_fill_fn, F_ds, 0, options=iolib.gdal_opt) F_ds = None for n in (1, 2): print('Smoothing band %i' % n) b = F_fill_ds.GetRasterBand(n) b_fill_bma = iolib.b_getma(b) #b_fill_bma = iolib.b_getma(dem_downsample_fill.gdalfill(b)) #Filter extreme values (careful, could lose areas of valid data with fastest v) #b_fill_bma = filtlib.perc_fltr(b_fill_bma, perc=(0.01, 99.99)) #These filters remove extreme values and fill data gaps #b_fill_bma = filtlib.median_fltr_skimage(b_fill_bma, radius=7, erode=0) #b_fill_bma = filtlib.median_fltr(b_fill_bma, fsize=7, origmask=True) #Gaussian filter b_fill_bma = filtlib.gauss_fltr_astropy(b_fill_bma, size=9) b.WriteArray(b_fill_bma) F_fill_ds = None d_fn = make_ln(outdir, outprefix, '-F_smooth.tif') print('\n%s' % datetime.now()) print('%s UTC\n' % datetime.utcnow()) #If time interval is specified, convert pixel displacements to rates if args.dt != 'none': #Check if vm.tif already exists #Should probably just overwrite by default #if os.path.exists(os.path.splitext(d_fn)[0]+'_vm.tif'): # print("\nFound existing velocity magnitude map!\n" #else: #Generate output velocity products and figure #Requires that vmap repo is in PATH cmd = ['disp2v.py', d_fn] #Note: this will attempt to automatically determine control surfaces #disp2v.py will accept arbitrary mask, could pass through here if args.remove_offsets: cmd.append('-remove_offsets') cmd.extend(['-dt', args.dt]) print("Converting disparities to velocities") print(cmd) subprocess.call(cmd)
#trend_filt = filtlib.sigma_fltr(trend, n=3) #print("Output pixel count: %s" % trend_filt.count()) #Remove islands #trend_filt = filtlib.remove_islands(trend, iterations=1) #Erode edges near nodata trend_filt = filtlib.erode_edge(trend, iterations=1) print("Output pixel count: %s" % trend_filt.count()) #Rolling median filter (remove noise) - can use a slightly larger window here trend_filt = filtlib.rolling_fltr(trend_filt, size=size, circular=True, origmask=True) print("Output pixel count: %s" % trend_filt.count()) #Gaussian filter (smooth) #trend_filt = filtlib.gauss_fltr_astropy(trend_filt, size=size, origmask=True, fill_interior=True) trend_filt = filtlib.gauss_fltr_astropy(trend_filt, size=size) print("Output pixel count: %s" % trend_filt.count()) trend_fn=out_fn+'_trend_%spx_filt.tif' % size print("Writing out: %s" % trend_fn) iolib.writeGTiff(trend_filt*365.25, trend_fn, trend_ds) #Update intercept using new filtered slope values #Need to update for different periods? #dt_pivot = timelib.mean_date(datetime(2000,5,31), datetime(2009,5,31)) #dt_pivot = timelib.mean_date(datetime(2009,5,31), datetime(2018,5,31)) dt_pivot = timelib.dt2o(datetime(2009, 5, 31)) intercept_filt = dt_pivot * (trend - trend_filt) + intercept intercept_fn=out_fn+'_intercept_%spx_filt.tif' % size print("Writing out: %s" % intercept_fn) iolib.writeGTiff(intercept_filt*365.25, intercept_fn, trend_ds)
def main(): #This is defualt filter size (pixels) size = 19 #Compute and print stats before/after stats = False #Need to clean up with argparse #Accept filter list, filter size as argument if len(sys.argv) == 2: dem_fn = sys.argv[1] elif len(sys.argv) == 3: dem_fn = sys.argv[1] size = int(sys.argv[2]) else: sys.exit("Usage is %s dem [size]" % sys.argv[0]) print("Loading DEM into masked array") dem_ds = iolib.fn_getds(dem_fn) dem = iolib.ds_getma(dem_ds, 1) #Cast input ma as float32 so np.nan filling works #dem = dem.astype(np.float32) dem_fltr = dem #Should accept arbitrary number of ordered filter operations as cli argument #filt_list = ['gauss_fltr_astropy',] #for filt in filt_list: # dem_fltr = filtlib.filt(dem_fltr, size=size, kwargs) #Percentile filter #dem_fltr = filtlib.perc_fltr(dem, perc=(15.865, 84.135)) #dem_fltr = filtlib.perc_fltr(dem, perc=(2.275, 97.725)) #dem_fltr = filtlib.perc_fltr(dem, perc=(0.135, 99.865)) #dem_fltr = filtlib.perc_fltr(dem, perc=(0, 99.73)) #dem_fltr = filtlib.perc_fltr(dem, perc=(0, 95.45)) #dem_fltr = filtlib.perc_fltr(dem, perc=(0, 68.27)) #Difference filter, need to specify refdem_fn #dem_fltr = filtlib.dz_fltr(dem_fn, refdem_fn, abs_dz_lim=(0,30)) #Absolute range filter #dem_fltr = filtlib.range_fltr(dem_fltr, (15, 9999)) #Median filter #dem_fltr = filtlib.rolling_fltr(dem_fltr, f=np.nanmedian, size=size) #dem_fltr = filtlib.median_fltr(dem_fltr, fsize=size, origmask=True) #dem_fltr = filtlib.median_fltr_skimage(dem_fltr, radius=4, origmask=True) #High pass filter #dem_fltr = filtlib.highpass(dem_fltr, size=size) #Gaussian filter (default) dem_fltr = filtlib.gauss_fltr_astropy(dem_fltr, size=size, origmask=True, fill_interior=False) if stats: print("Input DEM stats:") malib.print_stats(dem) print("Filtered DEM stats:") malib.print_stats(dem_fltr) dst_fn = os.path.splitext(dem_fn)[0]+'_filt%ipx.tif' % size print("Writing out filtered DEM: %s" % dst_fn) #Note: writeGTiff writes dem_fltr.filled() iolib.writeGTiff(dem_fltr, dst_fn, dem_ds)