Exemple #1
0
def main():
    parser = getparser()
    args = parser.parse_args()

    ras_fn = args.ras_fn
    min = args.min
    max = args.max

    print("Loading dz raster into masked array")
    ras_ds = iolib.fn_getds(ras_fn)
    ras = iolib.ds_getma(ras_ds, 1)
    #Cast input ma as float32 so np.nan filling works
    ras = ras.astype(np.float32)
    ras_fltr = ras

    #Absolute range filter
    ras_fltr = filtlib.range_fltr(ras_fltr, (min, max))

    if args.stats:
        print("Input dz raster stats:")
        malib.print_stats(ras)
        print("Filtered dz raster stats:")
        malib.print_stats(ras_fltr)

    #Output filename will have 'filt' appended
    dst_fn = os.path.splitext(ras_fn)[0] + '_filt.tif'

    print("Writing out filtered dz raster: %s" % dst_fn)
    #Note: writeGTiff writes ras_fltr.filled()
    iolib.writeGTiff(ras_fltr, dst_fn, ras_ds)
Exemple #2
0
def gen_ts_fn(fn, dt_ref=None, ma=False):
    from osgeo import gdal
    from pygeotools.lib import iolib
    print("Generating timestamp for: %s" % fn)
    fn_ts = os.path.splitext(fn)[0] + '_ts.tif'
    if not os.path.exists(fn_ts) or dt_ref is not None:
        ds = gdal.Open(fn)
        #Should be ok with float ordinals here
        a = iolib.ds_getma(ds)
        ts = fn_getdatetime(fn)
        #Want to check that dt_ref is valid datetime object
        if dt_ref is not None:
            t = ts - dt_ref
            t = t.total_seconds() / 86400.
            fn_ts = os.path.splitext(fn)[0] + '_ts_rel.tif'
        else:
            t = dt2o(ts)
        a[~np.ma.getmaskarray(a)] = t
        #Probably want to be careful about ndv here - could be 0 for rel
        #ndv = 1E20
        ndv = -9999.0
        a.set_fill_value(ndv)
        iolib.writeGTiff(a, fn_ts, ds)
    if ma:
        return a
    else:
        return fn_ts
Exemple #3
0
def get_nlcd_mask(nlcd_ds, filter='not_forest', out_fn=None):
    """Generate raster mask for specified NLCD LULC filter
    """
    print("Loading NLCD LULC")
    b = nlcd_ds.GetRasterBand(1)
    l = b.ReadAsArray()
    print("Filtering NLCD LULC with: %s" % filter)
    #Original nlcd products have nan as ndv
        #12 - ice
        #31 - rock
        #11 - open water, includes rivers
        #52 - shrub, <5 m tall, >20%
        #42 - evergreeen forest
    #Should use data dictionary here for general masking
    #Using 'rock+ice+water' preserves the most pixels, although could be problematic over areas with lakes
    if filter == 'rock':
        mask = (l==31)
    elif filter == 'rock+ice':
        mask = np.logical_or((l==31),(l==12))
    elif filter == 'rock+ice+water':
        mask = np.logical_or(np.logical_or((l==31),(l==12)),(l==11))
    elif filter == 'not_forest':
        mask = ~(np.logical_or(np.logical_or((l==41),(l==42)),(l==43)))
    elif filter == 'not_forest+not_water':
        mask = ~(np.logical_or(np.logical_or(np.logical_or((l==41),(l==42)),(l==43)),(l==11)))
    else:
        print("Invalid mask type")
        mask = None
    #Write out original data
    if out_fn is not None:
        print("Writing out %s" % out_fn)
        iolib.writeGTiff(l, out_fn, nlcd_ds)
    l = None
    return mask
Exemple #4
0
def main():
    parser = argparse.ArgumentParser(description="Clip input raster by input shp polygons")
    #Should add support for similar arguments as in warplib - arbitrary extent, res, etc
    parser.add_argument('-extent', type=str, default='raster', choices=['raster','shp'], \
                        help='Desired output extent')
    parser.add_argument('r_fn', type=str, help='Input raster filename')
    parser.add_argument('shp_fn', type=str, help='Input shp filename')
    args = parser.parse_args()

    r_fn = args.r_fn
    if not os.path.exists(args.r_fn):
        sys.exit("Unable to find r_fn: %s" % r_fn)
        
    shp_fn = args.shp_fn
    if shp_fn == 'RGI' or shp_fn == 'rgi':
        from demcoreg.dem_mask import get_glacier_poly
        rgi_fn = get_glacier_poly() 
        shp_fn = rgi_fn

    if not os.path.exists(shp_fn):
        sys.exit("Unable to find shp_fn: %s" % shp_fn)

    extent=args.extent

    #Do the clipping
    r = raster_shpclip(r_fn, shp_fn, extent)

    #Write out
    out_fn = os.path.splitext(r_fn)[0]+'_shpclip.tif'
    #Note: passing r_fn here as the src_ds
    iolib.writeGTiff(r, out_fn, r_fn) 
def main():
    parser = getparser()
    args = parser.parse_args()

    r_fn = args.r_fn
    if not os.path.exists(r_fn):
        sys.exit("Unable to find r_fn: %s" % r_fn)

    shp_fn = args.shp_fn
    #Convenience shortcut to clip to glacier polygons (global shp)
    #Requires demcoreg package: https://github.com/dshean/demcoreg
    if shp_fn == 'RGI' or shp_fn == 'rgi':
        from demcoreg.dem_mask import get_glacier_poly
        rgi_fn = get_glacier_poly()
        shp_fn = rgi_fn

    if not os.path.exists(shp_fn):
        sys.exit("Unable to find shp_fn: %s" % shp_fn)

    extent = args.extent

    #Do the clipping
    r = geolib.raster_shpclip(r_fn, shp_fn, extent)

    #Write out
    out_fn = os.path.splitext(r_fn)[0] + '_shpclip.tif'
    #Note: passing r_fn here as the src_ds
    iolib.writeGTiff(r, out_fn, r_fn)
Exemple #6
0
def main():
    parser = getparser()
    args = parser.parse_args()

    src_fn = args.src_fn
    new_ndv = args.new_ndv

    #Input argument is a string, which is not recognized by set_fill_value
    #Must use np.nan object
    if new_ndv == 'nan' or new_ndv == 'np.nan':
        new_ndv = np.nan
    else:
        new_ndv = float(new_ndv)

    #Output filename will have ndv appended
    if args.overwrite:
        out_fn = src_fn
    else:
        out_fn = os.path.splitext(src_fn)[0] + '_ndv.tif'

    ds = gdal.Open(src_fn)
    b = ds.GetRasterBand(1)
    #Extract old ndv
    old_ndv = iolib.get_ndv_b(b)

    print(src_fn)
    print("Replacing old ndv %s with new ndv %s" % (old_ndv, new_ndv))

    #Load masked array
    bma = iolib.ds_getma(ds)
    #Set new fill value
    bma.set_fill_value(new_ndv)
    #Fill ma with new value and write out
    iolib.writeGTiff(bma.filled(), out_fn, ds, ndv=new_ndv)
Exemple #7
0
def main():
    parser = getparser()
    args = parser.parse_args()

    r_fn = args.r_fn
    if not os.path.exists(r_fn):
        sys.exit("Unable to find r_fn: %s" % r_fn)

    # r_fn to r_ds
    r_ds = iolib.fn_getds(r_fn)
    # ...to array
    r_arr = r_ds.GetRasterBand(1).ReadAsArray()

    r_arr = r_arr * args.scale_factor
    arr_out = r_arr.astype(getattr(
        np, args.out_type))  # this works like r_arr.astype(np.unit16)

    print "\tOutput array type: %s" % (arr_out.dtype)
    print "\tOutput nodata value: %s" % (args.nodata_val)
    # Set No Data Value: Deal with negatives and nan
    arr_out = np.where(arr_out < 0, args.nodata_val, arr_out)
    arr_out = np.where(np.isnan(arr_out), args.nodata_val, arr_out)

    #Write out
    out_fn = os.path.splitext(r_fn)[0] + '_' + args.out_type + '.tif'
    print "\tOutput file: %s" % (out_fn)
    #Note: passing r_fn here as the src_ds
    iolib.writeGTiff(arr_out, out_fn, r_fn)
