def raster_shpclip(r_fn, shp_fn, extent='raster'): r_ds = iolib.fn_getds(r_fn) r_srs = geolib.get_ds_srs(r_ds) r_extent = geolib.ds_extent(r_ds) shp_ds = ogr.Open(shp_fn) lyr = shp_ds.GetLayer() shp_srs = lyr.GetSpatialRef() shp_extent = lyr.GetExtent() #Define the output - can set to either raster or shp #Accept as cl arg out_srs = r_srs if extent == 'raster': out_extent = r_extent elif extent == 'shp': out_extent = shp_extent #r = iolib.ds_getma(r_ds) r_ds = warplib.memwarp(r_ds, extent=out_extent, t_srs=out_srs, r='cubic') r = iolib.ds_getma(r_ds) mask = geolib.shp2array(shp_fn, r_ds) r = np.ma.array(r, mask=mask) return r
def scale_ticks(ax, ds, latlon=False): gt = ds.GetGeoTransform() if gt != (0.0, 1.0, 0.0, 0.0, 0.0, 1.0): x_ticks = np.array(ax.get_xticks()) #x_tick_labels = np.around(gt[0]+x_ticks*gt[1], decimals=-1).astype(int) x_tick_labels = np.around(gt[0] + x_ticks * gt[1]).astype(int) y_ticks = np.array(ax.get_yticks()) #y_tick_labels = np.around(gt[3]+y_ticks*gt[5], decimals=-1).astype(int) y_tick_labels = np.around(gt[3] + y_ticks * gt[5]).astype(int) ax.set_xlabel('X coord (meters)') ax.set_ylabel('Y coord (meters)') if latlon: #Want to automatically determine number of decimals based on extent here srs = geolib.get_ds_srs(ds) ct = osr.CoordinateTransformation(srs, geolib.wgs_srs) lbl = np.array( ct.TransformPoints(zip(x_tick_labels, y_tick_labels))) x_tick_labels = np.round(lbl[:, 0], decimals=3) x_tick_labels = ['%.3f' % a for a in x_tick_labels] y_tick_labels = np.round(lbl[:, 1], decimals=3) y_tick_labels = ['%.3f' % a for a in y_tick_labels] ax.set_xlabel('Longitude') ax.set_ylabel('Latitude') ax.set_xticklabels(x_tick_labels, size='8') ax.set_yticklabels(y_tick_labels, size='8')
def parse_srs(t_srs, src_ds_list=None): """Parse arbitrary input t_srs Parameters ---------- t_srs : str or gdal.Dataset or filename Arbitrary input t_srs src_ds_list : list of gdal.Dataset objects, optional Needed if specifying 'first' or 'last' Returns ------- t_srs : osr.SpatialReference() object Output spatial reference system """ if t_srs is None and src_ds_list is None: print("Input t_srs and src_ds_list are both None") else: if t_srs is None: t_srs = 'first' if t_srs == 'first' and src_ds_list is not None: t_srs = geolib.get_ds_srs(src_ds_list[0]) elif t_srs == 'last' and src_ds_list is not None: t_srs = geolib.get_ds_srs(src_ds_list[-1]) elif t_srs == 'source' and src_ds_list is not None: #Assume ds to be warped is first in ds_list t_srs = geolib.get_ds_srs(src_ds_list[0]) elif isinstance(t_srs, osr.SpatialReference): pass elif isinstance(t_srs, gdal.Dataset): t_srs = geolib.get_ds_srs(t_srs) elif isinstance(t_srs, str) and os.path.exists(t_srs): t_srs = geolib.get_ds_srs(gdal.Open(t_srs)) elif isinstance(t_srs, str): temp = osr.SpatialReference() if 'EPSG' in t_srs.upper(): epsgcode = int(t_srs.split(':')[-1]) temp.ImportFromEPSG(epsgcode) elif 'proj' in t_srs: temp.ImportFromProj4(t_srs) else: #Assume the user knows what they are doing temp.ImportFromWkt(t_srs) t_srs = temp else: t_srs = None return t_srs
def site_filter_extent_ds(ds, pad=None): """ Filter available sites for a given dataset """ snotel_srs = geolib.wgs_srs ds_srs = geolib.get_ds_srs(ds) extent = geolib.ds_extent(ds) #extent = geolib.ds_extent(ds, snotel_srs) #geom = geolib.get_outline(ds) return site_filter_extent(extent, ds_srs, pad)
def shift_ll2proj(fn, llz): from osgeo import gdal, osr from pygeotools.lib import geolib ds = gdal.Open(fn) s_srs = geolib.wgs_srs t_srs = geolib.get_ds_srs(ds) shift = None if t_srs is not None and not s_srs.IsSame(t_srs): #center is lon, lat #llz is lat, lon c = geolib.get_center(ds, t_srs=s_srs) c_shift = [c[0]+llz[1], c[1]+llz[0]] ct = osr.CoordinateTransformation(s_srs, t_srs) c_proj = list(ct.TransformPoint(*c)[0:2]) c_shift_proj = list(ct.TransformPoint(*c_shift)[0:2]) shift = list([c_shift_proj[0] - c_proj[0], c_shift_proj[1] - c_proj[1]]) shift.append(llz[2]) return shift
def get_raster_idx(x_vect, y_vect, pt_srs, ras_ds, max_slope=20): """Get raster index corresponding to the set of X,Y locations """ #Convert input xy coordinates to raster coordinates mX_fltr, mY_fltr, mZ = geolib.cT_helper(x_vect, y_vect, 0, pt_srs, geolib.get_ds_srs(ras_ds)) pX_fltr, pY_fltr = geolib.mapToPixel(mX_fltr, mY_fltr, ras_ds.GetGeoTransform()) pX_fltr = np.atleast_1d(pX_fltr) pY_fltr = np.atleast_1d(pY_fltr) #Sample raster #This returns median and mad for ICESat footprint samp = geolib.sample(ras_ds, mX_fltr, mY_fltr, pad=pad) samp_idx = ~(np.ma.getmaskarray(samp[:,0])) npts = samp_idx.nonzero()[0].size if False: print("Applying slope filter, masking points with slope > %0.1f" % max_slope) slope_ds = geolib.gdaldem_mem_ds(ras_ds, processing='slope', returnma=False) slope_samp = geolib.sample(slope_ds, mX_fltr, mY_fltr, pad=pad) slope_samp_idx = (slope_samp[:,0] <= max_slope).data samp_idx = np.logical_and(slope_samp_idx, samp_idx) return samp, samp_idx, npts, pX_fltr, pY_fltr
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
print "Loading disparity maps into masked arrays" disp_x_f_in = iolib.ds_getma(disp_ds, 1) disp_y_f_in = iolib.ds_getma(disp_ds, 2) #If the input disp_ds (not velocities) has been resampled from original pixel dimensions, must alter values #disp_scaling = 0.57/32.0 #disp_x_f_in *= disp_scaling #disp_y_f_in *= disp_scaling disp_mask = malib.common_mask([disp_x_f_in, disp_y_f_in]) disp_x_f = np.ma.array(disp_x_f_in, mask=disp_mask) disp_y_f = np.ma.array(disp_y_f_in, mask=disp_mask) disp_m_f = np.ma.sqrt(disp_x_f**2 + disp_y_f**2) x_res, y_res = geolib.get_res(disp_ds) srs = geolib.get_ds_srs(disp_ds) proj_scale_factor = 1.0 if srs.IsSame(geolib.nps_srs) or srs.IsSame(geolib.sps_srs): proj_scale_factor = geolib.scale_ps_ds(disp_ds) print "Projection scale factor: ", proj_scale_factor #This is an ugly hack to iterate when external velocity map is used - want to clean up t_factor_lag = t_factor if vel_input: niter = 4 else: niter = 1 while niter > 0: #Convert input velocity grids to pixel disparities if vel_input: #Note minus sign for disp_y_f
def main(argv=None): parser = getparser() args = parser.parse_args() #Should check that files exist ref_dem_fn = args.ref_fn src_dem_fn = args.src_fn mode = args.mode mask_list = args.mask_list max_offset = args.max_offset max_dz = args.max_dz slope_lim = tuple(args.slope_lim) tiltcorr = args.tiltcorr polyorder = args.polyorder res = args.res #Maximum number of iterations max_iter = args.max_iter #These are tolerances (in meters) to stop iteration tol = args.tol min_dx = tol min_dy = tol min_dz = tol outdir = args.outdir if outdir is None: outdir = os.path.splitext(src_dem_fn)[0] + '_dem_align' if tiltcorr: outdir += '_tiltcorr' tiltcorr_done = False #Relax tolerance for initial round of co-registration #tiltcorr_tol = 0.1 #if tol < tiltcorr_tol: # tol = tiltcorr_tol if not os.path.exists(outdir): os.makedirs(outdir) outprefix = '%s_%s' % (os.path.splitext(os.path.split(src_dem_fn)[-1])[0], \ os.path.splitext(os.path.split(ref_dem_fn)[-1])[0]) outprefix = os.path.join(outdir, outprefix) print("\nReference: %s" % ref_dem_fn) print("Source: %s" % src_dem_fn) print("Mode: %s" % mode) print("Output: %s\n" % outprefix) src_dem_ds = gdal.Open(src_dem_fn) ref_dem_ds = gdal.Open(ref_dem_fn) #Get local cartesian coordinate system #local_srs = geolib.localtmerc_ds(src_dem_ds) #Use original source dataset coordinate system #Potentially issues with distortion and xyz/tiltcorr offsets for DEM with large extent local_srs = geolib.get_ds_srs(src_dem_ds) #local_srs = geolib.get_ds_srs(ref_dem_ds) #Resample to common grid ref_dem_res = float(geolib.get_res(ref_dem_ds, t_srs=local_srs, square=True)[0]) #Create a copy to be updated in place src_dem_ds_align = iolib.mem_drv.CreateCopy('', src_dem_ds, 0) src_dem_res = float(geolib.get_res(src_dem_ds, t_srs=local_srs, square=True)[0]) src_dem_ds = None #Resample to user-specified resolution ref_dem_ds, src_dem_ds_align = warplib.memwarp_multi([ref_dem_ds, src_dem_ds_align], \ extent='intersection', res=args.res, t_srs=local_srs, r='cubic') res = float(geolib.get_res(src_dem_ds_align, square=True)[0]) print("\nReference DEM res: %0.2f" % ref_dem_res) print("Source DEM res: %0.2f" % src_dem_res) print("Resolution for coreg: %s (%0.2f m)\n" % (args.res, res)) #Iteration number n = 1 #Cumulative offsets dx_total = 0 dy_total = 0 dz_total = 0 #Now iteratively update geotransform and vertical shift while True: print("*** Iteration %i ***" % n) dx, dy, dz, static_mask, fig = compute_offset(ref_dem_ds, src_dem_ds_align, src_dem_fn, mode, max_offset, \ mask_list=mask_list, max_dz=max_dz, slope_lim=slope_lim, plot=True) xyz_shift_str_iter = "dx=%+0.2fm, dy=%+0.2fm, dz=%+0.2fm" % (dx, dy, dz) print("Incremental offset: %s" % xyz_shift_str_iter) dx_total += dx dy_total += dy dz_total += dz xyz_shift_str_cum = "dx=%+0.2fm, dy=%+0.2fm, dz=%+0.2fm" % (dx_total, dy_total, dz_total) print("Cumulative offset: %s" % xyz_shift_str_cum) #String to append to output filenames xyz_shift_str_cum_fn = '_%s_x%+0.2f_y%+0.2f_z%+0.2f' % (mode, dx_total, dy_total, dz_total) #Should make an animation of this converging if n == 1: #static_mask_orig = static_mask if fig is not None: dst_fn = outprefix + '_%s_iter%02i_plot.png' % (mode, n) print("Writing offset plot: %s" % dst_fn) fig.gca().set_title("Incremental: %s\nCumulative: %s" % (xyz_shift_str_iter, xyz_shift_str_cum)) fig.savefig(dst_fn, dpi=300) #Apply the horizontal shift to the original dataset src_dem_ds_align = coreglib.apply_xy_shift(src_dem_ds_align, dx, dy, createcopy=False) #Should src_dem_ds_align = coreglib.apply_z_shift(src_dem_ds_align, dz, createcopy=False) n += 1 print("\n") #If magnitude of shift in all directions is less than tol #if n > max_iter or (abs(dx) <= min_dx and abs(dy) <= min_dy and abs(dz) <= min_dz): #If magnitude of shift is less than tol dm = np.sqrt(dx**2 + dy**2 + dz**2) dm_total = np.sqrt(dx_total**2 + dy_total**2 + dz_total**2) if dm_total > max_offset: sys.exit("Total offset exceeded specified max_offset (%0.2f m). Consider increasing -max_offset argument" % max_offset) #Stop iteration if n > max_iter or dm < tol: if fig is not None: dst_fn = outprefix + '_%s_iter%02i_plot.png' % (mode, n) print("Writing offset plot: %s" % dst_fn) fig.gca().set_title("Incremental:%s\nCumulative:%s" % (xyz_shift_str_iter, xyz_shift_str_cum)) fig.savefig(dst_fn, dpi=300) #Compute final elevation difference if True: ref_dem_clip_ds_align, src_dem_clip_ds_align = warplib.memwarp_multi([ref_dem_ds, src_dem_ds_align], \ res=res, extent='intersection', t_srs=local_srs, r='cubic') ref_dem_align = iolib.ds_getma(ref_dem_clip_ds_align, 1) src_dem_align = iolib.ds_getma(src_dem_clip_ds_align, 1) ref_dem_clip_ds_align = None diff_align = src_dem_align - ref_dem_align src_dem_align = None ref_dem_align = None #Get updated, final mask static_mask_final = get_mask(src_dem_clip_ds_align, mask_list, src_dem_fn) static_mask_final = np.logical_or(np.ma.getmaskarray(diff_align), static_mask_final) #Final stats, before outlier removal diff_align_compressed = diff_align[~static_mask_final] diff_align_stats = malib.get_stats_dict(diff_align_compressed, full=True) #Prepare filtered version for tiltcorr fit diff_align_filt = np.ma.array(diff_align, mask=static_mask_final) diff_align_filt = outlier_filter(diff_align_filt, f=3, max_dz=max_dz) #diff_align_filt = outlier_filter(diff_align_filt, perc=(12.5, 87.5), max_dz=max_dz) slope = get_filtered_slope(src_dem_clip_ds_align) diff_align_filt = np.ma.array(diff_align_filt, mask=np.ma.getmaskarray(slope)) diff_align_filt_stats = malib.get_stats_dict(diff_align_filt, full=True) #Fit 2D polynomial to residuals and remove #To do: add support for along-track and cross-track artifacts if tiltcorr and not tiltcorr_done: print("\n************") print("Calculating 'tiltcorr' 2D polynomial fit to residuals with order %i" % polyorder) print("************\n") gt = src_dem_clip_ds_align.GetGeoTransform() #Need to apply the mask here, so we're only fitting over static surfaces #Note that the origmask=False will compute vals for all x and y indices, which is what we want vals, resid, coeff = geolib.ma_fitpoly(diff_align_filt, order=polyorder, gt=gt, perc=(0,100), origmask=False) #vals, resid, coeff = geolib.ma_fitplane(diff_align_filt, gt, perc=(12.5, 87.5), origmask=False) #Should write out coeff or grid with correction vals_stats = malib.get_stats_dict(vals) #Want to have max_tilt check here #max_tilt = 4.0 #m #Should do percentage #vals.ptp() > max_tilt #Note: dimensions of ds and vals will be different as vals are computed for clipped intersection #Need to recompute planar offset for full src_dem_ds_align extent and apply xgrid, ygrid = geolib.get_xy_grids(src_dem_ds_align) valgrid = geolib.polyval2d(xgrid, ygrid, coeff) #For results of ma_fitplane #valgrid = coeff[0]*xgrid + coeff[1]*ygrid + coeff[2] src_dem_ds_align = coreglib.apply_z_shift(src_dem_ds_align, -valgrid, createcopy=False) if True: print("Creating plot of polynomial fit to residuals") fig, axa = plt.subplots(1,2, figsize=(8, 4)) dz_clim = malib.calcperc_sym(vals, (2, 98)) ax = pltlib.iv(diff_align_filt, ax=axa[0], cmap='RdBu', clim=dz_clim, \ label='Residual dz (m)', scalebar=False) ax = pltlib.iv(valgrid, ax=axa[1], cmap='RdBu', clim=dz_clim, \ label='Polyfit dz (m)', ds=src_dem_ds_align) #if tiltcorr: #xyz_shift_str_cum_fn += "_tiltcorr" tiltcorr_fig_fn = outprefix + '%s_polyfit.png' % xyz_shift_str_cum_fn print("Writing out figure: %s\n" % tiltcorr_fig_fn) fig.savefig(tiltcorr_fig_fn, dpi=300) print("Applying tilt correction to difference map") diff_align -= vals #Should iterate until tilts are below some threshold #For now, only do one tiltcorr tiltcorr_done=True #Now use original tolerance, and number of iterations tol = args.tol max_iter = n + args.max_iter else: break if True: #Write out aligned difference map for clipped extent with vertial offset removed align_diff_fn = outprefix + '%s_align_diff.tif' % xyz_shift_str_cum_fn print("Writing out aligned difference map with median vertical offset removed") iolib.writeGTiff(diff_align, align_diff_fn, src_dem_clip_ds_align) if True: #Write out fitered aligned difference map align_diff_filt_fn = outprefix + '%s_align_diff_filt.tif' % xyz_shift_str_cum_fn print("Writing out filtered aligned difference map with median vertical offset removed") iolib.writeGTiff(diff_align_filt, align_diff_filt_fn, src_dem_clip_ds_align) #Extract final center coordinates for intersection center_coord_ll = geolib.get_center(src_dem_clip_ds_align, t_srs=geolib.wgs_srs) center_coord_xy = geolib.get_center(src_dem_clip_ds_align) src_dem_clip_ds_align = None #Write out final aligned src_dem align_fn = outprefix + '%s_align.tif' % xyz_shift_str_cum_fn print("Writing out shifted src_dem with median vertical offset removed: %s" % align_fn) #Open original uncorrected dataset at native resolution src_dem_ds = gdal.Open(src_dem_fn) src_dem_ds_align = iolib.mem_drv.CreateCopy('', src_dem_ds, 0) #Apply final horizontal and vertial shift to the original dataset #Note: potentially issues if we used a different projection during coregistration! src_dem_ds_align = coreglib.apply_xy_shift(src_dem_ds_align, dx_total, dy_total, createcopy=False) src_dem_ds_align = coreglib.apply_z_shift(src_dem_ds_align, dz_total, createcopy=False) if tiltcorr: xgrid, ygrid = geolib.get_xy_grids(src_dem_ds_align) valgrid = geolib.polyval2d(xgrid, ygrid, coeff) #For results of ma_fitplane #valgrid = coeff[0]*xgrid + coeff[1]*ygrid + coeff[2] src_dem_ds_align = coreglib.apply_z_shift(src_dem_ds_align, -valgrid, createcopy=False) #Might be cleaner way to write out MEM ds directly to disk src_dem_full_align = iolib.ds_getma(src_dem_ds_align) iolib.writeGTiff(src_dem_full_align, align_fn, src_dem_ds_align) if True: #Output final aligned src_dem, masked so only best pixels are preserved #Useful if creating a new reference product #Can also use apply_mask.py print("Applying filter to shiftec src_dem") align_diff_filt_full_ds = warplib.memwarp_multi_fn([align_diff_filt_fn,], res=src_dem_ds_align, extent=src_dem_ds_align, \ t_srs=src_dem_ds_align)[0] align_diff_filt_full = iolib.ds_getma(align_diff_filt_full_ds) align_diff_filt_full_ds = None align_fn_masked = outprefix + '%s_align_filt.tif' % xyz_shift_str_cum_fn iolib.writeGTiff(np.ma.array(src_dem_full_align, mask=np.ma.getmaskarray(align_diff_filt_full)), \ align_fn_masked, src_dem_ds_align) src_dem_full_align = None src_dem_ds_align = None #Compute original elevation difference if True: ref_dem_clip_ds, src_dem_clip_ds = warplib.memwarp_multi([ref_dem_ds, src_dem_ds], \ res=res, extent='intersection', t_srs=local_srs, r='cubic') src_dem_ds = None ref_dem_ds = None ref_dem_orig = iolib.ds_getma(ref_dem_clip_ds) src_dem_orig = iolib.ds_getma(src_dem_clip_ds) #Needed for plotting ref_dem_hs = geolib.gdaldem_mem_ds(ref_dem_clip_ds, processing='hillshade', returnma=True, computeEdges=True) src_dem_hs = geolib.gdaldem_mem_ds(src_dem_clip_ds, processing='hillshade', returnma=True, computeEdges=True) diff_orig = src_dem_orig - ref_dem_orig #Only compute stats over valid surfaces static_mask_orig = get_mask(src_dem_clip_ds, mask_list, src_dem_fn) #Note: this doesn't include outlier removal or slope mask! static_mask_orig = np.logical_or(np.ma.getmaskarray(diff_orig), static_mask_orig) #For some reason, ASTER DEM diff have a spike near the 0 bin, could be an issue with masking? diff_orig_compressed = diff_orig[~static_mask_orig] diff_orig_stats = malib.get_stats_dict(diff_orig_compressed, full=True) #Prepare filtered version for comparison diff_orig_filt = np.ma.array(diff_orig, mask=static_mask_orig) diff_orig_filt = outlier_filter(diff_orig_filt, f=3, max_dz=max_dz) #diff_orig_filt = outlier_filter(diff_orig_filt, perc=(12.5, 87.5), max_dz=max_dz) slope = get_filtered_slope(src_dem_clip_ds) diff_orig_filt = np.ma.array(diff_orig_filt, mask=np.ma.getmaskarray(slope)) diff_orig_filt_stats = malib.get_stats_dict(diff_orig_filt, full=True) #Write out original difference map print("Writing out original difference map for common intersection before alignment") orig_diff_fn = outprefix + '_orig_diff.tif' iolib.writeGTiff(diff_orig, orig_diff_fn, ref_dem_clip_ds) src_dem_clip_ds = None ref_dem_clip_ds = None if True: align_stats_fn = outprefix + '%s_align_stats.json' % xyz_shift_str_cum_fn align_stats = {} align_stats['src_fn'] = src_dem_fn align_stats['ref_fn'] = ref_dem_fn align_stats['align_fn'] = align_fn align_stats['res'] = {} align_stats['res']['src'] = src_dem_res align_stats['res']['ref'] = ref_dem_res align_stats['res']['coreg'] = res align_stats['center_coord'] = {'lon':center_coord_ll[0], 'lat':center_coord_ll[1], \ 'x':center_coord_xy[0], 'y':center_coord_xy[1]} align_stats['shift'] = {'dx':dx_total, 'dy':dy_total, 'dz':dz_total, 'dm':dm_total} #This tiltcorr flag gets set to false, need better flag if tiltcorr: align_stats['tiltcorr'] = {} align_stats['tiltcorr']['coeff'] = coeff.tolist() align_stats['tiltcorr']['val_stats'] = vals_stats align_stats['before'] = diff_orig_stats align_stats['before_filt'] = diff_orig_filt_stats align_stats['after'] = diff_align_stats align_stats['after_filt'] = diff_align_filt_stats import json with open(align_stats_fn, 'w') as f: json.dump(align_stats, f) #Create output plot if True: print("Creating final plot") kwargs = {'interpolation':'none'} #f, axa = plt.subplots(2, 4, figsize=(11, 8.5)) f, axa = plt.subplots(2, 4, figsize=(16, 8)) for ax in axa.ravel()[:-1]: ax.set_facecolor('k') pltlib.hide_ticks(ax) dem_clim = malib.calcperc(ref_dem_orig, (2,98)) axa[0,0].imshow(ref_dem_hs, cmap='gray', **kwargs) im = axa[0,0].imshow(ref_dem_orig, cmap='cpt_rainbow', clim=dem_clim, alpha=0.6, **kwargs) pltlib.add_cbar(axa[0,0], im, arr=ref_dem_orig, clim=dem_clim, label=None) pltlib.add_scalebar(axa[0,0], res=res) axa[0,0].set_title('Reference DEM') axa[0,1].imshow(src_dem_hs, cmap='gray', **kwargs) im = axa[0,1].imshow(src_dem_orig, cmap='cpt_rainbow', clim=dem_clim, alpha=0.6, **kwargs) pltlib.add_cbar(axa[0,1], im, arr=src_dem_orig, clim=dem_clim, label=None) axa[0,1].set_title('Source DEM') #axa[0,2].imshow(~static_mask_orig, clim=(0,1), cmap='gray') axa[0,2].imshow(~static_mask, clim=(0,1), cmap='gray', **kwargs) axa[0,2].set_title('Surfaces for co-registration') dz_clim = malib.calcperc_sym(diff_orig_compressed, (5, 95)) im = axa[1,0].imshow(diff_orig, cmap='RdBu', clim=dz_clim) pltlib.add_cbar(axa[1,0], im, arr=diff_orig, clim=dz_clim, label=None) axa[1,0].set_title('Elev. Diff. Before (m)') im = axa[1,1].imshow(diff_align, cmap='RdBu', clim=dz_clim) pltlib.add_cbar(axa[1,1], im, arr=diff_align, clim=dz_clim, label=None) axa[1,1].set_title('Elev. Diff. After (m)') #tight_dz_clim = (-1.0, 1.0) tight_dz_clim = (-2.0, 2.0) #tight_dz_clim = (-10.0, 10.0) #tight_dz_clim = malib.calcperc_sym(diff_align_filt, (5, 95)) im = axa[1,2].imshow(diff_align_filt, cmap='RdBu', clim=tight_dz_clim) pltlib.add_cbar(axa[1,2], im, arr=diff_align_filt, clim=tight_dz_clim, label=None) axa[1,2].set_title('Elev. Diff. After (m)') #Tried to insert Nuth fig here #ax_nuth.change_geometry(1,2,1) #f.axes.append(ax_nuth) bins = np.linspace(dz_clim[0], dz_clim[1], 128) axa[1,3].hist(diff_orig_compressed, bins, color='g', label='Before', alpha=0.5) axa[1,3].hist(diff_align_compressed, bins, color='b', label='After', alpha=0.5) axa[1,3].set_xlim(*dz_clim) axa[1,3].axvline(0, color='k', linewidth=0.5, linestyle=':') axa[1,3].set_xlabel('Elev. Diff. (m)') axa[1,3].set_ylabel('Count (px)') axa[1,3].set_title("Source - Reference") before_str = 'Before\nmed: %0.2f\nnmad: %0.2f' % (diff_orig_stats['med'], diff_orig_stats['nmad']) axa[1,3].text(0.05, 0.95, before_str, va='top', color='g', transform=axa[1,3].transAxes, fontsize=8) after_str = 'After\nmed: %0.2f\nnmad: %0.2f' % (diff_align_stats['med'], diff_align_stats['nmad']) axa[1,3].text(0.65, 0.95, after_str, va='top', color='b', transform=axa[1,3].transAxes, fontsize=8) #This is empty axa[0,3].axis('off') suptitle = '%s\nx: %+0.2fm, y: %+0.2fm, z: %+0.2fm' % (os.path.split(outprefix)[-1], dx_total, dy_total, dz_total) f.suptitle(suptitle) f.tight_layout() plt.subplots_adjust(top=0.90) fig_fn = outprefix + '%s_align.png' % xyz_shift_str_cum_fn print("Writing out figure: %s" % fig_fn) f.savefig(fig_fn, dpi=300)
y_fltr = glas_pts_fltr[:, ycol] z_fltr = glas_pts_fltr[:, zcol] dem_mask_fn = os.path.splitext(dem_fn)[0] + '_control.tif' if os.path.exists(dem_mask_fn): print("Loading Masked DEM: %s" % dem_mask_fn) dem_mask_ds = gdal.Open(dem_mask_fn) dem_mask = iolib.ds_getma(dem_mask_ds) else: dem_mask_ds = dem_ds dem_mask = dem_ma #Convert input xy coordinates to raster coordinates mX_fltr, mY_fltr, mZ = geolib.cT_helper(x_fltr, y_fltr, 0, pt_srs, geolib.get_ds_srs(dem_mask_ds)) pX_fltr, pY_fltr = geolib.mapToPixel(mX_fltr, mY_fltr, dem_mask_ds.GetGeoTransform()) pX_fltr = np.atleast_1d(pX_fltr) pY_fltr = np.atleast_1d(pY_fltr) #Sample raster #This returns median and mad for ICESat footprint samp = geolib.sample(dem_mask_ds, mX_fltr, mY_fltr, pad=pad) samp_idx = ~(np.ma.getmaskarray(samp[:, 0])) npts = samp_idx.nonzero()[0].size if npts < min_pts: print( "Not enough points after sampling valid pixels, post control.tif mask (%i < %i)\n" % (npts, min_pts))
def main(): parser = getparser() #Create dictionary of arguments args = vars(parser.parse_args()) #Want to enable -full when -of is specified, probably a fancy way to do this with argparse if args['of']: args['full'] = True #Note, imshow has many interpolation types: #'none', 'nearest', 'bilinear', 'bicubic', 'spline16', 'spline36', 'hanning', 'hamming', #'hermite', 'kaiser', 'quadric', 'catrom', 'gaussian', 'bessel', 'mitchell', 'sinc', 'lanczos' #{'interpolation':'bicubic', 'aspect':'auto'} #args['imshow_kwargs']={'interpolation':'bicubic'} args['imshow_kwargs']={'interpolation':'none'} if args['clipped'] and args['overlay'] is None: sys.exit("Must specify an overlay filename with option 'clipped'") #Set this as the background numpy array args['bg'] = None if args['shp'] is not None: print args['shp'] if args['link']: fig = plt.figure(0) n_ax = len(args['filelist']) src_ds_list = [gdal.Open(fn) for fn in args['filelist']] t_srs = geolib.get_ds_srs(src_ds_list[0]) res_stats = geolib.get_res_stats(src_ds_list, t_srs=t_srs) #Use min res res = res_stats[0] extent = geolib.ds_geom_union_extent(src_ds_list, t_srs=t_srs) #print res, extent for n,fn in enumerate(args['filelist']): if not iolib.fn_check(fn): print 'Unable to open input file: %s' % fn continue #Note: this won't work if img1 has 1 band and img2 has 3 bands #Hack for now if not args['link']: fig = plt.figure(n) n_ax = 1 #fig.set_facecolor('black') fig.set_facecolor('white') fig.canvas.set_window_title(os.path.split(fn)[1]) #fig.suptitle(os.path.split(fn)[1], fontsize=10) #Note: warplib SHOULD internally check to see if extent/resolution/projection are identical #This eliminates the need for a clipped flag #If user has already warped the background and source data if args['overlay']: if args['clipped']: src_ds = gdal.Open(fn, gdal.GA_ReadOnly) #Only load up the bg array once if args['bg'] is None: #Need to check that background fn exists print "%s background" % args['overlay'] bg_ds = gdal.Open(args['overlay'], gdal.GA_ReadOnly) #Check image dimensions args['bg'] = get_bma(bg_ds, 1, args['full']) else: #Clip/warp background dataset to match overlay dataset #src_ds, bg_ds = warplib.memwarp_multi_fn([fn, args['overlay']], extent='union') src_ds, bg_ds = warplib.memwarp_multi_fn([fn, args['overlay']], extent='first') #src_ds, bg_ds = warplib.memwarp_multi_fn([fn, args['overlay']], res='min', extent='first') #Want to load up the unique bg array for each input args['bg'] = get_bma(bg_ds, 1, args['full']) else: src_ds = gdal.Open(fn, gdal.GA_ReadOnly) if args['link']: #Not sure why, but this still warps all linked ds, even when identical res/extent/srs #src_ds = warplib.warp(src_ds, res=res, extent=extent, t_srs=t_srs) src_ds = warplib.memwarp_multi([src_ds,], res=res, extent=extent, t_srs=t_srs)[0] cbar_kwargs={'extend':'both', 'orientation':'vertical', 'shrink':0.7, 'fraction':0.12, 'pad':0.02} nbands = src_ds.RasterCount b = src_ds.GetRasterBand(1) dt = gdal.GetDataTypeName(b.DataType) #Eventually, check dt of each band print print "%s (%i bands)" % (fn, nbands) #Singleband raster if (nbands == 1): if args['cmap'] is None: #Special case to handle ASP float32 grayscale data if '-L_sub' in fn or '-R_sub' in fn: args['cmap'] = 'gray' else: if (dt == 'Float64') or (dt == 'Float32') or (dt == 'Int32'): args['cmap'] = 'cpt_rainbow' #This is for WV images elif (dt == 'UInt16'): args['cmap'] = 'gray' elif (dt == 'Byte'): args['cmap'] = 'gray' else: args['cmap'] = 'cpt_rainbow' """ if 'count' in fn: args['clim_perc'] = (0,100) cbar_kwargs['extend'] = 'neither' args['cmap'] = 'cpt_rainbow' if 'mask' in fn: args['clim'] = (0, 1) #Could be (0, 255) #args['clim_perc'] = (0,100) #Want absolute clim of 0, then perc of 100 cbar_kwargs['extend'] = 'neither' args['cmap'] = 'gray' """ args['cbar_kwargs'] = cbar_kwargs bma = get_bma(src_ds, 1, args['full']) #Note n+1 here ensures we're assigning subplot correctly here (n is 0-relative, subplot is 1) bma_fig(fig, bma, n_subplt=n_ax, subplt=n+1, ds=src_ds, **args) #3-band raster, likely disparity map #This doesn't work when alpha band is present elif (nbands == 3) and (dt == 'Byte'): #For some reason, tifs are vertically flipped if (os.path.splitext(fn)[1] == '.tif'): args['imshow_kwargs']['origin'] = 'lower' #Use gdal dataset here instead of imread(fn)? imgplot = plt.imshow(plt.imread(fn), **args['imshow_kwargs']) pltlib.hide_ticks(imgplot.axes) #Handle the 3-band disparity map case here #elif ((dt == 'Float32') or (dt == 'Int32')): else: if args['cmap'] is None: args['cmap'] = 'cpt_rainbow' bn = 1 while bn <= nbands: bma = get_bma(src_ds, bn, args['full']) bma_fig(fig, bma, n_subplt=nbands, subplt=bn, ds=src_ds, **args) bn += 1 #Want to be better about this else case - lazy for now #else: # bma = get_bma(src_ds, 1, args['full']) # bma_fig(fig, bma, **args) ts = timelib.fn_getdatetime_list(fn) if ts: print "Timestamp list: ", ts """ if len(ts) == 1: plt.title(ts[0].date()) elif len(ts) == 2: plt.title("%s to %s" % (ts[0].date(), ts[1].date())) """ plt.tight_layout() #Write out the file #Note: make sure display is local for savefig if args['of']: outf = str(os.path.splitext(fn)[0])+'_fig.'+args['of'] #outf = str(os.path.splitext(fn)[0])+'_'+str(os.path.splitext(args['overlay'])[0])+'_fig.'+args['of'] #Note: need to account for colorbar (12%) and title - some percentage of axes beyond bma dimensions #Should specify minimum text size for output max_size = np.array((10.0,10.0)) max_dpi = 300.0 #If both outsize and dpi are specified, don't try to change, just make the figure if (args['outsize'] is None) and (args['dpi'] is None): args['dpi'] = 150.0 #Unspecified out figure size for a given dpi if (args['outsize'] is None) and (args['dpi'] is not None): args['outsize'] = np.array(bma.shape[::-1])/args['dpi'] if np.any(np.array(args['outsize']) > max_size): args['outsize'] = max_size #Specified output figure size, no specified dpi elif (args['outsize'] is not None) and (args['dpi'] is None): args['dpi'] = np.min([np.max(np.array(bma.shape[::-1])/np.array(args['outsize'])), max_dpi]) print print "Saving output figure:" print "Filename: ", outf print "Size (in): ", args['outsize'] print "DPI (px/in): ", args['dpi'] print "Input dimensions (px): ", bma.shape[::-1] print "Output dimensions (px): ", tuple(np.array(args['outsize'])*args['dpi']) print fig.set_size_inches(args['outsize']) #fig.set_size_inches(54.427, 71.87) #fig.set_size_inches(40, 87) fig.savefig(outf, dpi=args['dpi'], bbox_inches='tight', pad_inches=0, facecolor=fig.get_facecolor(), edgecolor='none') #Show the plot - want to show all at once if not args['of']: plt.show()
def bma_fig(fig, bma, cmap='cpt_rainbow', clim=None, clim_perc=(2, 98), bg=None, bg_perc=(2, 98), n_subplt=1, subplt=1, label=None, title=None, contour_int=None, contour_fn=None, alpha=0.5, ticks=False, scalebar=None, ds=None, shp=None, imshow_kwargs={'interpolation': 'nearest'}, cbar_kwargs={'orientation': 'vertical'}, **kwargs): #We don't use the kwargs, just there to save parsing in main if clim is None: clim = pltlib.get_clim(bma, clim_perc=clim_perc) print("Colorbar limits: %0.3f %0.3f" % (clim[0], clim[1])) #Link all subplots for zoom/pan sharex = sharey = None if len(fig.get_axes()) > 0: sharex = sharey = fig.get_axes()[0] #Hack to catch situations with only 1 subplot, but a subplot number > 1 if n_subplt == 1: subplt = 1 #One row, multiple columns ax = fig.add_subplot(1, n_subplt, subplt, sharex=sharex, sharey=sharey) #This occupies the full figure #ax = fig.add_axes([0., 0., 1., 1., ]) #ax.patch.set_facecolor('black') ax.patch.set_facecolor('white') #Set appropriate nodata value color cmap_name = cmap cmap = pltlib.cmap_setndv(cmap_name) #ax.set_title("Band %i" % subplt, fontsize=10) if title is not None: ax.set_title(title) #If a background image is provided, plot it first if bg is not None: #Note, alpha=1 is opaque, 0 completely transparent #alpha = 0.6 bg_perc = (4, 96) bg_alpha = 1.0 #bg_clim = malib.calcperc(bg, bg_perc) bg_clim = (1, 255) bg_cmap_name = 'gray' bg_cmap = pltlib.cmap_setndv(bg_cmap_name, cmap_name) #bg_cmap = plt.get_cmap(bg_cmap_name) #if 'inferno' in cmap_name: # bg_cmap.set_bad('0.5', alpha=1) #else: # bg_cmap.set_bad('k', alpha=1) #Set the overlay bad values to completely transparent, otherwise darkens the bg cmap.set_bad(alpha=0) bgplot = ax.imshow(bg, cmap=bg_cmap, clim=bg_clim, alpha=bg_alpha) imgplot = ax.imshow(bma, alpha=alpha, cmap=cmap, clim=clim, **imshow_kwargs) else: imgplot = ax.imshow(bma, cmap=cmap, clim=clim, **imshow_kwargs) gt = None if ds is not None: gt = np.array(ds.GetGeoTransform()) gt_scale_factor = min( np.array([ds.RasterYSize, ds.RasterXSize]) / np.array(bma.shape, dtype=float)) gt[1] *= gt_scale_factor gt[5] *= gt_scale_factor ds_srs = geolib.get_ds_srs(ds) if ticks: scale_ticks(ax, ds) else: pltlib.hide_ticks(ax) xres = geolib.get_res(ds)[0] else: pltlib.hide_ticks(ax) #This forces the black line outlining the image subplot to snap to the actual image dimensions #depreciated in 2.2 #ax.set_adjustable('box-forced') if cbar_kwargs: #Should set the format based on dtype of input data #cbar_kwargs['format'] = '%i' #cbar_kwargs['format'] = '%0.1f' #cbar_kwargs['orientation'] = 'horizontal' #Determine whether we need to add extend triangles to colorbar cbar_kwargs['extend'] = pltlib.get_cbar_extend(bma, clim) #Add the colorbar to the axes cbar = pltlib.add_cbar(ax, imgplot, label=label, cbar_kwargs=cbar_kwargs) #Plot contours every contour_int interval and update colorbar appropriately if contour_int is not None: if contour_fn is not None: contour_bma = iolib.fn_getma(contour_fn) contour_bma_clim = malib.calcperc(contour_bma) else: contour_bma = bma contour_bma_clim = clim #PIG bed ridge contours #bma_clim = (-1300, -300) #Jak front shear margin contours #bma_clim = (2000, 4000) contour_bma_clim = (100, 250) cstart = int(np.floor(contour_bma_clim[0] / contour_int)) * contour_int cend = int(np.ceil(contour_bma_clim[1] / contour_int)) * contour_int #Turn off dashed negative (beds are below sea level) #matplotlib.rcParams['contour.negative_linestyle'] = 'solid' clvl = np.arange(cstart, cend + 1, contour_int) contour_prop = { 'levels': clvl, 'linestyle': '-', 'linewidths': 0.5, 'alpha': 1.0 } #contours = ax.contour(contour_bma, colors='k', **contour_prop) #contour_cmap = 'gray' contour_cmap = 'gray_r' #This prevents white contours contour_cmap_clim = (0, contour_bma_clim[-1]) contours = ax.contour(contour_bma, cmap=contour_cmap, vmin=contour_cmap_clim[0], \ vmax=contour_cmap_clim[-1], **contour_prop) #Add labels ax.clabel(contours, inline=True, inline_spacing=0, fontsize=4, fmt='%i') #Update the cbar with contour locations #cbar.add_lines(contours) #cbar.set_ticks(contours.levels) #Plot shape overlay, moved code to pltlib if shp is not None: pltlib.shp_overlay(ax, ds, shp, gt=gt, color='k') if scalebar: scale_ticks(ax, ds) sb_loc = pltlib.best_scalebar_location(bma) #Force scalebar position #sb_loc = 'lower right' pltlib.add_scalebar(ax, xres, location=sb_loc) if not ticks: pltlib.hide_ticks(ax) #Set up interactive display global gbma gbma = bma global ggt ggt = gt #Clicking on a subplot will make it active for z-coordinate display fig.canvas.mpl_connect('button_press_event', onclick) fig.canvas.mpl_connect('axes_enter_event', enter_axis) #Add support for interactive z-value display ax.format_coord = format_coord
def main(): parser = getparser() args = parser.parse_args() t_unit = args.dt plot = args.plot remove_offsets = args.remove_offsets mask_fn = args.mask_fn if mask_fn is not None: remove_offsets = True #Input is 3-band disparity map, extract bands directly src_fn = args.disp_fn if not iolib.fn_check(src_fn): sys.exit("Unable to locate input file: %s" % src_fn) src_ds = iolib.fn_getds(src_fn) if src_ds.RasterCount != 3: sys.exit("Input file must be ASP disparity map (3 bands: x, y, mask)") #Extract pixel resolution h_res, v_res = geolib.get_res(src_ds) #Horizontal scale factor #If running on disparity_view output (gdal_translate -outsize 5% 5% F.tif F_5.tif) #h_res /= 20 #v_res /= 20 #Load horizontal and vertical disparities h = iolib.ds_getma(src_ds, bnum=1) v = iolib.ds_getma(src_ds, bnum=2) #ASP output has northward motion as negative values in band 2 v *= -1 t1, t2 = timelib.fn_getdatetime_list(src_fn) dt = t2 - t1 #Default t_factor is in 1/years t_factor = timelib.get_t_factor(t1, t2) #Input timestamp arrays if inputs are mosaics if False: t1_fn = '' t2_fn = '' if os.path.exists(t1_fn) and os.path.exists(t2_fn): t_factor = timelib.get_t_factor_fn(t1_fn, t2_fn) if t_factor is None: sys.exit("Unable to determine input timestamps") if t_unit == 'day': t_factor *= 365.25 print("Input dates:") print(t1) print(t2) print(dt) print(t_factor, t_unit) #Scale values for polar stereographic distortion srs = geolib.get_ds_srs(src_ds) proj_scale_factor = 1.0 #Want to scale to get correct distances for polar sterographic if srs.IsSame(geolib.nps_srs) or srs.IsSame(geolib.sps_srs): proj_scale_factor = geolib.scale_ps_ds(src_ds) #Convert disparity values in pixels to m/t_unit h_myr = h * h_res * proj_scale_factor / t_factor h = None v_myr = v * v_res * proj_scale_factor / t_factor v = None #Velocity Magnitude m = np.ma.sqrt(h_myr**2 + v_myr**2) print("Velocity Magnitude stats") malib.print_stats(m) #Remove x and y offsets over control surfaces offset_str = '' if remove_offsets: if mask_fn is None: from demcoreg.dem_mask import get_mask print( "\nUsing demcoreg to prepare mask of stable control surfaces\n" ) #TODO: Accept mask_list as in demcoreg #mask_list = args.mask_list # for now keep it simple, limit to non-glacier surfaces mask_list = [ 'glaciers', ] mask = get_mask(src_ds, mask_list=mask_list, dem_fn=src_fn) else: print("\nWarping input raster mask") #This can be from previous dem_mask.py run (e.g. *rockmask.tif) mask_ds = warplib.memwarp_multi_fn([ mask_fn, ], res=src_ds, extent=src_ds, t_srs=src_ds)[0] mask = iolib.ds_getma(mask_ds) #The default from ds_getma is a masked array, so need to isolate boolean mask #Assume input is 0 for masked, 1 for unmasked (valid control surface) mask = mask.filled().astype('bool') #This should work, as the *rockmask.py is 1 for unmasked, 0 for masked, with ndv=0 #mask = np.ma.getmaskarray(mask) #Vector mask - untested if os.path.splitext(mask_fn)[1] == 'shp': mask = geolib.shp2array(mask_fn, src_ds) print("\nRemoving median x and y offset over static control surfaces") h_myr_count = h_myr.count() h_myr_static_count = np.ma.array(h_myr, mask=mask).count() h_myr_mad, h_myr_med = malib.mad(np.ma.array(h_myr, mask=mask), return_med=True) v_myr_mad, v_myr_med = malib.mad(np.ma.array(v_myr, mask=mask), return_med=True) print("Static pixel count: %i (%0.1f%%)" % (h_myr_static_count, 100 * float(h_myr_static_count) / h_myr_count)) print("median (+/-NMAD)") print("x velocity offset: %0.2f (+/-%0.2f) m/%s" % (h_myr_med, h_myr_mad, t_unit)) print("y velocity offset: %0.2f (+/-%0.2f) m/%s" % (v_myr_med, v_myr_mad, t_unit)) h_myr -= h_myr_med v_myr -= v_myr_med offset_str = '_offsetcorr_h%0.2f_v%0.2f' % (h_myr_med, v_myr_med) #Velocity Magnitude m = np.ma.sqrt(h_myr**2 + v_myr**2) print("Velocity Magnitude stats after correction") malib.print_stats(m) if plot: fig_fn = os.path.splitext(src_fn)[0] + '.png' label = 'Velocity (m/%s)' % t_unit f, ax = make_plot(m, fig_fn, label) plotvec(h_myr, v_myr) plt.tight_layout() plt.savefig(fig_fn, dpi=300, bbox_inches='tight', pad_inches=0, edgecolor='none') print("Writing out files") gt = src_ds.GetGeoTransform() proj = src_ds.GetProjection() dst_fn = os.path.splitext(src_fn)[0] + '_vm%s.tif' % offset_str iolib.writeGTiff(m, dst_fn, create=True, gt=gt, proj=proj) dst_fn = os.path.splitext(src_fn)[0] + '_vx%s.tif' % offset_str iolib.writeGTiff(h_myr, dst_fn, create=True, gt=gt, proj=proj) dst_fn = os.path.splitext(src_fn)[0] + '_vy%s.tif' % offset_str iolib.writeGTiff(v_myr, dst_fn, create=True, gt=gt, proj=proj) src_ds = None
x_fltr = glas_pts_fltr[:,xcol] y_fltr = glas_pts_fltr[:,ycol] z_fltr = glas_pts_fltr[:,zcol] dem_mask_fn = os.path.splitext(dem_fn)[0]+'_ref.tif' if os.path.exists(dem_mask_fn): print("Loading Masked DEM: %s" % dem_mask_fn) dem_mask_ds = gdal.Open(dem_mask_fn) dem_mask = iolib.ds_getma(dem_mask_ds) else: dem_mask_ds = dem_ds dem_mask = dem_ma #Convert input xy coordinates to raster coordinates mX_fltr, mY_fltr, mZ = geolib.cT_helper(x_fltr, y_fltr, 0, pt_srs, geolib.get_ds_srs(dem_mask_ds)) pX_fltr, pY_fltr = geolib.mapToPixel(mX_fltr, mY_fltr, dem_mask_ds.GetGeoTransform()) pX_fltr = np.atleast_1d(pX_fltr) pY_fltr = np.atleast_1d(pY_fltr) #Sample raster #This returns median and mad for ICESat footprint samp = geolib.sample(dem_mask_ds, mX_fltr, mY_fltr, pad=pad) samp_idx = ~(np.ma.getmaskarray(samp[:,0])) npts = samp_idx.nonzero()[0].size if npts < min_pts: print("Not enough points after sampling valud pixels, post bareground mask (%i < %i)" % (npts, min_pts)) continue if True: print("Applying slope filter, masking points with slope > %0.1f" % max_slope)
np.savetxt(out_csv_valsurf_fn, glas_pts_fltr_valsurf, header=hdr_out, fmt=fmt_out, delimiter=',', comments='') if os.path.exists(dem_mask_fn): print("Writing out %i ICESat-GLAS shots for co-registration" % glas_pts_fltr_coreg.shape[0]) out_csv_fn_coreg = os.path.splitext(out_csv_fn)[0]+'_ref.csv' #lat,lon,elev_ground for pc_align out_csv_fn_coreg_asp = os.path.splitext(out_csv_fn)[0]+'_ref_asp.csv' #Could add DEM samp columns here np.savetxt(out_csv_fn_coreg, glas_pts_fltr_coreg, header=hdr_out, fmt=fmt_out, delimiter=',', comments='') np.savetxt(out_csv_fn_coreg_asp, glas_pts_fltr_coreg_asp, fmt='%0.6f, %0.6f, %0.2f', delimiter=',') # For plotting the qfilt ICESat-GLAS used for co-reg x_fltr_mask_coreg = glas_pts_fltr_coreg[:,xcol] y_fltr_mask_coreg = glas_pts_fltr_coreg[:,ycol] z_fltr_mask_coreg = glas_pts_fltr_coreg[:,zcol] mX_fltr_mask_coreg, mY_fltr_mask_coreg, mZ_coreg = geolib.cT_helper(x_fltr_mask_coreg, y_fltr_mask_coreg, 0, pt_srs, geolib.get_ds_srs(dem_mask_ds)) pX_fltr_mask_coreg, pY_fltr_mask_coreg = geolib.mapToPixel(mX_fltr_mask_coreg, mY_fltr_mask_coreg, dem_mask_ds.GetGeoTransform()) pX_fltr_mask_coreg = np.atleast_1d(pX_fltr_mask_coreg) pY_fltr_mask_coreg = np.atleast_1d(pY_fltr_mask_coreg) # For plotting the qfilt ICESat-GLAS used for examining all valid surfaces x_fltr_mask_valsurf = glas_pts_fltr_valsurf[:,xcol] y_fltr_mask_valsurf = glas_pts_fltr_valsurf[:,ycol] z_fltr_mask_valsurf = glas_pts_fltr_valsurf[:,zcol] mX_fltr_mask_valsurf, mY_fltr_mask_valsurf, mZ_valsurf = geolib.cT_helper(x_fltr_mask_valsurf, y_fltr_mask_valsurf, 0, pt_srs, geolib.get_ds_srs(dem_chmmask_ds)) pX_fltr_mask_valsurf, pY_fltr_mask_valsurf = geolib.mapToPixel(mX_fltr_mask_valsurf, mY_fltr_mask_valsurf, dem_chmmask_ds.GetGeoTransform()) pX_fltr_mask_valsurf = np.atleast_1d(pX_fltr_mask_valsurf) pY_fltr_mask_valsurf = np.atleast_1d(pY_fltr_mask_valsurf) # Get the elev dif b/w GLAS and DEM dz = z_fltr_mask_coreg - coreg_samp[coreg_samp_idx,0]
def warp_multi(src_ds_list, res='first', extent='intersection', t_srs='first', r='cubic', warptype=memwarp, outdir=None, dst_ndv=None, verbose=True, debug=False): """This parses and checks inputs, then calls desired warp function with appropriate arguments for each input ds Parameters ---------- src_ds_list : list of gdal.Dataset objects List of original datasets to be warped res : arbitrary type Desired output resolution extent : arbitrary type Desired output extent t_srs : arbitrary type Desired output spatial reference r : str Desired resampling algorithm warptype : function Desired warp type (write to memory or disk) outdir : str Desired output directory (for disk warp) dst_ndv : float Desired output NoData Value verbose : bool Print warp parameters debug : bool Print extra information for debugging purposes Returns ------- out_ds_list : list of gdal.Dataset objects List of warped datasets (either in memory or on disk) """ #Type cast arguments as str for evaluation #Avoid path errors #res = str(res) #extent = str(extent) #t_srs = str(t_srs) #Parse the input t_srs = parse_srs(t_srs, src_ds_list) res = parse_res(res, src_ds_list, t_srs) extent = parse_extent(extent, src_ds_list, t_srs) if verbose: print("\nWarping all inputs to the following:") print("Resolution: %s" % res) print("Extent: %s" % str(extent)) print("Projection: '%s'" % t_srs.ExportToProj4()) print("Resampling alg: %s\n" % r) out_ds_list = [] for i, ds in enumerate(src_ds_list): fn_list = ds.GetFileList() fn = '[memory]' if fn_list is not None: fn = fn_list[0] if verbose: print("%i of %i: %s" % (i+1, len(src_ds_list), fn)) #If input srs are different, must warp ds_t_srs = geolib.get_ds_srs(ds) srscheck = bool(t_srs.IsSame(ds_t_srs)) if debug: print('\n%s' % ds_t_srs.ExportToWkt()) print('%s\n' % t_srs.ExportToWkt()) print('srscheck: %s\n' % srscheck) rescheck = False extentcheck = False #if srscheck: #Extract info from ds to see if warp is necessary ds_res = geolib.get_res(ds, square=True)[0] ds_extent = geolib.ds_extent(ds) #Note: these checks necessary to handle rounding and precision issues #Round extent and res to nearest mm precision = 1E-3 #Or if t_srs has units of degrees if ds_t_srs.IsGeographic(): precision = 1E-8 rescheck = (res is None) or geolib.res_compare(res, ds_res, precision=precision) extentcheck = (extent is None) or geolib.extent_compare(extent, ds_extent, precision=precision) if debug: print('\n%s, %s\n' % (ds_res, res)) print('%s' % ds_extent) print('%s\n' % extent) print('rescheck: %s' % rescheck) print('extentcheck: %s\n' % extentcheck) #If the ds passes all three, it is identical to desired output, short circuit if rescheck and extentcheck and srscheck: out_ds_list.append(ds) else: dst_ds = warptype(ds, res, extent, t_srs, r, outdir, dst_ndv=dst_ndv, verbose=verbose) out_ds_list.append(dst_ds) return out_ds_list
def bma_fig(fig, bma, cmap='cpt_rainbow', clim=None, clim_perc=(2,98), bg=None, bg_perc=(2,98), n_subplt=1, subplt=1, label=None, title=None, cint=None, alpha=0.5, ticks=False, scalebar=None, ds=None, shp=None, imshow_kwargs={'interpolation':'nearest'}, cbar_kwargs={'extend':'both', 'orientation':'vertical', 'shrink':0.7, 'fraction':0.12, 'pad':0.02}, **kwargs): #We don't use the kwargs, just there to save parsing in main if clim is None: clim = malib.calcperc(bma, clim_perc) #Deal with masked cases if clim[0] == clim[1]: if clim[0] > bma.fill_value: clim = (bma.fill_value, clim[0]) else: clim = (clim[0], bma.fill_value) print "Colorbar limits (%0.1f-%0.1f%%): %0.3f %0.3f" % (clim_perc[0], clim_perc[1], clim[0], clim[1]) else: print "Colorbar limits: %0.3f %0.3f" % (clim[0], clim[1]) #Link all subplots for zoom/pan sharex = sharey = None if len(fig.get_axes()) > 0: sharex = sharey = fig.get_axes()[0] #Hack to catch situations with only 1 subplot, but a subplot number > 1 if n_subplt == 1: subplt = 1 #One row, multiple columns ax = fig.add_subplot(1, n_subplt, subplt, sharex=sharex, sharey=sharey) #This occupies the full figure #ax = fig.add_axes([0., 0., 1., 1., ]) #ax.patch.set_facecolor('black') ax.patch.set_facecolor('white') cmap_name = cmap cmap = plt.get_cmap(cmap_name) if 'inferno' in cmap_name: #Use a gray background cmap.set_bad('0.5', alpha=1) else: #This sets the nodata background to opaque black cmap.set_bad('k', alpha=1) #cmap.set_bad('w', alpha=1) #ax.set_title("Band %i" % subplt, fontsize=10) if title is not None: ax.set_title(title) #If a background image is provided, plot it first if bg is not None: #Note, 1 is opaque, 0 completely transparent #alpha = 0.6 #bg_perc = (4,96) bg_perc = (0.05, 99.95) #bg_perc = (1, 99) bg_alpha = 1.0 #bg_alpha = 0.5 bg_clim = malib.calcperc(bg, bg_perc) bg_cmap_name = 'gray' bg_cmap = plt.get_cmap(bg_cmap_name) if 'inferno' in cmap_name: bg_cmap.set_bad('0.5', alpha=1) else: bg_cmap.set_bad('k', alpha=1) #Set the overlay bad values to completely transparent, otherwise darkens the bg cmap.set_bad(alpha=0) bgplot = ax.imshow(bg, cmap=bg_cmap, clim=bg_clim, alpha=bg_alpha) imgplot = ax.imshow(bma, alpha=alpha, cmap=cmap, clim=clim, **imshow_kwargs) else: imgplot = ax.imshow(bma, cmap=cmap, clim=clim, **imshow_kwargs) gt = None if ds is not None: gt = np.array(ds.GetGeoTransform()) gt_scale_factor = min(np.array([ds.RasterYSize, ds.RasterXSize])/np.array(bma.shape,dtype=float)) gt[1] *= gt_scale_factor gt[5] *= gt_scale_factor ds_srs = geolib.get_ds_srs(ds) if ticks: scale_ticks(ax, ds) else: pltlib.hide_ticks(ax) xres = geolib.get_res(ds)[0] else: pltlib.hide_ticks(ax) #This forces the black line outlining the image subplot to snap to the actual image dimensions ax.set_adjustable('box-forced') cbar = True if cbar: #Had to turn off the ax=ax for overlay to work #cbar = fig.colorbar(imgplot, ax=ax, extend='both', shrink=0.5) #Should set the format based on dtype of input data #cbar_kwargs['format'] = '%i' #cbar_kwargs['format'] = '%0.1f' #cbar_kwargs['orientation'] = 'horizontal' #cbar_kwargs['shrink'] = 0.8 cbar = pltlib.add_cbar(ax, imgplot, label=label, cbar_kwargs=cbar_kwargs) #Plot contours every cint interval and update colorbar appropriately if cint is not None: if bma_c is not None: bma_clim = malib.calcperc(bma_c) #PIG bed ridge contours #bma_clim = (-1300, -300) #Jak front shear margin contours #bma_clim = (2000, 4000) cstart = int(np.floor(bma_clim[0] / cint)) * cint cend = int(np.ceil(bma_clim[1] / cint)) * cint else: #cstart = int(np.floor(bma.min() / cint)) * cint #cend = int(np.ceil(bma.max() / cint)) * cint cstart = int(np.floor(clim[0] / cint)) * cint cend = int(np.ceil(clim[1] / cint)) * cint #Turn off dashed negative (beds are below sea level) #matplotlib.rcParams['contour.negative_linestyle'] = 'solid' clvl = np.arange(cstart, cend+1, cint) #contours = ax.contour(bma_c, colors='k', levels=clvl, alpha=0.5) contours = ax.contour(bma_c, cmap='gray', linestyle='--', levels=clvl, alpha=1.0) #Update the cbar with contour locations cbar.add_lines(contours) cbar.set_ticks(contours.levels) #Plot shape overlay, moved code to pltlib if shp is not None: pltlib.shp_overlay(ax, ds, shp, gt=gt) if scalebar: scale_ticks(ax, ds) pltlib.add_scalebar(ax, xres) if not ticks: pltlib.hide_ticks(ax) #imgplot.set_cmap(cmap) #imgplot.set_clim(clim) global gbma gbma = bma global ggt ggt = gt #Clicking on a subplot will make it active for z-coordinate display fig.canvas.mpl_connect('button_press_event', onclick) fig.canvas.mpl_connect('axes_enter_event', enter_axis) #Add support for interactive z-value display ax.format_coord = format_coord
def main(): parser = getparser() #Create dictionary of arguments args = vars(parser.parse_args()) #Want to enable -full when -of is specified, probably a fancy way to do this with argparse if args['of']: args['full'] = True args['imshow_kwargs'] = pltlib.imshow_kwargs #Need to implement better extent handling for link and overlay #Can use warplib extent parsing extent = 'first' #extent = 'union' #Should accept 'ts' or 'fn' or string here, default is 'ts' #Can also accept list for subplots title = args['title'] if args['link']: fig = plt.figure(0) n_ax = len(args['filelist']) src_ds_list = [gdal.Open(fn) for fn in args['filelist']] t_srs = geolib.get_ds_srs(src_ds_list[0]) res_stats = geolib.get_res_stats(src_ds_list, t_srs=t_srs) #Use min res res = res_stats[0] extent = 'intersection' extent = geolib.ds_geom_union_extent(src_ds_list, t_srs=t_srs) #extent = geolib.ds_geom_intersection_extent(src_ds_list, t_srs=t_srs) #print(res, extent) for n, fn in enumerate(args['filelist']): if not iolib.fn_check(fn): print('Unable to open input file: %s' % fn) continue if title == 'ts': ts = timelib.fn_getdatetime_list(fn) if ts: print("Timestamp list: ", ts) if len(ts) == 1: args['title'] = ts[0].date() elif len(ts) > 1: args['title'] = "%s to %s" % (ts[0].date(), ts[1].date()) else: print("Unable to extract timestamp") args['title'] = None elif title == 'fn': args['title'] = fn #if title is not None: # plt.title(title, fontdict={'fontsize':12}) #Note: this won't work if img1 has 1 band and img2 has 3 bands #Hack for now if not args['link']: fig = plt.figure(n) n_ax = 1 #fig.set_facecolor('black') fig.set_facecolor('white') fig.canvas.set_window_title(os.path.split(fn)[1]) #fig.suptitle(os.path.split(fn)[1], fontsize=10) if args['overlay']: #Should automatically search for shaded relief with same base fn #bg_fn = os.path.splitext(fn)[0]+'_hs_az315.tif' #Clip/warp background dataset to match overlay dataset src_ds, bg_ds = warplib.memwarp_multi_fn([fn, args['overlay']], extent=extent, res='max') #Want to load up the unique bg array for each input args['bg'] = get_bma(bg_ds, 1, args['full']) else: src_ds = gdal.Open(fn, gdal.GA_ReadOnly) if args['link']: src_ds = warplib.memwarp_multi([ src_ds, ], res=res, extent=extent, t_srs=t_srs)[0] args['cbar_kwargs'] = pltlib.cbar_kwargs if args['no_cbar']: args['cbar_kwargs'] = None nbands = src_ds.RasterCount b = src_ds.GetRasterBand(1) dt = gdal.GetDataTypeName(b.DataType) #Eventually, check dt of each band print("%s (%i bands)" % (fn, nbands)) #Singleband raster if (nbands == 1): if args['cmap'] is None: #Special case to handle ASP float32 grayscale data if '-L_sub' in fn or '-R_sub' in fn: args['cmap'] = 'gray' else: if (dt == 'Float64') or (dt == 'Float32') or (dt == 'Int32'): args['cmap'] = 'cpt_rainbow' #This is for WV images elif (dt == 'UInt16'): args['cmap'] = 'gray' elif (dt == 'Byte'): args['cmap'] = 'gray' else: args['cmap'] = 'cpt_rainbow' """ if 'count' in fn: args['clim_perc'] = (0,100) cbar_kwargs['extend'] = 'neither' args['cmap'] = 'cpt_rainbow' if 'mask' in fn: args['clim'] = (0, 1) #Could be (0, 255) #args['clim_perc'] = (0,100) #Want absolute clim of 0, then perc of 100 cbar_kwargs['extend'] = 'neither' args['cmap'] = 'gray' """ bma = get_bma(src_ds, 1, args['full']) if args['invert']: bma *= -1 #Note n+1 here ensures we're assigning subplot correctly here (n is 0-relative, subplot is 1) bma_fig(fig, bma, n_subplt=n_ax, subplt=n + 1, ds=src_ds, **args) #3-band raster, likely disparity map #This doesn't work when alpha band is present elif (nbands == 3) and (dt == 'Byte'): #For some reason, tifs are vertically flipped if (os.path.splitext(fn)[1] == '.tif'): args['imshow_kwargs']['origin'] = 'lower' #Use gdal dataset here instead of imread(fn)? imgplot = plt.imshow(plt.imread(fn), **args['imshow_kwargs']) pltlib.hide_ticks(imgplot.axes) #Handle the 3-band disparity map case here #elif ((dt == 'Float32') or (dt == 'Int32')): else: if args['cmap'] is None: args['cmap'] = 'cpt_rainbow' bn = 1 while bn <= nbands: bma = get_bma(src_ds, bn, args['full']) bma_fig(fig, bma, n_subplt=nbands, subplt=bn, ds=src_ds, **args) bn += 1 #Want to be better about this else case - lazy for now #else: # bma = get_bma(src_ds, 1, args['full']) # bma_fig(fig, bma, **args) plt.tight_layout() #Write out the file #Note: make sure display is local for savefig if args['of']: outf = str(os.path.splitext(fn)[0]) + '_fig.' + args['of'] #outf = str(os.path.splitext(fn)[0])+'_'+str(os.path.splitext(args['overlay'])[0])+'_fig.'+args['of'] #Note: need to account for colorbar (12%) and title - some percentage of axes beyond bma dimensions #Should specify minimum text size for output max_size = np.array((10.0, 10.0)) max_dpi = 300.0 #If both outsize and dpi are specified, don't try to change, just make the figure if (args['outsize'] is None) and (args['dpi'] is None): args['dpi'] = 150.0 #Unspecified out figure size for a given dpi if (args['outsize'] is None) and (args['dpi'] is not None): args['outsize'] = np.array(bma.shape[::-1]) / args['dpi'] if np.any(np.array(args['outsize']) > max_size): args['outsize'] = max_size #Specified output figure size, no specified dpi elif (args['outsize'] is not None) and (args['dpi'] is None): args['dpi'] = np.min([ np.max( np.array(bma.shape[::-1]) / np.array(args['outsize'])), max_dpi ]) print() print("Saving output figure:") print("Filename: ", outf) print("Size (in): ", args['outsize']) print("DPI (px/in): ", args['dpi']) print("Input dimensions (px): ", bma.shape[::-1]) print("Output dimensions (px): ", tuple(np.array(args['outsize']) * args['dpi'])) print() fig.set_size_inches(args['outsize']) #fig.set_size_inches(54.427, 71.87) #fig.set_size_inches(40, 87) fig.savefig(outf, dpi=args['dpi'], bbox_inches='tight', pad_inches=0, facecolor=fig.get_facecolor(), edgecolor='none') #fig.savefig(outf, dpi=args['dpi'], facecolor=fig.get_facecolor(), edgecolor='none') #Show the plot - want to show all at once if not args['of']: plt.show()
def shp_overlay(ax, ds, shp_fn, gt=None, color='darkgreen'): from osgeo import ogr from pygeotools.lib import geolib #ogr2ogr -f "ESRI Shapefile" output.shp input.shp -clipsrc xmin ymin xmax ymax shp_ds = ogr.Open(shp_fn) lyr = shp_ds.GetLayer() lyr_srs = lyr.GetSpatialRef() lyr.ResetReading() nfeat = lyr.GetFeatureCount() #Note: this is inefficient for large numbers of features #Should produce collections of points or lines, then have single plot call for n, feat in enumerate(lyr): geom = feat.GetGeometryRef() geom_type = geom.GetGeometryType() #Points if geom_type == 1: mX, mY, z = geom.GetPoint() attr = {'marker':'o', 'markersize':5, 'linestyle':'None'} #Line elif geom_type == 2: l, mX, mY = geolib.line2pts(geom) z = 0 #attr = {'marker':None, 'linestyle':'-', 'linewidth':0.5, 'alpha':0.8} attr = {'marker':None, 'linestyle':'-', 'linewidth':1.0, 'alpha':0.8} #attr = {'marker':'.', 'markersize':0.5, 'linestyle':'None'} #Polygon, placeholder #Note: this should be done with the matplotlib patch functionality #http://matplotlib.org/users/path_tutorial.html elif geom_type == 3: print("Polygon support not yet implemented") #ogr2ogr -nlt LINESTRING out.shp in.shp l, mX, mY = geolib.line2pts(geom) z = 0 attr = {'marker':None, 'linestyle':'-', 'facecolor':'w'} ds_srs = geolib.get_ds_srs(ds) if gt is None: gt = ds.GetGeoTransform() if not lyr_srs.IsSame(ds_srs): mX, mY, z = geolib.cT_helper(mX, mY, z, lyr_srs, ds_srs) #ds_extent = geolib.ds_extent(ds) ds_extent = geolib.ds_geom_extent(ds) mX = np.ma.array(mX) mY = np.ma.array(mY) mX[mX < ds_extent[0]] = np.ma.masked mX[mX > ds_extent[2]] = np.ma.masked mY[mY < ds_extent[1]] = np.ma.masked mY[mY > ds_extent[3]] = np.ma.masked mask = np.ma.getmaskarray(mY) | np.ma.getmaskarray(mX) mX = mX[~mask] mY = mY[~mask] if mX.count() > 0: ax.set_autoscale_on(False) if geom_type == 1: pX, pY = geolib.mapToPixel(np.array(mX), np.array(mY), gt) ax.plot(pX, pY, color=color, **attr) else: l = np.ma.array(l) l = l[~mask] lmed = np.ma.median(np.diff(l)) lbreaks = (np.diff(l) > lmed*2).nonzero()[0] if lbreaks.size: a = 0 lbreaks = list(lbreaks) lbreaks.append(l.size) for b in lbreaks: mmX = mX[a:b+1] mmY = mY[a:b+1] a = b+1 #import ipdb; ipdb.set_trace() #pX, pY = geolib.mapToPixel(np.array(mX), np.array(mY), gt) pX, pY = geolib.mapToPixel(mmX, mmY, gt) print(n, np.diff(pX).max(), np.diff(pY).max()) #ax.plot(pX, pY, color='LimeGreen', **attr) #ax.plot(pX, pY, color='LimeGreen', alpha=0.5, **attr) #ax.plot(pX, pY, color='w', alpha=0.5, **attr) ax.plot(pX, pY, color=color, **attr) else: pX, pY = geolib.mapToPixel(np.array(mX), np.array(mY), gt) ax.plot(pX, pY, color=color, **attr)
#mask_key = key+'mask' #mask = mask_mat[mask_key].T else: print "Unrecognized extension, continuing without filtering or scaling" #Parse GCPs gcp_fn = os.path.splitext(in_fn)[0]+'.gcp' gcp = parse_gcp(gcp_fn) #Load DEM #Should be in projected, cartesian coords dem_fn = sys.argv[3] #Extract DEM to ma dem_ds = iolib.fn_getds(dem_fn) dem_srs = geolib.get_ds_srs(dem_ds) dem_gt = dem_ds.GetGeoTransform() dem = iolib.ds_getma(dem_ds) #Compute azimuth pixel size in meters (function of range) az_pixel_spacing = az_angle_step * np.arange(near_range_slc, far_range_slc, range_pixel_spacing) #Downsample DEM to match radar GSD, or 2x radar GSD? #min(range, az) #Want to allow for input more precise DGPS coordinates for GPRI origin #Trimble GeoXH shp output has XY, need to process raw data for XYZ #46.78364631 #-121.7502352 #ref_coord = [-121.7502352, 46.78364631, ref_coord[2]] #Need to correct boresight for "principal point" of radar relative to GPS point at top of tower - this will depend on antenna used for interferogram