Exemple #8
0
def main():
    parser = getparser()
    args = parser.parse_args()

    mask_list = []
    if args.toa: mask_list.append('toa') 
    if args.snodas: mask_list.append('snodas') 
    if args.modscag: mask_list.append('modscag') 
    if args.bareground: mask_list.append('bareground') 
    if args.glaciers: mask_list.append('glaciers') 
    if args.nlcd: mask_list.append('nlcd') 

    if not mask_list:
        parser.print_help()
        sys.exit("Must specify at least one mask type")

    #This directory should or will contain the relevant data products
    #if args.datadir is None:
    #    datadir = iolib.get_datadir() 

    dem_fn = args.dem_fn
    dem_ds = gdal.Open(dem_fn)
    print(dem_fn)

    #Get DEM masked array
    dem = iolib.ds_getma(dem_ds)
    print("%i valid pixels in original input tif" % dem.count())

    #Set up cascading mask preparation
    #True (1) represents "valid" unmasked pixel, False (0) represents "invalid" pixel to be masked
    #Initialize the mask
    #newmask = ~(np.ma.getmaskarray(dem))

    #Basename for output files
    if args.outdir is not None:
        if not os.path.exists(args.outdir):
            os.makedirs(args.outdir)
    else:
        args.outdir = os.path.split(dem_fn)[0]
    
    newmask = get_mask(dem_ds, mask_list, dem_fn=dem_fn, writeout=args.writeout, outdir=args.outdir, args=args)
    
    #Apply mask to original DEM - use these surfaces for co-registration
    newdem = np.ma.array(dem, mask=newmask)

    #Check that we have enough pixels, good distribution
    min_validpx_count = 100
    min_validpx_std = 10
    validpx_count = newdem.count()
    validpx_std = newdem.std()
    print("%i valid pixels in masked output tif to be used as ref" % validpx_count)
    print("%0.2f std in masked output tif to be used as ref" % validpx_std)
    #if (validpx_count > min_validpx_count) and (validpx_std > min_validpx_std):
    if (validpx_count > min_validpx_count):
        out_fn = os.path.join(args.outdir, os.path.splitext(dem_fn)[0]+'_ref.tif')
        print("Writing out %s" % out_fn)
        iolib.writeGTiff(newdem, out_fn, src_ds=dem_ds)
    else:
        print("Not enough valid pixels!")
Exemple #9
0
def main():

    parser = getparser()
    args = parser.parse_args()
    dem_fn = args.dem_fn
    ndv = args.ndv
    max_slope = args.max_slope
    reduce_pct = args.reduce_pct
    #slope_res = args.slope_res

    slopelim = (0.1, max_slope)

    out_base = os.path.splitext(dem_fn)[0]

    print "\n\tGetting a slopemasked dem...\n"

    if reduce_pct != 100:
        print "\tCoarsening by %s.." % (reduce_pct)
        out_fn = out_base + '_pct' + str(reduce_pct) + '.tif'
        if not os.path.exists(out_fn):
            red_pct_str = str(reduce_pct) + "% " + str(reduce_pct) + "%"
            cmdStr = " ".join([
                "gdal_translate", "-r", "cubic", "-outsize", red_pct_str,
                dem_fn, out_fn
            ])
            print cmdStr
            #cmdStr = "gdal_translate -r cubic -outsize " + str(reduce_pct) + "% " + str(reduce_pct) + "%"
            #cmdStr += dem_fn + out_fn
            cmd = subprocess.Popen(cmdStr, stdout=subprocess.PIPE, shell=True)
            stdOut, err = cmd.communicate()

            dem_fn = out_fn

    # Get slope as a masked array
    dem_slope_ma = geolib.gdaldem_wrapper(dem_fn,
                                          product='slope',
                                          returnma=True)

    # Get reduced dem ds
    dem_ds = iolib.fn_getds(dem_fn)
    dem_ma = iolib.ds_getma(dem_ds)

    # Get a new slope ma using max slope
    slopemask = (dem_slope_ma > max_slope)

    # Get whichever dem ma was there in the first place
    demmask = (dem_ma == ndv)
    newmask = np.logical_or(demmask, slopemask)

    # Apply mask from slope to slope
    newdem = np.ma.array(dem_ma, mask=newmask)

    # Save the new masked DEM
    dst_fn = out_base + '_slopemasked.tif'
    iolib.writeGTiff(newdem, dst_fn, dem_ds, ndv=ndv)

    return dst_fn
Exemple #10
0
def mask_nlcd(ds,
              valid='rock+ice+water',
              datadir=None,
              mask_glaciers=True,
              out_fn=None):
    """Generate raster mask for exposed rock in NLCD data
    """
    print("Loading NLCD LULC")
    b = ds.GetRasterBand(1)
    l = b.ReadAsArray()
    print("Filtering NLCD LULC")
    #Original nlcd products have nan as ndv
    #12 - ice
    #31 - rock
    #11 - open water, includes rivers
    #52 - shrub, <5 m tall, >20%
    #42 - evergreeen forest
    #Should use data dictionary here for general masking
    #Using 'rock+ice+water' preserves the most pixels, although could be problematic over areas with lakes
    if valid == 'rock':
        mask = (l == 31)
    elif valid == 'rock+ice':
        mask = np.logical_or((l == 31), (l == 12))
    elif valid == 'rock+ice+water':
        mask = np.logical_or(np.logical_or((l == 31), (l == 12)), (l == 11))
    elif valid == 'not_forest':
        mask = ~(np.logical_or(np.logical_or((l == 41), (l == 42)), (l == 43)))
    elif valid == 'not_forest+not_water':
        mask = ~(np.logical_or(
            np.logical_or(np.logical_or((l == 41), (l == 42)), (l == 43)),
            (l == 11)))
    else:
        print("Invalid mask type")
        mask = None
    #Write out original data
    if out_fn is not None:
        print("Writing out %s\n" % out_fn)
        iolib.writeGTiff(l, out_fn, ds)
    l = None
    if mask_glaciers:
        if datadir is None:
            datadir = iolib.get_datadir()
        #Note: RGI6.0 includes Fountain's 24K polygons, no longer need to maintain two separate shp
        #Use updated 24k glacier outlines
        #glac_shp_fn = os.path.join(datadir, 'conus_glacierpoly_24k/conus_glacierpoly_24k_32610.shp')
        #if not os.path.exists(glac_shp_fn):
        #    glac_shp_fn = None
        glac_shp_fn = None
        icemask = get_icemask(ds, datadir=datadir, glac_shp_fn=glac_shp_fn)
        if icemask is not None:
            mask *= icemask
    return mask
Exemple #11
0
def proc_modscag(fn_list, extent=None, t_srs=None):
    """Process the MODSCAG products for full date range, create composites and reproject
    """
    #Use cubic spline here for improve upsampling 
    ds_list = warplib.memwarp_multi_fn(fn_list, res='min', extent=extent, t_srs=t_srs, r='cubicspline')
    stack_fn = os.path.splitext(fn_list[0])[0] + '_' + os.path.splitext(os.path.split(fn_list[-1])[1])[0] + '_stack_%i' % len(fn_list) 
    #Create stack here - no need for most of mastack machinery, just make 3D array
    #Mask values greater than 100% (clouds, bad pixels, etc)
    ma_stack = np.ma.array([np.ma.masked_greater(iolib.ds_getma(ds), 100) for ds in np.array(ds_list)], dtype=np.uint8)

    stack_count = np.ma.masked_equal(ma_stack.count(axis=0), 0).astype(np.uint8)
    stack_count.set_fill_value(0)
    stack_min = ma_stack.min(axis=0).astype(np.uint8)
    stack_min.set_fill_value(0)
    stack_max = ma_stack.max(axis=0).astype(np.uint8)
    stack_max.set_fill_value(0)
    stack_med = np.ma.median(ma_stack, axis=0).astype(np.uint8)
    stack_med.set_fill_value(0)

    out_fn = stack_fn + '_count.tif'
    iolib.writeGTiff(stack_count, out_fn, ds_list[0])
    out_fn = stack_fn + '_max.tif'
    iolib.writeGTiff(stack_max, out_fn, ds_list[0])
    out_fn = stack_fn + '_min.tif'
    iolib.writeGTiff(stack_min, out_fn, ds_list[0])
    out_fn = stack_fn + '_med.tif'
    iolib.writeGTiff(stack_med, out_fn, ds_list[0])

    ds = gdal.Open(out_fn)
    return ds
def domask(tile_fn):
    prefix = '-'.join(tile_fn.split('-')[:-1])
    print("\nLoading: %s" % tile_fn)
    #dem_fn = prefix+'-median.tif'
    dem_fn = tile_fn
    dem_ds = iolib.fn_getds(dem_fn)
    dem = iolib.ds_getma(dem_ds)

    #Get original mask, True where masked
    mask = np.ma.getmaskarray(dem)
    valid_px_count = (~mask).sum()
    if valid_px_count < 1:
        print("No valid pixels remain")
    else:
        print("Valid pixel count: %i" % valid_px_count)
        min_count = 2
        count_fn = prefix + '-count.tif'
        print("Loading: %s" % count_fn)
        count = iolib.fn_getma(count_fn)
        print("min: %i max: %i" % (count.min(), count.max()))
        print("Masking: (count < %i)" % min_count)
        mask = np.logical_or(mask, (count < min_count))
        valid_px_count = (~mask).sum()
        if valid_px_count < 1:
            print("No valid pixels remain")
        else:
            print("Valid pixel count: %i" % valid_px_count)

            max_std = 3.0
            #std_fn = prefix+'-std.tif'
            std_fn = prefix + '-nmad.tif'
            print("Loading: %s" % std_fn)
            std = iolib.fn_getma(std_fn)
            print("min: %i max: %i" % (std.min(), std.max()))
            print("Masking: (std/nmad >= %i)" % max_std)
            mask = np.logical_or(mask, (std >= max_std))
            valid_px_count = (~mask).sum()
            if valid_px_count < 1:
                print("No valid pixels remain")
            else:
                print("Valid pixel count: %i" % valid_px_count)

    #Modified so we always write out, even if empty tif
    #Easier for tracking progress
    print("Applying mask")
    dem_masked = np.ma.array(dem, mask=mask)
    out_fn = os.path.splitext(dem_fn)[0] + '_masked.tif'
    print("Writing: %s" % out_fn)
    iolib.writeGTiff(dem_masked, out_fn, dem_ds)
Exemple #13
0
def get_bareground_mask(bareground_ds, bareground_thresh=60, out_fn=None):
    """Generate raster mask for exposed bare ground from global bareground data
    """
    print("Loading bareground")
    b = bareground_ds.GetRasterBand(1)
    l = b.ReadAsArray()
    print("Masking pixels with <%0.1f%% bare ground" % bareground_thresh)
    if bareground_thresh < 0.0 or bareground_thresh > 100.0:
        sys.exit("Invalid bare ground percentage")
    mask = (l > bareground_thresh)
    #Write out original data
    if out_fn is not None:
        print("Writing out %s" % out_fn)
        iolib.writeGTiff(l, out_fn, bareground_ds)
    l = None
    return mask
Exemple #14
0
def main():

    parser = getparser()
    args = parser.parse_args()
    dem_fn = args.dem_fn
    ndv = args.ndv
    max_slope = args.max_slope
    reduce_pct = args.reduce_pct
    #slope_res = args.slope_res

    slopelim = (0.1, max_slope)

    print "\n\tGetting masked slope of input dem..."

    #Get a coarsened version of DEM on which to calc slope
    dem_fn_reduced = os.path.splitext(dem_fn)[0] + '_' + str(
        reduce_pct) + 'pct.vrt'
    #dem_fn_reduced = os.path.splitext(dem_fn)[0]+'_'+ str(slope_res) +'m.vrt'

    #print "\tReducing percent by %s..." %(str(reduce_pct))
    run_os("gdal_translate -of VRT -r cubic -outsize " + str(reduce_pct) +
           "% " + str(reduce_pct) + "% " + dem_fn + " " + dem_fn_reduced)
    #run_os("gdal_translate -of VRT -r cubic -tr " + str(slope_res) + "% " + str(slope_res) + "% " + dem_fn + " " + dem_fn_reduced)

    # Run slope
    dem_slope_fn = geolib.gdaldem_wrapper(dem_fn_reduced,
                                          product='slope',
                                          returnma=False)

    # Get original ma and ds
    dem_slope = iolib.fn_getma(dem_slope_fn)
    dem_slope_ds = iolib.fn_getds(dem_slope_fn)

    # Apply mask from slope to slope
    dem_slope = np.ma.array(dem_slope,
                            mask=np.ma.masked_outside(dem_slope,
                                                      *slopelim).mask,
                            keep_mask=True,
                            fill_value=dem_slope.fill_value)

    # Save the filtered slope dataset
    dst_fn = os.path.splitext(dem_slope_fn)[0] + '_mask.tif'
    iolib.writeGTiff(dem_slope, dst_fn, dem_slope_ds, ndv=ndv)
    run_os("rm -fv " + dem_slope_fn)

    return dst_fn
Exemple #15
0
def mask_slope(ds, maxslope=10, out_fn=None):
    """Generate raster mask for slope from input slope
    """
    print("Loading slope")
    b = ds.GetRasterBand(1)
    l = b.ReadAsArray()
    print("Masking pixels with >%0.1f%% slopes\n" % maxslope)
    if maxslope < 0.0 or maxslope > 90.0:
        sys.exit("Invalid slope in degrees")
    mask = (l < maxslope)
    #Write out original data
    if out_fn is not None:
        print("Writing out %s\n" % out_fn)
        iolib.writeGTiff(l, out_fn, ds)
    l = None

    return mask
Exemple #16
0
def main():
    parser = getparser()
    args = parser.parse_args()
 
    dem_fn = args.dem_fn
    weight = args.weight
    poly_order = args.order

    # Get original DEM
    array_dem = iolib.fn_getma(dem_fn)
    dem_ds = iolib.fn_getds(dem_fn)

    # Create empty meshgrid
    x = range (0, dem_ds.RasterXSize, 1)
    y = range (0, dem_ds.RasterYSize, 1)
    X, Y = np.meshgrid(x, y)

    print "\nGet the gradient of the dem..."
    dzdy,dzdx = np.gradient(array_dem)

    print "\nCreate copies for modification, and set the masked areas to 0 in the gradients..."
    dzdx_mod = dzdx.copy()
    dzdy_mod = dzdy.copy()
    
    print "\nOsmanoglu Algorithm..."
    #routine to get the scale corrected surface back from gradients.
    #Note that this is with the original slopes, I want the result to be close to the original DEM as possible
    fco_dem = frankotchellappaosmanoglu(dzdx, dzdy) ; #FrankotChellappa removes long wavelength trends

    print "\nSubtract the recovered DEM from the original and estimate a surface..."
    planefit, fitfunc = fitSurface(X.ravel(), Y.ravel(), (array_dem - fco_dem).ravel())

    print "\nAdd the surface to the masked gradient derived DEM..."
    dem_interp = frankotchellappaosmanoglu(dzdx_mod, dzdy_mod) + fitfunc(planefit, X, Y, weight, poly_order)


    print("\nWriting DEM with interpolated surfaces:")
    dst_fn = os.path.splitext(dem_fn)[0]+'_interp.tif'
    print(dst_fn)
    iolib.writeGTiff(dem_interp, dst_fn, dem_ds)

    return dst_fn

    # Return a numpy masked array
    return dem_interp
Exemple #17
0
def main():
    parser = getparser()
    args = parser.parse_args()

    src_fn = args.src_fn
    if not iolib.fn_check(src_fn):
        sys.exit("Unable to find src_fn: %s" % src_fn)

    #This is a wrapper around gdal.Open()
    src_ds = iolib.fn_getds(src_fn)
    src_gt = src_ds.GetGeoTransform()

    print("Loading input raster into masked array")
    bma = iolib.ds_getma(src_ds)

    print("Computing min/max indices for mask")
    edge_env = malib.edgefind2(bma, intround=True)

    print("Updating output geotransform")
    out_gt = list(src_gt)
    #This should be OK, as edge_env values are integer multiples, and the initial gt values are upper left pixel corner
    #Update UL_X
    out_gt[0] = src_gt[0] + src_gt[1] * edge_env[2]
    #Update UL_Y, note src_gt[5] is negative
    out_gt[3] = src_gt[3] + src_gt[5] * edge_env[0]
    out_gt = tuple(out_gt)

    #debug
    #print([0, bma.shape[0], 0, bma.shape[1]])
    #print(edge_env)
    #print(src_gt)
    #print(out_gt)

    out_fn = os.path.splitext(src_fn)[0] + '_trim.tif'
    print("Writing out: %s" % out_fn)
    #Extract valid subsection from input array
    #indices+1 are necessary to include valid row/col on right and bottom edges
    iolib.writeGTiff(bma[edge_env[0]:edge_env[1] + 1,
                         edge_env[2]:edge_env[3] + 1],
                     out_fn,
                     src_ds,
                     gt=out_gt)
    bma = None
Exemple #18
0
def main():

    parser = getparser()
    args = parser.parse_args()
    chm_fn = args.chm_fn
    outdir = args.outdir
    ndv = args.ndv
    min_height = args.min_height
    max_height = args.max_height

    if not iolib.fn_check(chm_fn):
        sys.exit("Unable to find chm_fn: %s" % chm_fn)

    out_base = os.path.splitext(chm_fn)[0]
    if outdir is not None:
        inputdir, chmname = os.path.split(chm_fn)
        out_base = os.path.join(outdir, os.path.splitext(chmname)[0])

    # Get chm ds and ma
    chm_ds = iolib.fn_getds(chm_fn)
    chm_ma = iolib.ds_getma(chm_ds)

    # Get a new chm ma using max height
    heightmasklo = (chm_ma < min_height)
    heightmaskhi = (chm_ma > max_height)

    # Get whichever dem ma was there in the first place
    chmmask = (chm_ma == ndv)
    # https://stackoverflow.com/questions/20528328/numpy-logical-or-for-more-than-two-arguments
    newmask = np.logical_or.reduce(
        (chmmask, heightmasklo,
         heightmaskhi))  #np.logical_or(heightmasklo, heightmaskhi)

    # Apply mask
    newchm = np.ma.array(chm_ma, mask=newmask)

    # Save the new masked CHM
    dst_fn = out_base + '_htmasked.tif'
    iolib.writeGTiff(newchm, dst_fn, chm_ds, ndv=ndv)

    print(dst_fn)
    return dst_fn
def make_dem_mosaic_index_ts(index_tif_fn):
    index_txt_fn = index_tif_fn + '-index-map.txt'
    out_fn = os.path.splitext(index_tif_fn)[0] + '_ts.tif'

    if not os.path.exists(index_tif_fn):
        print("Unable to find input file: %s" % index_tif_fn)
        return False
    if not os.path.exists(index_txt_fn):
        print("Unable to find input file: %s" % index_txt_fn)
        return False
    if os.path.exists(out_fn):
        print("Existing ts output found: %s" % out_fn)
        return True

    #Load dem_mosaic index tif
    index_tif_ds = iolib.fn_getds(index_tif_fn)
    index_tif = iolib.ds_getma(index_tif_ds)

    #Create output array
    #index_ts_tif = np.zeros(index_tif.shape, dtype=np.float32)
    #index_ts_tif = np.ma.masked_all_like(index_tif)
    index_ts_tif = np.ma.masked_all(index_tif.shape, dtype=np.float32)

    #Read in dem_mosaic index txt file - should be "fn, index" for each record
    index_txt = np.atleast_2d(np.genfromtxt(index_txt_fn, dtype=str))

    #Extract Python datetime object from filename (should pull out YYYYMMDD_HHMM)
    index_ts = [timelib.fn_getdatetime(fn) for fn in index_txt[:, 0]]

    #Convert to desired output timestamp format
    #Python ordinal
    #index_ts = timelib.dt2o(index_ts)
    #YYYYMMDD integer
    #index_ts = [ts.strftime('%Y%m%d') for ts in index_ts]
    #Decimal year
    index_ts = [timelib.dt2decyear(ts) for ts in index_ts]

    for n, dt in enumerate(index_ts):
        index_ts_tif[index_tif == n] = dt

    iolib.writeGTiff(index_ts_tif, out_fn, index_tif_ds, ndv=0)
    return True
Exemple #20
0
def mask_bareground(ds, minperc=60, mask_glaciers=True, out_fn=None):
    """Generate raster mask for exposed bare ground from global bareground data
    """
    print("Loading bareground")
    b = ds.GetRasterBand(1)
    l = b.ReadAsArray()
    print("Masking pixels with <%0.1f%% bare ground\n" % minperc)
    if minperc < 0.0 or minperc > 100.0:
        sys.exit("Invalid bare ground percentage")
    mask = (l > minperc)
    #Write out original data
    if out_fn is not None:
        print("Writing out %s\n" % out_fn)
        iolib.writeGTiff(l, out_fn, ds)
    l = None
    if mask_glaciers:
        icemask = get_icemask(ds)
        if icemask is not None:
            mask *= icemask
    return mask
Exemple #21
0
def dz_fltr_dir(dem_fn_list, refdem_fn, abs_dz_lim, out_dir):
    #names = dem_fn_list[0]
    for names in dem_fn_list:
        #print("Loading ouput DEM into masked array")
        dem_ds = iolib.fn_getds(names)
        dem_fltr = iolib.ds_getma(dem_ds, 1)

        #Difference filter, need to specify refdem_fn
        dem_fltr = filtlib.dz_fltr(names, refdem_fn, abs_dz_lim)

        # create output directory and file name
        parts = names.split('/')
        file_name = parts[len(parts) - 1]

        dst_fn = out_dir + file_name.split(
            '.')[0] + '_filt%ipx.tif' % abs_dz_lim[1]

        print("Writing out filtered DEM: %s" % dst_fn)
        #Note: writeGTiff writes dem_fltr.filled()
        iolib.writeGTiff(dem_fltr, dst_fn, dem_ds)
Exemple #22
0
def main():
    parser = getparser()
    args = parser.parse_args()

    r_fn = args.r_fn
    if not os.path.exists(r_fn):
        sys.exit("Unable to find r_fn: %s" % r_fn)

    windowsize=args.windowsize

    # r_fn to r_ds
    r_ds = iolib.fn_getds(r_fn)
    r_arr = r_ds.GetRasterBand(1).ReadAsArray()

    # Creating data range
    #r_arr = np.ma.masked_outside(r_arr,0,100)   # mask all values outside this interval
    #r_arr = np.ma.masked_invalid(r_arr)       # mask all nan and inf values

    # Forget about masked arrays...just use np.where to put 0 for all invalid vals
    r_arr = np.where((r_arr > args.min) & (r_arr <= args.max), r_arr, 0)
    #myType=float
    #r_arr = r_arr.astype(myType)

    print "\tDoing moving window on array..."
    arr_out = moving_window(r_arr.astype(np.uint16), func=np.sum, window_size=windowsize)
    #r = filtlib.rolling_fltr(r_arr, f=np.sum, size=windowsize, circular=True)
    #r = gauss_fltr(r_arr, sigma=1)
    print "\tCheck array type OUTPUT from filter: %s" %(arr_out.dtype)
    # Deal with negatives and nan
    arr_out = np.where(arr_out < 0, -99, arr_out)
    arr_out = np.where(np.isnan(arr_out),-99, arr_out)

    #Write out
    win_str = "%02d" % (int(windowsize))
    out_fn = os.path.splitext(r_fn)[0]+'_win'+win_str+'sum.tif'
    #Note: passing r_fn here as the src_ds
    iolib.writeGTiff(arr_out, out_fn, r_fn)
Exemple #23
0
def main():
    start_time = timer()
    parser = getparser()
    args = parser.parse_args()

    r_fn = args.r_fn
    metric_list = args.metric_list.split(" ")
    win_size_list = args.win_size_list.split(" ")
    distance_list = args.distance_list.split(" ")

    print "\tGLCM metrics to be processed: %s" % metric_list

    if not os.path.exists(r_fn):
        sys.exit("Unable to find r_fn: %s" % r_fn)

    # r_fn to r_ds
    r_ds = iolib.fn_getds(r_fn)

    # ...to array
    r_arr = r_ds.GetRasterBand(1).ReadAsArray()

    # Forget about masked arrays...just use np.where to put 0 for all invalid vals
    r_arr = np.where((r_arr > 0.0) & (r_arr <= 1.0), r_arr, np.nan)

    # A way of checking the histograms of the orig image, and the scaled image
    # scale and set to to byte
    ##fit_GMM(r_arr, os.path.split(r_fn)[0], os.path.split(r_fn)[1], 5, 'float')
    ##r_arr = img_as_ubyte(r_arr)
    ##r_arr = img_as_uint(r_arr)
    ##fit_GMM(r_arr, os.path.split(r_fn)[0], os.path.split(r_fn)[1], 5, 'byte')
    end_readdata = timer()
    print "\tData: %s" % (os.path.basename(r_fn))
    print "\n\tTime to read in data: {} minutes\n".format(
        round(find_elapsed_time(start_time, end_readdata), 3))
    print "\tWindow sizes to be processed: %s" % win_size_list
    print "\tDistances to be processed: %s" % distance_list
    for win_size in win_size_list:
        print "\n\tWindow size: %s" % win_size
        win_size = int(win_size)

        for distance in distance_list:
            print "\tDistance: %s" % distance
            start_win_dist = timer()
            distance = int(distance)

            # Set up arrays to hold GLCM output
            #       these need to be float

            con = np.copy(r_arr).astype(np.float32)
            con[:] = 0
            dis = np.copy(r_arr).astype(np.float32)
            dis[:] = 0
            cor = np.copy(r_arr).astype(np.float32)
            cor[:] = 0
            asm = np.copy(r_arr).astype(np.float32)
            asm[:] = 0

            start_glcm = timer()
            print "\tCalculating GLCM and its properties..."
            # Loop over pixel windows (row and col, by win_size
            for i in range(con.shape[0]):
                print i,
                for j in range(con.shape[1]):

                    #windows needs to fit completely in image
                    if i < ((win_size - 1) / 2) or j < ((win_size - 1) / 2):
                        continue
                    if i > (con.shape[0] -
                            ((win_size + 1) / 2)) or j > (con.shape[0] - (
                                (win_size + 1) / 2)):
                        continue

                    #Calculate GLCM on a window
                    #
                    # converting to byte array right before GLCM processing
                    #       output arrays still with input precision
                    in_arr = img_as_ubyte(r_arr)
                    in_glcm_window_arr = in_arr[(i - ((win_size - 1) / 2)):(
                        i + ((win_size + 1) / 2)), (j - ((win_size - 1) / 2)):(
                            j + ((win_size + 1) / 2))]
                    del in_arr
                    out_glcm_window_arr = greycomatrix(in_glcm_window_arr, \
                                                        distances=[distance],\
                                                        #angles=[0, np.pi/4, np.pi/2, 3*np.pi/4],\
                                                        angles=[0],\
                                                        levels=256,  symmetric=True, normed=True )

                    con[i, j], dis[i, j], cor[i, j], asm[i, j] = [
                        greycoprops(out_glcm_window_arr, metric)
                        for metric in metric_list
                    ]

                    del out_glcm_window_arr

            end_glcm = timer()
            print "\n\tTime to compute this GLCM and its properties: {} minutes\n".format(
                round(find_elapsed_time(start_glcm, end_glcm), 3))

            out_glcm_list = [con, dis, cor, asm]

            for num, metric in enumerate(metric_list):
                out_fn = os.path.splitext(r_fn)[0] + '_TEXTij_win' + str(
                    win_size) + '_' + 'dist' + str(
                        distance) + '_' + metric + '.tif'
                print '\tWriting: %s' % (out_fn)
                iolib.writeGTiff(out_glcm_list[num], out_fn, r_fn)
            end_win_dist = timer()
            print "\tTotal compute time for GLCM on this window & distance: {} minutes\n".format(
                round(find_elapsed_time(start_win_dist, end_win_dist), 3))
Exemple #24
0
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)
Exemple #25
0
def main():
    parser = getparser()
    args = parser.parse_args()
    refdem = args.refdem
    srcdem = args.srcdem
    outfolder = '{}__{}_comparison_stats'.format(
        os.path.splitext(os.path.basename(refdem))[0],
        os.path.splitext(os.path.basename(srcdem))[0])
    header_str = '{}__{}'.format(
        os.path.splitext(os.path.basename(refdem))[0],
        os.path.splitext(os.path.basename(srcdem))[0])
    if not os.path.exists(outfolder):
        os.makedirs(outfolder)
    if args.local_ortho == 1:
        temp_ds = warplib.memwarp_multi_fn([refdem, srcdem])[0]
        bbox = geolib.ds_extent(temp_ds)
        geo_crs = temp_ds.GetProjection()
        print('Bounding box lon_lat is{}'.format(bbox))
        bound_poly = Polygon([[bbox[0], bbox[3]], [bbox[2], bbox[3]],
                              [bbox[2], bbox[1]], [bbox[0], bbox[1]]])
        bound_shp = gpd.GeoDataFrame(index=[0],
                                     geometry=[bound_poly],
                                     crs=geo_crs)
        bound_centroid = bound_shp.centroid
        cx = bound_centroid.x.values[0]
        cy = bound_centroid.y.values[0]
        pad = np.ptp([bbox[3], bbox[1]]) / 6.0
        lat_1 = bbox[1] + pad
        lat_2 = bbox[3] - pad
        local_ortho = "+proj=ortho +lat_1={} +lat_2={} +lat_0={} +lon_0={} +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs".format(
            lat_1, lat_2, cy, cx)
        logging.info('Local Ortho projection is {}'.format(local_ortho))
        t_srs = local_ortho
    else:
        t_srs = 'first'
    # this step performs the desired warping operation
    ds_list = warplib.memwarp_multi_fn([refdem, srcdem],
                                       res=args.comparison_res,
                                       t_srs=t_srs)
    refma = iolib.ds_getma(ds_list[0])
    srcma = iolib.ds_getma(ds_list[1])
    init_diff = refma - srcma
    init_stats = malib.get_stats_dict(init_diff)
    print("Original descriptive statistics {}".format(init_stats))
    init_diff_json_fn = os.path.join(
        outfolder, '{}_precoreg_descriptive_stats.json'.format(header_str))
    init_diff_json = json.dumps(init_stats)

    with open(init_diff_json_fn, 'w') as f:
        f.write(init_diff_json)
    logging.info("Saved initial stats at {}".format(init_diff_json))
    refslope = gdaldem(ds_list[0])
    # stats for elevation difference vs reference DEM elevation
    elev_bin, diff_mean, diff_median, diff_std, diff_perc = cummulative_profile(
        refma, init_diff, args.elev_bin_width)
    # stats for elevation difference vs reference DEM slope
    slope_bin, diff_mean_s, diff_median_s, diff_std_s, diff_perc_s = cummulative_profile(
        refslope, init_diff, args.slope_bin_width)
    f, ax = plt.subplots(1, 2, figsize=(10, 4))
    im = ax[0].scatter(elev_bin, diff_mean, c=diff_perc, cmap='inferno')
    ax[0].set_xlabel('Elevation (m)')
    divider = make_axes_locatable(ax[0])
    cax = divider.append_axes('right', size='2.5%', pad=0.05)
    plt.colorbar(im,
                 cax=cax,
                 orientation='vertical',
                 label='pixel count percentage')
    im2 = ax[1].scatter(slope_bin, diff_mean_s, c=diff_perc_s, cmap='inferno')
    ax[1].set_xlabel('Slope (degrees)')
    divider = make_axes_locatable(ax[1])
    cax = divider.append_axes('right', size='2.5%', pad=0.05)
    plt.colorbar(im2,
                 cax=cax,
                 orientation='vertical',
                 label='pixel count percentage')

    for axa in ax.ravel():
        axa.axhline(y=0, c='k')
        axa.set_ylabel('Elevation Difference (m)')
    plt.tight_layout()
    precoreg_plot = os.path.join(outfolder,
                                 header_str + '_precoreg_binned_plot.png')
    f.savefig(precoreg_plot, dpi=300, bbox_inches='tight', pad_inches=0.1)
    logging.info("Saved binned plot at {}".format(precoreg_plot))
    if args.coreg == 1:
        logging.info("will attempt coregisteration")
        if args.local_ortho == 1:
            ref_local_ortho = os.path.splitext(refdem)[0] + '_local_ortho.tif'
            src_local_ortho = os.path.splitext(srcdem)[0] + '_local_ortho.tif'
            # coregisteration works best at mean resolution
            # we will rewarp if the initial args.res was not mean
            if args.comparison_res != 'mean':
                ds_list = warplib.memwarp_multi_fn([refdem, srcdem],
                                                   res='mean',
                                                   t_srs=t_srs)
                refma = iolib.ds_getma(ds_list[0])
                srcma = iolib.ds_getma(ds_list[1])
            iolib.writeGTiff(refma, ref_local_ortho, ds_list[0])
            iolib.writeGTiff(srcma, src_local_ortho, ds_list[1])
            coreg_ref = ref_local_ortho
            src_ref = src_local_ortho
        else:
            coreg_ref = refdem
            src_ref = srcdem
        demcoreg_dir = os.path.join(outfolder, 'coreg_results')
        align_opts = [
            '-mode', 'nuth', '-max_iter', '12', '-max_offset', '400',
            '-outdir', demcoreg_dir
        ]
        align_args = [coreg_ref, src_ref]
        align_cmd = ['dem_align.py'] + align_opts + align_args
        subprocess.call(align_cmd)
        #ah final round of warping and stats calculation
        try:
            srcdem_align = glob.glob(os.path.join(demcoreg_dir,
                                                  '*align.tif'))[0]
            logging.info(
                "Attempting stats calculation for aligned DEM {}".format(
                    srcdem_align))
            ds_list = warplib.memwarp_multi_fn([args.refdem, srcdem_align],
                                               res=args.comparison_res,
                                               t_srs=t_srs)
            refma = iolib.ds_getma(ds_list[0])
            srcma = iolib.ds_getma(ds_list[1])
            # this is creepy, but I am recycling variable names to save on memory
            init_diff = refma - srcma
            init_stats = malib.get_stats_dict(init_diff)
            print("Final descriptive statistics {}".format(init_stats))
            init_diff_json_fn = os.path.join(
                outfolder,
                '{}_postcoreg_descriptive_stats.json'.format(header_str))
            init_diff_json = json.dumps(init_stats)

            with open(init_diff_json_fn, 'w') as f:
                f.write(init_diff_json)
            logging.info("Saved final stats at {}".format(init_diff_json))
            refslope = gdaldem(ds_list[0])
            # stats for elevation difference vs reference DEM elevation
            elev_bin, diff_mean, diff_median, diff_std, diff_perc = cummulative_profile(
                refma, init_diff, args.elev_bin_width)
            # stats for elevation difference vs reference DEM slope
            slope_bin, diff_mean_s, diff_median_s, diff_std_s, diff_perc_s = cummulative_profile(
                refslope, init_diff, args.slope_bin_width)
            f, ax = plt.subplots(1, 2, figsize=(10, 4))
            im = ax[0].scatter(elev_bin,
                               diff_mean,
                               c=diff_perc,
                               cmap='inferno')
            ax[0].set_xlabel('Elevation (m)')
            divider = make_axes_locatable(ax[0])
            cax = divider.append_axes('right', size='2.5%', pad=0.05)
            plt.colorbar(im,
                         cax=cax,
                         orientation='vertical',
                         label='pixel count percentage')
            im2 = ax[1].scatter(slope_bin,
                                diff_mean_s,
                                c=diff_perc_s,
                                cmap='inferno')
            ax[1].set_xlabel('Slope (degrees)')
            divider = make_axes_locatable(ax[1])
            cax = divider.append_axes('right', size='2.5%', pad=0.05)
            plt.colorbar(im2,
                         cax=cax,
                         orientation='vertical',
                         label='pixel count percentage')

            for axa in ax.ravel():
                axa.axhline(y=0, c='k')
                axa.set_ylabel('Elevation Difference (m)')
            plt.tight_layout()
            precoreg_plot = os.path.join(
                outfolder, header_str + '_postcoreg_binned_plot.png')
            f.savefig(precoreg_plot,
                      dpi=300,
                      bbox_inches='tight',
                      pad_inches=0.1)
        except:
            logging.info(
                "Failed to compute post coreg stats, see corresponding job log"
            )
        logging.info("Script is complete !")
Exemple #26
0
def main():
    parser = getparser()
    args = parser.parse_args()

    src_fn = args.src_fn
    if not iolib.fn_check(src_fn):
        sys.exit("Unable to find src_fn: %s" % src_fn)

    mask_fn = args.mask_fn
    if not iolib.fn_check(mask_fn):
        sys.exit("Unable to find mask_fn: %s" % mask_fn)

    #Determine output extent, default is input raster extent
    extent = args.extent
    if extent == 'raster':
        extent = src_fn
    elif extent == 'mask':
        extent = mask_fn
    else:
        #This is a hack for intersection computation
        src_ds_list = [
            gdal.Open(fn, gdal.GA_ReadOnly) for fn in [src_fn, mask_fn]
        ]
        #t_srs = geolib.get_ds_srs(src_ds_list[0])
        extent = warplib.parse_extent(extent, src_ds_list, src_fn)

    print("Warping mask_fn")
    mask_ds = warplib.memwarp_multi_fn([
        mask_fn,
    ],
                                       res=src_fn,
                                       extent=extent,
                                       t_srs=src_fn)[0]

    print("Loading mask array")
    mask_ma_full = iolib.ds_getma(mask_ds)
    mask_ds = None

    print("Extracting mask")
    mask = np.ma.getmaskarray(mask_ma_full)

    #Free up memory
    mask_ma_full = None

    #Add dilation step for buffer

    #newmask = np.logical_or(np.ma.getmaskarray(src_ma_full), mask)

    if args.invert:
        print("Inverting mask")
        mask = ~(mask)

    print("Loading src array and applying updated mask")
    if extent == src_fn:
        src_ds = gdal.Open(src_fn)
    else:
        src_ds = warplib.memwarp_multi_fn([
            src_fn,
        ],
                                          res=src_fn,
                                          extent=extent,
                                          t_srs=src_fn)[0]

    #Now load source array with new mask
    src_ma_full = np.ma.array(iolib.ds_getma(src_ds), mask=mask)
    mask = None

    if args.out_fn is not None:
        src_fn_masked = args.out_fn
    else:
        src_fn_masked = os.path.splitext(src_fn)[0] + '_masked.tif'
    print("Writing out masked version of input raster: %s" % src_fn_masked)
    iolib.writeGTiff(src_ma_full, src_fn_masked, src_ds, create=True)
Exemple #27
0
    print('Mean mb: %0.2f mwe/yr' % mb_mean)
    print('Sum/Area mb: %0.2f mwe/yr' % (mb_sum / glac_area))
    print('Mean mb * Area: %0.2f mwe/yr' % dmbdt_total_myr)
    print('Sum mb: %0.2f mwe/yr' % mb_sum)
    print('-------------------------------')

    #Write to master list
    out.append(outlist)
    #Write to temporary file
    writer.writerow(outlist)
    f.flush()

    min_glac_area_writeout = 2.0
    if writeout and (glac_area / 1E6 > min_glac_area_writeout):
        out_dz_fn = os.path.join(outdir, feat_fn + '_dz.tif')
        iolib.writeGTiff(dz, out_dz_fn, ds_list[0])

        out_z1_fn = os.path.join(outdir, feat_fn + '_z1.tif')
        iolib.writeGTiff(z1, out_z1_fn, ds_list[0])

        out_z2_fn = os.path.join(outdir, feat_fn + '_z2.tif')
        iolib.writeGTiff(z2, out_z2_fn, ds_list[0])

        if site == 'conus':
            out_z1_date_fn = os.path.join(outdir, feat_fn + '_ned_date.tif')
            iolib.writeGTiff(z1_date, out_z1_date_fn, ds_list[0])

            out_prism_ppt_annual_fn = os.path.join(
                outdir, feat_fn + '_precip_annual.tif')
            iolib.writeGTiff(prism_ppt_annual, out_prism_ppt_annual_fn,
                             ds_list[0])
Exemple #28
0
    #dem1_tide_fn = dem1_fn_base+'_tidecorr.tif'
    #dem2_tide_fn = dem2_fn_base+'_tidecorr.tif'
    dem1_tide_fn = findfile(dem1_fn_base, 'tidecorr.tif')
    if not dem1_tide_fn:
        dem1_tide_fn = findfile(dem1_fn_base, 'tidemodel_smooth_full_clip.tif')
    dem2_tide_fn = findfile(dem2_fn_base, 'tidecorr.tif')
    if not dem2_tide_fn:
        dem2_tide_fn = findfile(dem2_fn_base, 'tidemodel_smooth_full_clip.tif')
    if dem1_tide_fn and dem2_tide_fn:
        dem1_tide_ds, dem2_tide_ds = warplib.memwarp_multi_fn(
            [dem1_tide_fn, dem2_tide_fn], extent=dem1_ds, res=dem1_ds)
        dem1_tide = iolib.ds_getma(dem1_tide_ds)
        dem2_tide = iolib.ds_getma(dem2_tide_ds)
        tide_diff = dem2_tide - dem1_tide
        dst_fn = os.path.join(outdir, outprefix + '_tide_diff.tif')
        iolib.writeGTiff(tide_diff, dst_fn, dem1_ds, ndv=diffndv)
        #These values are tide prediction, to remove, want to subtract from observed elevation
        #Need to fill with 0 to prevent clipping to floating ice
        dem1 -= dem1_tide.filled(0)
        dem2 -= dem2_tide.filled(0)

firnair = True
#This is constant value for PIG
dem1_firnair = 15.0
dem2_firnair = dem1_firnair
firnair_diff = dem2_firnair - dem1_firnair
if firnair:
    #dem1_firnair_fn = dem1_fn_base+'_racmo_FirnAir.tif'
    #dem2_firnair_fn = dem2_fn_base+'_racmo_FirnAir.tif'
    dem1_firnair_fn = findfile(dem1_fn_base, 'racmo_FirnAir.tif')
    dem2_firnair_fn = findfile(dem2_fn_base, 'racmo_FirnAir.tif')
Exemple #29
0
def get_mask(dem_ds,
             mask_list,
             dem_fn=None,
             writeout=False,
             outdir=None,
             args=None):
    mask_list = check_mask_list(mask_list)
    if not mask_list or 'none' in mask_list:
        newmask = False
    else:
        #Basename for output files
        if outdir is not None:
            if not os.path.exists(outdir):
                os.makedirs(outdir)
        else:
            outdir = os.path.split(os.path.realpath(dem_fn))[0]

        if dem_fn is not None:
            #Extract DEM timestamp
            dem_dt = timelib.fn_getdatetime(dem_fn)
            out_fn_base = os.path.join(
                outdir,
                os.path.splitext(os.path.split(dem_fn)[-1])[0])

        if args is None:
            #Get default values
            parser = getparser()
            args = parser.parse_args([
                '',
            ])

        newmask = True

        if 'glaciers' in mask_list:
            icemask = get_icemask(dem_ds)
            if writeout:
                out_fn = out_fn_base + '_ice_mask.tif'
                print("Writing out %s" % out_fn)
                iolib.writeGTiff(icemask, out_fn, src_ds=dem_ds)
            newmask = np.logical_and(icemask, newmask)

        #Need to process NLCD separately, with nearest neighbor inteprolatin
        if 'nlcd' in mask_list and args.nlcd_filter != 'none':
            rs = 'near'
            nlcd_ds = gdal.Open(get_nlcd_fn())
            nlcd_ds_warp = warplib.memwarp_multi([
                nlcd_ds,
            ],
                                                 res=dem_ds,
                                                 extent=dem_ds,
                                                 t_srs=dem_ds,
                                                 r=rs)[0]
            out_fn = None
            if writeout:
                out_fn = out_fn_base + '_nlcd.tif'
            nlcdmask = get_nlcd_mask(nlcd_ds_warp,
                                     filter=args.nlcd_filter,
                                     out_fn=out_fn)
            if writeout:
                out_fn = os.path.splitext(out_fn)[0] + '_mask.tif'
                print("Writing out %s" % out_fn)
                iolib.writeGTiff(nlcdmask, out_fn, src_ds=dem_ds)
            newmask = np.logical_and(nlcdmask, newmask)

        if 'bareground' in mask_list and args.bareground_thresh > 0:
            bareground_ds = gdal.Open(get_bareground_fn())
            bareground_ds_warp = warplib.memwarp_multi([
                bareground_ds,
            ],
                                                       res=dem_ds,
                                                       extent=dem_ds,
                                                       t_srs=dem_ds,
                                                       r='cubicspline')[0]
            out_fn = None
            if writeout:
                out_fn = out_fn_base + '_bareground.tif'
            baregroundmask = get_bareground_mask(
                bareground_ds_warp,
                bareground_thresh=args.bareground_thresh,
                out_fn=out_fn)
            if writeout:
                out_fn = os.path.splitext(out_fn)[0] + '_mask.tif'
                print("Writing out %s" % out_fn)
                iolib.writeGTiff(baregroundmask, out_fn, src_ds=dem_ds)
            newmask = np.logical_and(baregroundmask, newmask)

        if 'snodas' in mask_list and args.snodas_thresh > 0:
            #Get SNODAS snow depth products for DEM timestamp
            snodas_min_dt = datetime(2003, 9, 30)
            if dem_dt >= snodas_min_dt:
                snodas_ds = get_snodas_ds(dem_dt)
                if snodas_ds is not None:
                    snodas_ds_warp = warplib.memwarp_multi([
                        snodas_ds,
                    ],
                                                           res=dem_ds,
                                                           extent=dem_ds,
                                                           t_srs=dem_ds,
                                                           r='cubicspline')[0]
                    #snow depth values are mm, convert to meters
                    snodas_depth = iolib.ds_getma(snodas_ds_warp) / 1000.
                    if snodas_depth.count() > 0:
                        print(
                            "Applying SNODAS snow depth filter (masking values >= %0.2f m)"
                            % args.snodas_thresh)
                        out_fn = None
                        if writeout:
                            out_fn = out_fn_base + '_snodas_depth.tif'
                            print("Writing out %s" % out_fn)
                            iolib.writeGTiff(snodas_depth,
                                             out_fn,
                                             src_ds=dem_ds)
                        snodas_mask = np.ma.masked_greater(
                            snodas_depth, args.snodas_thresh)
                        snodas_mask = ~(np.ma.getmaskarray(snodas_mask))
                        if writeout:
                            out_fn = os.path.splitext(out_fn)[0] + '_mask.tif'
                            print("Writing out %s" % out_fn)
                            iolib.writeGTiff(snodas_mask,
                                             out_fn,
                                             src_ds=dem_ds)
                        newmask = np.logical_and(snodas_mask, newmask)
                    else:
                        print(
                            "SNODAS grid for input location and timestamp is empty"
                        )

        #These tiles cover CONUS
        #tile_list=('h08v04', 'h09v04', 'h10v04', 'h08v05', 'h09v05')
        if 'modscag' in mask_list and args.modscag_thresh > 0:
            modscag_min_dt = datetime(2000, 2, 24)
            if dem_dt < modscag_min_dt:
                print("Warning: DEM timestamp (%s) is before earliest MODSCAG timestamp (%s)" \
                        % (dem_dt, modscag_min_dt))
            else:
                tile_list = get_modis_tile_list(dem_ds)
                print(tile_list)
                pad_days = 7
                modscag_fn_list = get_modscag_fn_list(dem_dt,
                                                      tile_list=tile_list,
                                                      pad_days=pad_days)
                if modscag_fn_list:
                    modscag_ds = proc_modscag(modscag_fn_list,
                                              extent=dem_ds,
                                              t_srs=dem_ds)
                    modscag_ds_warp = warplib.memwarp_multi([
                        modscag_ds,
                    ],
                                                            res=dem_ds,
                                                            extent=dem_ds,
                                                            t_srs=dem_ds,
                                                            r='cubicspline')[0]
                    print(
                        "Applying MODSCAG fractional snow cover percent filter (masking values >= %0.1f%%)"
                        % args.modscag_thresh)
                    modscag_fsca = iolib.ds_getma(modscag_ds_warp)
                    out_fn = None
                    if writeout:
                        out_fn = out_fn_base + '_modscag_fsca.tif'
                        print("Writing out %s" % out_fn)
                        iolib.writeGTiff(modscag_fsca, out_fn, src_ds=dem_ds)
                    modscag_mask = (modscag_fsca.filled(0) >=
                                    args.modscag_thresh)
                    modscag_mask = ~(modscag_mask)
                    if writeout:
                        out_fn = os.path.splitext(out_fn)[0] + '_mask.tif'
                        print("Writing out %s" % out_fn)
                        iolib.writeGTiff(modscag_mask, out_fn, src_ds=dem_ds)
                    newmask = np.logical_and(modscag_mask, newmask)

        #Use reflectance values to estimate snowcover
        if 'toa' in mask_list:
            #Use top of atmosphere scaled reflectance values (0-1)
            toa_ds = gdal.Open(get_toa_fn(dem_fn))
            toa_ds_warp = warplib.memwarp_multi([
                toa_ds,
            ],
                                                res=dem_ds,
                                                extent=dem_ds,
                                                t_srs=dem_ds)[0]
            toa_mask = get_toa_mask(toa_ds_warp, args.toa_thresh)
            if writeout:
                out_fn = out_fn_base + '_toa_mask.tif'
                print("Writing out %s" % out_fn)
                iolib.writeGTiff(toa_mask, out_fn, src_ds=dem_ds)
            newmask = np.logical_and(toa_mask, newmask)

        if False:
            #Filter based on expected snowline
            #Simplest approach uses altitude cutoff
            max_elev = 1500
            newdem = np.ma.masked_greater(dem, max_elev)
            newmask = np.ma.getmaskarray(newdem)

        print(
            "Generating final mask to use for reference surfaces, and applying to input DEM"
        )
        #Now invert to use to create final masked array
        #True (1) represents "invalid" pixel to match numpy ma convetion
        newmask = ~newmask

        #Dilate the mask
        if args.dilate is not None:
            niter = args.dilate
            print("Dilating mask with %i iterations" % niter)
            from scipy import ndimage
            newmask = ~(ndimage.morphology.binary_dilation(~newmask,
                                                           iterations=niter))

    return newmask
Exemple #30
0
def compute_offset(ref_dem_ds, src_dem_ds, src_dem_fn, mode='nuth', remove_outliers=True, max_offset=100, \
        max_dz=100, slope_lim=(0.1, 40), mask_list=['glaciers',], plot=True):
    #Make sure the input datasets have the same resolution/extent
    #Use projection of source DEM
    ref_dem_clip_ds, src_dem_clip_ds = warplib.memwarp_multi([ref_dem_ds, src_dem_ds], \
            res='max', extent='intersection', t_srs=src_dem_ds, r='cubic')

    #Compute size of NCC and SAD search window in pixels
    res = float(geolib.get_res(ref_dem_clip_ds, square=True)[0])
    max_offset_px = (max_offset/res) + 1
    #print(max_offset_px)
    pad = (int(max_offset_px), int(max_offset_px))

    #This will be updated geotransform for src_dem
    src_dem_gt = np.array(src_dem_clip_ds.GetGeoTransform())

    #Load the arrays
    ref_dem = iolib.ds_getma(ref_dem_clip_ds, 1)
    src_dem = iolib.ds_getma(src_dem_clip_ds, 1)

    print("Elevation difference stats for uncorrected input DEMs (src - ref)")
    diff = src_dem - ref_dem

    static_mask = get_mask(src_dem_clip_ds, mask_list, src_dem_fn)
    diff = np.ma.array(diff, mask=static_mask)

    if diff.count() == 0:
        sys.exit("No overlapping, unmasked pixels shared between input DEMs")

    if remove_outliers:
        diff = outlier_filter(diff, f=3, max_dz=max_dz)

    #Want to use higher quality DEM, should determine automatically from original res/count
    #slope = get_filtered_slope(ref_dem_clip_ds, slope_lim=slope_lim)
    slope = get_filtered_slope(src_dem_clip_ds, slope_lim=slope_lim)

    print("Computing aspect")
    #aspect = geolib.gdaldem_mem_ds(ref_dem_clip_ds, processing='aspect', returnma=True, computeEdges=False)
    aspect = geolib.gdaldem_mem_ds(src_dem_clip_ds, processing='aspect', returnma=True, computeEdges=False)

    ref_dem_clip_ds = None
    src_dem_clip_ds = None

    #Apply slope filter to diff
    #Note that we combine masks from diff and slope in coreglib
    diff = np.ma.array(diff, mask=np.ma.getmaskarray(slope))

    #Get final mask after filtering
    static_mask = np.ma.getmaskarray(diff)

    #Compute stats for new masked difference map
    print("Filtered difference map")
    diff_stats = malib.print_stats(diff)
    dz = diff_stats[5]

    print("Computing sub-pixel offset between DEMs using mode: %s" % mode)

    #By default, don't create output figure
    fig = None

    #Default horizntal shift is (0,0)
    dx = 0
    dy = 0

    #Sum of absolute differences
    if mode == "sad":
        ref_dem = np.ma.array(ref_dem, mask=static_mask)
        src_dem = np.ma.array(src_dem, mask=static_mask)
        m, int_offset, sp_offset = coreglib.compute_offset_sad(ref_dem, src_dem, pad=pad)
        #Geotransform has negative y resolution, so don't need negative sign
        #np array is positive down
        #GDAL coordinates are positive up
        dx = sp_offset[1]*src_dem_gt[1]
        dy = sp_offset[0]*src_dem_gt[5]
    #Normalized cross-correlation of clipped, overlapping areas
    elif mode == "ncc":
        ref_dem = np.ma.array(ref_dem, mask=static_mask)
        src_dem = np.ma.array(src_dem, mask=static_mask)
        m, int_offset, sp_offset, fig = coreglib.compute_offset_ncc(ref_dem, src_dem, \
                pad=pad, prefilter=False, plot=plot)
        dx = sp_offset[1]*src_dem_gt[1]
        dy = sp_offset[0]*src_dem_gt[5]
    #Nuth and Kaab (2011)
    elif mode == "nuth":
        #Compute relationship between elevation difference, slope and aspect
        fit_param, fig = coreglib.compute_offset_nuth(diff, slope, aspect, plot=plot)
        if fit_param is None:
            print("Failed to calculate horizontal shift")
        else:
            #fit_param[0] is magnitude of shift vector
            #fit_param[1] is direction of shift vector
            #fit_param[2] is mean bias divided by tangent of mean slope
            #print(fit_param)
            dx = fit_param[0]*np.sin(np.deg2rad(fit_param[1]))
            dy = fit_param[0]*np.cos(np.deg2rad(fit_param[1]))
            med_slope = malib.fast_median(slope)
            nuth_dz = fit_param[2]*np.tan(np.deg2rad(med_slope))
            print('Median dz: %0.2f\nNuth dz: %0.2f' % (dz, nuth_dz))
            #dz = nuth_dz
    elif mode == "all":
        print("Not yet implemented")
        #Want to compare all methods, average offsets
        #m, int_offset, sp_offset = coreglib.compute_offset_sad(ref_dem, src_dem)
        #m, int_offset, sp_offset = coreglib.compute_offset_ncc(ref_dem, src_dem)
    elif mode == "none":
        print("Skipping alignment, writing out DEM with median bias over static surfaces removed")
        dst_fn = outprefix+'_med%0.1f.tif' % dz
        iolib.writeGTiff(src_dem_orig + dz, dst_fn, src_dem_ds)
        sys.exit()
    #Note: minus signs here since we are computing dz=(src-ref), but adjusting src
    return -dx, -dy, -dz, static_mask, fig