Beispiel #1
0
def plot_2dhist(ax, x, y, xlim=None, ylim=None, xint=None, yint=None, nbins=(128,128), log=False, maxline=True, trendline=False):
    from pygeotools.lib import malib
    #Should compute number of bins automatically based on input values, xlim and ylim
    common_mask = ~(malib.common_mask([x,y]))
    x = x[common_mask]
    y = y[common_mask]
    if xlim is None:
        #xlim = (x.min(), x.max())
        xlim = malib.calcperc(x, (0.1, 99.9))
    if ylim is None:
        #ylim = (y.min(), y.max())
        ylim = malib.calcperc(y, (0.1, 99.9))
    #Note, round to nearest meter here
    #xlim = np.rint(np.array(xlim))
    xlim = np.array(xlim)
    ylim = np.array(ylim)
    if xint is not None:
        xedges = np.arange(xlim[0], xlim[1]+xint, xint)
    else:
        xedges = nbins[0]

    if yint is not None:
        yedges = np.arange(ylim[0], ylim[1]+yint, yint)
    else:
        yedges = nbins[1]

    H, xedges, yedges = np.histogram2d(x,y,range=[xlim,ylim],bins=[xedges, yedges])
    #H, xedges, yedges = np.histogram2d(x,y,range=[xlim,ylim],bins=nbins)
    #H = np.rot90(H)
    #H = np.flipud(H)
    H = H.T
    #Mask any empty bins
    Hmasked = np.ma.masked_where(H==0,H)
    #Hmasked = H
    H_clim = malib.calcperc(Hmasked, (2,98))
    if log:
        import matplotlib.colors as colors
        ax.pcolormesh(xedges,yedges,Hmasked,cmap='inferno',norm=colors.LogNorm(vmin=H_clim[0],vmax=H_clim[1]))
    else:
        ax.pcolormesh(xedges,yedges,Hmasked,cmap='inferno',vmin=H_clim[0],vmax=H_clim[1])
    if maxline:
        #Add line for max values in each x bin
        Hmed_idx = np.ma.argmax(Hmasked, axis=0)
        ymax = (yedges[:-1]+np.diff(yedges))[Hmed_idx]
        ax.plot(xedges[:-1]+np.diff(xedges), ymax, color='dodgerblue',lw=1.0)
    if trendline:
        #Add trendline
        import scipy.stats
        y_slope, y_intercept, r_value, p_value, std_err = scipy.stats.linregress(x, y)
        y_f = y_slope * xlim + y_intercept
        ax.plot(xlim, y_f, color='limegreen', ls='--', lw=0.5)
Beispiel #2
0
def dz_fltr_ma(dem, refdem, perc=None, abs_dz_lim=(0,30), smooth=True):
    """Absolute elevation difference range filter using values from a source array and a reference array 
    """
    if smooth:
        refdem = gauss_fltr_astropy(refdem)
        dem = gauss_fltr_astropy(dem)

    dz = refdem - dem

    #This is True for invalid values in DEM, and should be masked
    demmask = np.ma.getmaskarray(dem)

    if perc:
        dz_perc = malib.calcperc(dz, perc)
        print("Applying dz percentile filter (%s%%, %s%%): (%0.1f, %0.1f)" % (perc[0], perc[1], dz_perc[0], dz_perc[1]))
        #This is True for invalid values
        perc_mask = ((dz < dz_perc[0]) | (dz > dz_perc[1])).filled(False)
        demmask = (demmask | perc_mask)

    if abs_dz_lim:
        #This is True for invalid values
        abs_dz_mask = ((np.abs(dz) < abs_dz_lim[0]) | (np.abs(dz) > abs_dz_lim[1])).filled(False)
        if True:
            cutoff = 150
            abs_dz_lim = (0, 80)
            low = (refdem < cutoff).data
            abs_dz_mask[low] = ((np.abs(dz) < abs_dz_lim[0]) | (np.abs(dz) > abs_dz_lim[1])).filled(False)[low]
        demmask = (demmask | abs_dz_mask)

    out = np.ma.array(dem, mask=demmask, fill_value=dem.fill_value)
    return out
Beispiel #3
0
def perc_fltr(dem, perc=(1.0, 99.0)):
    """Percentile filter
    """
    rangelim = malib.calcperc(dem, perc)
    print('Excluding values outside of percentile ({0:0.2f}, {1:0.2f}) range: {2:0.1f} to {3:0.1f} m'.format(*(perc + rangelim)))
    out = range_fltr(dem, rangelim)
    return out
Beispiel #4
0
def plot_2dhist(ax, x, y, xlim, ylim, log=False):
    bins = (100, 100)
    common_mask = ~(malib.common_mask([x, y]))
    x = x[common_mask]
    y = y[common_mask]
    H, xedges, yedges = np.histogram2d(x, y, range=[xlim, ylim], bins=bins)
    H = np.rot90(H)
    H = np.flipud(H)
    Hmasked = np.ma.masked_where(H == 0, H)
    Hmed_idx = np.ma.argmax(Hmasked, axis=0)
    ymax = (yedges[:-1] + np.diff(yedges))[Hmed_idx]
    #Hmasked = H
    H_clim = malib.calcperc(Hmasked, (2, 98))
    if log:
        import matplotlib.colors as colors
        ax.pcolormesh(xedges,
                      yedges,
                      Hmasked,
                      cmap='inferno',
                      norm=colors.LogNorm(vmin=H_clim[0], vmax=H_clim[1]))
    else:
        ax.pcolormesh(xedges,
                      yedges,
                      Hmasked,
                      cmap='inferno',
                      vmin=H_clim[0],
                      vmax=H_clim[1])
    ax.plot(xedges[:-1] + np.diff(xedges), ymax, color='dodgerblue', lw=1.0)
Beispiel #5
0
def perc_fltr(dem, perc=(1.0, 99.0)):
    """Percentile filter
    """
    rangelim = malib.calcperc(dem, perc)
    print('Excluding values outside of percentile range: {0:0.2f} to {1:0.2f}'.format(*perc))
    out = range_fltr(dem, rangelim)
    return out
Beispiel #6
0
def get_bins(dem, bin_width=100.0):
    #Define min and max elevation
    minz, maxz = list(malib.calcperc(dem, perc=(0.01, 99.99)))
    minz = np.floor(minz / bin_width) * bin_width
    maxz = np.ceil(maxz / bin_width) * bin_width
    #Compute bin edges and centers
    bin_edges = np.arange(minz, maxz + bin_width, bin_width)
    bin_centers = bin_edges[:-1] + np.diff(bin_edges) / 2.0
    return bin_edges, bin_centers
Beispiel #7
0
def get_clim(a, clim_perc=(2, 98)):
    """
    Computer percentile stretch for input array
    """
    #print("Colorbar limits (%0.1f-%0.1f%%)" % clim_perc)
    clim = malib.calcperc(a, clim_perc)
    if clim[0] == clim[1]:
        if clim[0] > a.fill_value:
            clim = (a.fill_value, clim[0])
        else:
            clim = (clim[0], a.fill_value)
    return clim
Beispiel #8
0
def compute_offset_sad(dem1, dem2, pad=(9,9), plot=False):
    """Compute subpixel horizontal offset between input rasters using sum of absolute differences (SAD) method
    """
    #This defines the search window size
    #Use half-pixel stride?
    #Note: stride is not properly implemented 
    #stride = 1
    #ref = dem1[::stride,::stride]
    #kernel = dem2[pad[0]:-pad[0]:stride, pad[1]:-pad[1]:stride]
    kernel = dem2[pad[0]:-pad[0], pad[1]:-pad[1]]
    #Want to pad evenly on both sides, so add +1 here
    m = np.zeros((pad[0]*2+1, pad[1]*2+1))
   
    #Find integer pixel offset
    i = j = 0
    for i in range(m.shape[0]):
        print(i)
        for j in range(m.shape[1]):
            print(j)
            ref = dem1[i:i+kernel.shape[0], j:j+kernel.shape[1]]
            diff = ref - kernel
            
            #Remove outliers beyond IQR
            diff_iqr = malib.calcperc(diff, (25,75))
            diff = np.ma.masked_outside(diff, *diff_iqr)
            """ 
            diff_med = np.ma.median(diff)
            diff_mad = malib.mad(diff)
            diff_madr = (diff_med - mad, diff_med + mad)
            diff = np.ma.masked_outside(diff, diff_madr)     
            """
            #Masked areas will decrease sum! Normalize by count of valid pixels
            m[i,j] = np.ma.abs(diff).sum()/diff.count()
    
    #Note, we're dealing with min SAD here, so want to provide -m for sub-pixel refinement 
    m = -m  

    int_argmax = np.array(np.unravel_index(m.argmax(), m.shape))
    int_offset = int_argmax - pad
    
    sp_argmax = np.array(find_subpixel_peak_position(m, 'parabolic'))
    sp_offset = sp_argmax - pad

    if plot:
        plt.figure()
        plt.title('Sum of Absolute Differences')
        plt.imshow(m)
        plt.scatter(*sp_argmax[::-1])
        #plt.show()

    return m, int_offset, sp_offset
Beispiel #9
0
def cummulative_profile(xma, yma, xbin_width, limit_x_perc=(1, 99)):
    """
    compute binned statistics for independent variable with respect to dependendent variable
    Parameters
    -----------
    xma: masked array
        independent variable (like slope)
    yma: masked array
        dependent variable (like elevation difference)
    xbin_width: int
        bin_width for independent variable
    limit_x_perc: tuple
        limit binning of independent variable to the given percentile (default: 1 to 99 %)
    Returns
    -----------
    x_bins: np.array
        bin locations
    y_mean: np.array
        binned mean value for dependent variable
    y_meadian: np.array
        binned median value for dependent variable
    y_std: np.array
        binned standard deviation value for dependent varuiable
    y_perc: np.array
        binned percentage of variables within the bin
    """
    # xclim get rids of outliers in the independent variable
    # we only look at the 1 to 99 percentile values by default
    xclim = malib.calcperc(xma, limit_x_perc)
    # this step computes common mask where pixels of both x and y variables are valid
    xma_lim = np.ma.masked_outside(xma, xclim[0], xclim[1])
    cmask = malib.common_mask([xma_lim, yma])
    # the common mask is used to flatten the required points in a 1-D array
    xma_c = np.ma.compressed(np.ma.array(xma_lim, mask=cmask))
    yma_c = np.ma.compressed(np.ma.array(yma, mask=cmask))
    # we then use pandas groupby to quickly compute binned statistics
    df = pd.DataFrame({'x': xma_c, 'y': yma_c})
    df['x_rounded'] = (df['x'] + (xbin_width - 1)) // (xbin_width) * xbin_width
    grouped = df.groupby('x_rounded')
    df2 = grouped['y'].agg([np.mean, np.count_nonzero, np.median, np.std])
    df2.reset_index(inplace=True)
    # variables are returned as numpy array
    x_bins = df2['x_rounded'].values
    y_mean = df2['mean'].values
    y_median = df2['median'].values
    y_std = df2['std'].values
    y_perc = (df2['count_nonzero'].values /
              np.sum(df2['count_nonzero'].values)) * 100
    return x_bins, y_mean, y_median, y_std, y_perc
Beispiel #10
0
def aed(dem, res=None, bin_width=100.0):
    #Define min and max elevation
    minz, maxz= list(malib.calcperc(dem, perc=(0.01, 99.99)))
    minz = np.floor(minz/bin_width) * bin_width
    maxz = np.ceil(maxz/bin_width) * bin_width
    #Compute bin edges and centers
    bin_edges = np.arange(minz, maxz + bin_width, bin_width)
    bin_centers = bin_edges[:-1] + np.diff(bin_edges)/2.0
    #Compress masked array to get only valid elevations
    demc = dem.compressed()
    #Compute histogram
    bin_counts, bin_edges = np.histogram(demc, bins=bin_edges)
    #Convert count to area
    bin_areas = bin_counts * res * res / 1E6
    return bin_centers, bin_areas
Beispiel #11
0
def make_plot(m, fig_fn, label):
    f, ax = plt.subplots(figsize=(7, 7))
    #plt.title('%s to %s' % (t1.strftime('%Y-%m-%d'), t2.strftime('%Y-%m-%d')))
    perc = malib.calcperc(m, (2, 98))
    cmap = 'inferno'
    imgplot = ax.imshow(m, cmap=cmap)
    imgplot.set_clim(*perc)
    imgplot.axes.get_xaxis().set_visible(False)
    imgplot.axes.get_yaxis().set_visible(False)
    imgplot.axes.patch.set_facecolor('0.5')
    cb = plt.colorbar(imgplot,
                      orientation='vertical',
                      extend='both',
                      shrink=0.5)
    cb.set_label(label)
    return f, ax
Beispiel #12
0
def ndanimate(a):
    import matplotlib.animation as animation
    a = malib.checkma(a)
    #Compute constant scale
    clim = malib.calcperc(a)
    label = 'Elev. Diff. (m)'
    fig = plt.figure()
    ims = []
    for i in a:
        #cmap = 'gist_rainbow_r'
        cmap = 'cpt_rainbow'
        im = plt.imshow(i, cmap=cmap, clim=clim)
        im.axes.patch.set_facecolor('black')
        #cbar = fig.colorbar(im, extend='both', shrink=0.5)
        #cbar.set_label(label)
        ims.append([im])
    an = animation.ArtistAnimation(fig, ims, interval=100, blit=True)
    plt.show()
    return an
Beispiel #13
0
def map_plot(site_list, ds):
    a = iolib.ds_getma(ds)
    clim = malib.calcperc(a, (2, 98))
    mX = site_list[:, 1]
    mY = site_list[:, 2]
    pX, pY = geolib.mapToPixel(mX, mY, ds.GetGeoTransform())
    #f, ax = plt.subplots(1, figsize=(6,6), subplot_kw={'aspect':'equal', 'adjustable':'box-forced'})
    f, ax = plt.subplots(1, figsize=(6, 6), subplot_kw={'aspect': 'equal'})
    im = ax.imshow(a, vmin=clim[0], vmax=clim[1], cmap='inferno')
    ax.set_facecolor('0.5')
    from imview.lib import pltlib
    pltlib.add_scalebar(ax, geolib.get_res(ds)[0])
    ax.scatter(pX, pY, s=16, facecolors='w', edgecolors='k')
    for i, lbl in enumerate(site_list[:, 0]):
        bbox = dict(boxstyle='round,pad=0.1', fc='k', alpha=0.7)
        ax.annotate(str(int(lbl)),
                    xy=(pX[i], pY[i]),
                    xytext=(0, 4),
                    textcoords='offset points',
                    fontsize=8,
                    color='w',
                    bbox=bbox)
    return f
Beispiel #14
0
def map_plot(gf, z_bin_edges, outdir, hs=True):
    #print("Generating map plot")
    f, axa = plt.subplots(1, 3, figsize=(10, 7.5))
    #f.suptitle(gf.feat_fn)
    alpha = 1.0
    if hs:
        #z1_hs = geolib.gdaldem_wrapper(gf.out_z1_fn, product='hs', returnma=True, verbose=False)
        #z2_hs = geolib.gdaldem_wrapper(gf.out_z2_fn, product='hs', returnma=True, verbose=False)
        z1_hs = gf.z1_hs
        z2_hs = gf.z2_hs
        hs_clim = malib.calcperc(z2_hs, (2, 98))
        z1_hs_im = axa[0].imshow(z1_hs,
                                 cmap='gray',
                                 vmin=hs_clim[0],
                                 vmax=hs_clim[1])
        z2_hs_im = axa[1].imshow(z2_hs,
                                 cmap='gray',
                                 vmin=hs_clim[0],
                                 vmax=hs_clim[1])
        alpha = 0.5
    z1_im = axa[0].imshow(gf.z1,
                          cmap='cpt_rainbow',
                          vmin=z_bin_edges[0],
                          vmax=z_bin_edges[-1],
                          alpha=alpha)
    z2_im = axa[1].imshow(gf.z2,
                          cmap='cpt_rainbow',
                          vmin=z_bin_edges[0],
                          vmax=z_bin_edges[-1],
                          alpha=alpha)
    axa[0].contour(gf.z1, [
        gf.z1_ela,
    ],
                   linewidths=0.5,
                   linestyles=':',
                   colors='w')
    axa[1].contour(gf.z2, [
        gf.z2_ela,
    ],
                   linewidths=0.5,
                   linestyles=':',
                   colors='w')
    #t1_title = int(np.round(gf.t1))
    #t2_title = int(np.round(gf.t2))
    t1_title = '%0.2f' % gf.t1
    t2_title = '%0.2f' % gf.t2
    #t1_title = gf.t1.strftime('%Y-%m-%d')
    #t2_title = gf.t2.strftime('%Y-%m-%d')
    axa[0].set_title(t1_title)
    axa[1].set_title(t2_title)
    axa[2].set_title('%s to %s (%0.2f yr)' % (t1_title, t2_title, gf.dt))
    #dz_clim = (-10, 10)
    dz_clim = (-2.0, 2.0)
    dz_im = axa[2].imshow(gf.dhdt,
                          cmap='RdBu',
                          vmin=dz_clim[0],
                          vmax=dz_clim[1])
    for ax in axa:
        pltlib.hide_ticks(ax)
        ax.set_facecolor('k')
    sb_loc = pltlib.best_scalebar_location(gf.z1)
    pltlib.add_scalebar(axa[0], gf.res[0], location=sb_loc)
    pltlib.add_cbar(axa[0], z1_im, label='Elevation (m WGS84)')
    pltlib.add_cbar(axa[1], z2_im, label='Elevation (m WGS84)')
    pltlib.add_cbar(axa[2], dz_im, label='dh/dt (m/yr)')
    plt.tight_layout()
    #Make room for suptitle
    #plt.subplots_adjust(top=0.90)
    #print("Saving map plot")
    fig_fn = os.path.join(outdir, gf.feat_fn + '_mb_map.png')
    plt.savefig(fig_fn, bbox_inches='tight', dpi=300)
    plt.close(f)
Beispiel #15
0
def mb_calc(gf, z1_date=z1_date, z2_date=z2_date, verbose=verbose):
    #print("\n%i of %i: %s\n" % (n+1, len(glacfeat_list), gf.feat_fn))
    print(gf.feat_fn)

    #This should already be handled by earlier attribute filter, but RGI area could be wrong
    #24k shp has area in m^2, RGI in km^2
    #if gf.glac_area/1E6 < min_glac_area:
    if gf.glac_area < min_glac_area:
        if verbose:
            print("Glacier area below %0.1f km2 threshold" % min_glac_area)
        return None

    #Warp everything to common res/extent/proj
    ds_list = warplib.memwarp_multi_fn([z1_fn, z2_fn], res='min', \
            extent=gf.glac_geom_extent, t_srs=aea_srs, verbose=verbose)

    if site == 'conus':
        #Add prism datasets
        prism_fn_list = [prism_ppt_annual_fn, prism_tmean_annual_fn]
        prism_fn_list.extend([
            prism_ppt_summer_fn, prism_ppt_winter_fn, prism_tmean_summer_fn,
            prism_tmean_winter_fn
        ])
        ds_list.extend(warplib.memwarp_multi_fn(prism_fn_list, res=ds_list[0], \
                extent=gf.glac_geom_extent, t_srs=aea_srs, verbose=verbose))

    if site == 'hma':
        #Add debris cover datasets
        #Should tar this up, and extract only necessary file
        #Downloaded from: http://mountainhydrology.org/data-nature-2017/
        kra_nature_dir = '/nobackup/deshean/data/Kraaijenbrink_hma/regions/out'
        #This assumes that numbers are identical between RGI50 and RGI60
        debris_class_fn = os.path.join(
            kra_nature_dir, 'RGI50-%s/classification.tif' % gf.glacnum)
        debris_thick_fn = os.path.join(
            kra_nature_dir, 'RGI50-%s/debris-thickness-50cm.tif' % gf.glacnum)
        ice_thick_fn = os.path.join(kra_nature_dir,
                                    'RGI50-%s/ice-thickness.tif' % gf.glacnum)
        hma_fn_list = []
        if os.path.exists(debris_class_fn):
            hma_fn_list.append(debris_class_fn)
        if os.path.exists(debris_thick_fn):
            hma_fn_list.append(debris_thick_fn)
        if os.path.exists(ice_thick_fn):
            hma_fn_list.append(ice_thick_fn)
        if len(hma_fn_list) > 0:
            #Add velocity
            hma_fn_list.extend([vx_fn, vy_fn])
            ds_list.extend(warplib.memwarp_multi_fn(hma_fn_list, res=ds_list[0], \
                    extent=gf.glac_geom_extent, t_srs=aea_srs, verbose=verbose))

    #Check to see if z2 is empty, as z1 should be continuous
    gf.z2 = iolib.ds_getma(ds_list[1])
    if gf.z2.count() == 0:
        if verbose:
            print("No z2 pixels")
        return None

    glac_geom_mask = geolib.geom2mask(gf.glac_geom, ds_list[0])
    gf.z1 = np.ma.array(iolib.ds_getma(ds_list[0]), mask=glac_geom_mask)
    #Apply SRTM penetration correction
    if z1_srtm_penetration_corr:
        gf.z1 = srtm_corr(gf.z1)
    if z2_srtm_penetration_corr:
        gf.z2 = srtm_corr(gf.z2)
    gf.z2 = np.ma.array(gf.z2, mask=glac_geom_mask)
    gf.dz = gf.z2 - gf.z1
    if gf.dz.count() == 0:
        if verbose:
            print("No valid dz pixels")
        return None

    #Should add better filtering here
    #Elevation dependent abs. threshold filter?

    filter_outliers = True
    #Remove clearly bogus pixels
    if filter_outliers:
        bad_perc = (0.1, 99.9)
        #bad_perc = (1, 99)
        rangelim = malib.calcperc(gf.dz, bad_perc)
        gf.dz = np.ma.masked_outside(gf.dz, *rangelim)

    gf.res = geolib.get_res(ds_list[0])
    valid_area = gf.dz.count() * gf.res[0] * gf.res[1]
    valid_area_perc = valid_area / gf.glac_area
    if valid_area_perc < min_valid_area_perc:
        if verbose:
            print(
                "Not enough valid pixels. %0.1f%% percent of glacier polygon area"
                % (100 * valid_area_perc))
        return None

    #Filter dz - throw out abs differences >150 m

    #Compute dz, volume change, mass balance and stats
    gf.z1_stats = malib.get_stats(gf.z1)
    gf.z2_stats = malib.get_stats(gf.z2)
    z2_elev_med = gf.z2_stats[5]
    z2_elev_p16 = gf.z2_stats[11]
    z2_elev_p84 = gf.z2_stats[12]

    #Caluclate stats for aspect and slope using z2
    #Requires GDAL 2.1+
    gf.z2_aspect = np.ma.array(geolib.gdaldem_mem_ds(ds_list[1],
                                                     processing='aspect',
                                                     returnma=True),
                               mask=glac_geom_mask)
    gf.z2_aspect_stats = malib.get_stats(gf.z2_aspect)
    z2_aspect_med = gf.z2_aspect_stats[5]
    gf.z2_slope = np.ma.array(geolib.gdaldem_mem_ds(ds_list[1],
                                                    processing='slope',
                                                    returnma=True),
                              mask=glac_geom_mask)
    gf.z2_slope_stats = malib.get_stats(gf.z2_slope)
    z2_slope_med = gf.z2_slope_stats[5]

    #Rasterize source dates
    if z1_date is None:
        z1_date = get_date_a(ds_list[0], z1_date_shp_lyr, glac_geom_mask,
                             z1_datefield)
        gf.t1 = z1_date.mean()
    else:
        gf.t1 = z1_date

    if z2_date is None:
        z2_date = get_date_a(ds_list[0], z2_date_shp_lyr, glac_geom_mask,
                             z2_datefield)
        #Attempt to use YYYYMMDD string
        #z2_dta = np.datetime64(z2_date.astype("S8").tolist())
        gf.t2 = z2_date.mean()
    else:
        gf.t2 = z2_date

    if isinstance(gf.t1, datetime):
        gf.t1 = timelib.dt2decyear(gf.t1)

    if isinstance(gf.t2, datetime):
        gf.t2 = timelib.dt2decyear(gf.t2)

    gf.t1 = float(gf.t1)
    gf.t2 = float(gf.t2)

    #Calculate dt grids
    #gf.dt = z2_date - z1_date
    #gf.dt = gf.dt.mean()
    #This should be decimal years
    gf.dt = gf.t2 - gf.t1
    #if isinstance(gf.dt, timedelta):
    #    gf.dt = gf.dt.total_seconds()/timelib.spy
    #Calculate dh/dt, in m/yr
    gf.dhdt = gf.dz / gf.dt
    gf.dhdt_stats = malib.get_stats(gf.dhdt)
    dhdt_mean = gf.dhdt_stats[3]
    dhdt_med = gf.dhdt_stats[5]

    rho_i = 0.91
    rho_s = 0.50
    rho_f = 0.60

    #This is recommendation by Huss et al (2013)
    rho_is = 0.85
    rho_sigma = 0.06

    #Can estimate ELA values computed from hypsometry and typical AAR
    #For now, assume ELA is mean
    gf.z1_ela = None
    gf.z1_ela = gf.z1_stats[3]
    gf.z2_ela = gf.z2_stats[3]
    #Note: in theory, the ELA should get higher with mass loss
    #In practice, using mean and same polygon, ELA gets lower as glacier surface thins
    if verbose:
        print("ELA(t1): %0.1f" % gf.z1_ela)
        print("ELA(t2): %0.1f" % gf.z2_ela)

    if gf.z1_ela > gf.z2_ela:
        min_ela = gf.z2_ela
        max_ela = gf.z1_ela
    else:
        min_ela = gf.z1_ela
        max_ela = gf.z2_ela

    #Calculate mass balance map from dhdt
    gf.mb = gf.dhdt * rho_is
    """
    # This attempted to assign different densities above and below ELA
    if gf.z1_ela is None:
        gf.mb = gf.dhdt * rho_is
    else:
        #Initiate with average density
        gf.mb = gf.dhdt*(rho_is + rho_f)/2.
        #Everything that is above ELA at t2 is elevation change over firn, use firn density
        accum_mask = (gf.z2 > gf.z2_ela).filled(0).astype(bool)
        gf.mb[accum_mask] = (gf.dhdt*rho_f)[accum_mask]
        #Everything that is below ELA at t1 is elevation change over ice, use ice density
        abl_mask = (gf.z1 <= gf.z1_ela).filled(0).astype(bool)
        gf.mb[abl_mask] = (gf.dhdt*rho_is)[abl_mask]
        #Everything in between, use average of ice and firn density
        #mb[(z1 > z1_ela) || (z2 <= z2_ela)] = dhdt*(rhois + rho_f)/2.
        #Linear ramp
        #rho_f + z2*((rho_is - rho_f)/(z2_ela - z1_ela))
        #mb = np.where(dhdt < ela, dhdt*rho_i, dhdt*rho_s)
    """

    #Use this for winter balance
    #mb = dhdt * rho_s

    gf.mb_stats = malib.get_stats(gf.mb)
    gf.mb_mean = gf.mb_stats[3]

    #Calculate uncertainty of total elevation change
    #TODO: Better spatial distribution characterization
    #Add slope-dependent component here
    dz_sigma = np.sqrt(z1_sigma**2 + z2_sigma**2)
    #Uncrtainty of dh/dt
    dhdt_sigma = dz_sigma / gf.dt

    #This is mb uncertainty map
    gf.mb_sigma = np.ma.abs(gf.mb) * np.sqrt((rho_sigma / rho_is)**2 +
                                             (dhdt_sigma / gf.dhdt)**2)
    gf.mb_sigma_stats = malib.get_stats(gf.mb_sigma)
    #This is average mb uncertainty
    gf.mb_mean_sigma = gf.mb_sigma_stats[3]

    #Now calculate mb for entire polygon
    area_sigma_perc = 0.09
    gf.mb_mean_totalarea = gf.mb_mean * gf.glac_area
    #Already have area uncertainty as percentage, just use directly
    gf.mb_mean_totalarea_sigma = np.ma.abs(gf.mb_mean_totalarea) * np.sqrt(
        (gf.mb_mean_sigma / gf.mb_mean)**2 + area_sigma_perc**2)

    mb_sum = np.sum(gf.mb) * gf.res[0] * gf.res[1]

    outlist = [gf.glacnum, gf.cx, gf.cy, z2_elev_med, z2_elev_p16, z2_elev_p84, z2_slope_med, z2_aspect_med, \
            gf.mb_mean, gf.mb_mean_sigma, gf.glac_area, gf.mb_mean_totalarea, gf.mb_mean_totalarea_sigma, \
            gf.t1, gf.t2, gf.dt]

    if site == 'conus':
        prism_ppt_annual = np.ma.array(iolib.ds_getma(ds_list[2]),
                                       mask=glac_geom_mask) / 1000.
        prism_ppt_annual_stats = malib.get_stats(prism_ppt_annual)
        prism_ppt_annual_mean = prism_ppt_annual_stats[3]

        prism_tmean_annual = np.ma.array(iolib.ds_getma(ds_list[3]),
                                         mask=glac_geom_mask)
        prism_tmean_annual_stats = malib.get_stats(prism_tmean_annual)
        prism_tmean_annual_mean = prism_tmean_annual_stats[3]

        outlist.extend([prism_ppt_annual_mean, prism_tmean_annual_mean])

        #This is mean monthly summer precip, need to multiply by nmonths to get cumulative
        n_summer = 4
        prism_ppt_summer = n_summer * np.ma.array(iolib.ds_getma(ds_list[4]),
                                                  mask=glac_geom_mask) / 1000.
        prism_ppt_summer_stats = malib.get_stats(prism_ppt_summer)
        prism_ppt_summer_mean = prism_ppt_summer_stats[3]

        n_winter = 8
        prism_ppt_winter = n_winter * np.ma.array(iolib.ds_getma(ds_list[5]),
                                                  mask=glac_geom_mask) / 1000.
        prism_ppt_winter_stats = malib.get_stats(prism_ppt_winter)
        prism_ppt_winter_mean = prism_ppt_winter_stats[3]

        prism_tmean_summer = np.ma.array(iolib.ds_getma(ds_list[6]),
                                         mask=glac_geom_mask)
        prism_tmean_summer_stats = malib.get_stats(prism_tmean_summer)
        prism_tmean_summer_mean = prism_tmean_summer_stats[3]

        prism_tmean_winter = np.ma.array(iolib.ds_getma(ds_list[7]),
                                         mask=glac_geom_mask)
        prism_tmean_winter_stats = malib.get_stats(prism_tmean_winter)
        prism_tmean_winter_mean = prism_tmean_winter_stats[3]

        outlist.extend([
            prism_ppt_summer_mean, prism_ppt_winter_mean,
            prism_tmean_summer_mean, prism_tmean_winter_mean
        ])

    if site == 'hma':
        #Classes are: 1 = clean ice, 2 = debris, 3 = pond
        #Load up debris cover maps, ice thickness
        if len(ds_list) > 2:
            gf.debris_class = np.ma.array(iolib.ds_getma(ds_list[2]),
                                          mask=glac_geom_mask)
            gf.debris_thick = np.ma.array(iolib.ds_getma(ds_list[3]),
                                          mask=glac_geom_mask)
            #Load ice thickness from glabtop2
            gf.H = np.ma.array(iolib.ds_getma(ds_list[4]), mask=glac_geom_mask)
            #Load surface velocity maps from Dehecq
            gf.vx = np.ma.array(iolib.ds_getma(ds_list[5]),
                                mask=glac_geom_mask)
            gf.vy = np.ma.array(iolib.ds_getma(ds_list[6]),
                                mask=glac_geom_mask)
            gf.vm = np.ma.sqrt(gf.vx**2 + gf.vy**2)
            v_col_factor = 0.8
            #Should smooth, better handling of data gaps
            gf.divU = np.gradient(v_col_factor * gf.vx)[1] + np.gradient(
                v_col_factor * gf.vy)[0]
            gf.divQ = gf.H * gf.divU
            #Compute debris/pond/clean percentages for entire polygon
            if gf.debris_class.count() > 0:
                gf.perc_clean = 100. * (gf.debris_class
                                        == 1).sum() / gf.debris_class.count()
                gf.perc_debris = 100. * (gf.debris_class
                                         == 2).sum() / gf.debris_class.count()
                gf.perc_pond = 100. * (gf.debris_class
                                       == 3).sum() / gf.debris_class.count()
            outlist.extend([
                gf.H.mean(),
                gf.debris_thick.mean(), gf.perc_debris, gf.perc_pond,
                gf.perc_clean
            ])

    if verbose:
        print('Mean mb: %0.2f +/- %0.2f mwe/yr' %
              (gf.mb_mean, gf.mb_mean_sigma))
        print('Sum/Area mb: %0.2f mwe/yr' % (mb_sum / gf.glac_area))
        print('Mean mb * Area: %0.2f +/- %0.2f mwe/yr' %
              (gf.mb_mean_totalarea, gf.mb_mean_totalarea_sigma))
        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()

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

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

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

        temp_fn = os.path.join(outdir, gf.feat_fn + '_z2_aspect.tif')
        iolib.writeGTiff(gf.z2_aspect, temp_fn, ds_list[0])

        temp_fn = os.path.join(outdir, gf.feat_fn + '_z2_slope.tif')
        iolib.writeGTiff(gf.z2_slope, temp_fn, ds_list[0])

        #Need to fix this - write out constant date arrays regardless of source
        #out_z1_date_fn = os.path.join(outdir, gf.feat_fn+'_ned_date.tif')
        #iolib.writeGTiff(z1_date, out_z1_date_fn, ds_list[0])

        if site == 'conus':
            out_prism_ppt_annual_fn = os.path.join(
                outdir, gf.feat_fn + '_precip_annual.tif')
            iolib.writeGTiff(prism_ppt_annual, out_prism_ppt_annual_fn,
                             ds_list[0])
            out_prism_tmean_annual_fn = os.path.join(
                outdir, gf.feat_fn + '_tmean_annual.tif')
            iolib.writeGTiff(prism_tmean_annual, out_prism_tmean_annual_fn,
                             ds_list[0])

            out_prism_ppt_summer_fn = os.path.join(
                outdir, gf.feat_fn + '_precip_summer.tif')
            iolib.writeGTiff(prism_ppt_summer, out_prism_ppt_summer_fn,
                             ds_list[0])
            out_prism_ppt_winter_fn = os.path.join(
                outdir, gf.feat_fn + '_precip_winter.tif')
            iolib.writeGTiff(prism_ppt_winter, out_prism_ppt_winter_fn,
                             ds_list[0])

            out_prism_tmean_summer_fn = os.path.join(
                outdir, gf.feat_fn + '_tmean_summer.tif')
            iolib.writeGTiff(prism_tmean_summer, out_prism_tmean_summer_fn,
                             ds_list[0])
            out_prism_tmean_winter_fn = os.path.join(
                outdir, gf.feat_fn + '_tmean_winter.tif')
            iolib.writeGTiff(prism_tmean_winter, out_prism_tmean_winter_fn,
                             ds_list[0])

        if site == 'hma':
            if gf.H is not None:
                temp_fn = os.path.join(outdir, gf.feat_fn + '_H.tif')
                iolib.writeGTiff(gf.H, temp_fn, ds_list[0])

            if gf.debris_thick is not None:
                temp_fn = os.path.join(outdir,
                                       gf.feat_fn + '_debris_thick.tif')
                iolib.writeGTiff(gf.debris_thick, temp_fn, ds_list[0])

            if gf.debris_class is not None:
                temp_fn = os.path.join(outdir,
                                       gf.feat_fn + '_debris_class.tif')
                iolib.writeGTiff(gf.debris_class, temp_fn, ds_list[0])

            if gf.vm is not None:
                temp_fn = os.path.join(outdir, gf.feat_fn + '_vm.tif')
                iolib.writeGTiff(gf.vm, temp_fn, ds_list[0])

            if gf.divQ is not None:
                temp_fn = os.path.join(outdir, gf.feat_fn + '_divQ.tif')
                iolib.writeGTiff(gf.divQ, temp_fn, ds_list[0])

    #Do AED for all
    #Compute mb using scaled AED vs. polygon
    #Check for valid pixel count vs. feature area, fill if appropriate

    if mb_plot and (gf.glac_area / 1E6 > min_glac_area_writeout):
        z_bin_edges = hist_plot(gf, outdir)
        gf.z1_hs = geolib.gdaldem_mem_ds(ds_list[0],
                                         processing='hillshade',
                                         returnma=True)
        gf.z2_hs = geolib.gdaldem_mem_ds(ds_list[1],
                                         processing='hillshade',
                                         returnma=True)
        map_plot(gf, z_bin_edges, outdir)

    return outlist, gf
Beispiel #16
0
    #Try to pull out second timestamp from dz_fn
    dem2_ts = timelib.fn_getdatetime_list(dz_fn)[-1]
    outprefix = os.path.splitext(os.path.split(dz_fn)[1])[0]

outprefix = os.path.join(args.outdir, outprefix)

#Calculate water year
wy = dem1_ts.year + 1
if dem1_ts.month >= 10:
    wy = dem1_ts.year

#These need to be updated in geolib to use gdaldem API
hs = geolib.gdaldem_mem_ds(dem1_ds, processing='hillshade', returnma=True)
hs_clim = (1,255)

dem_clim = malib.calcperc(dem1, (1,99))
res = geolib.get_res(dem1_ds)[0]

if args.density is None:
    #Attempt to extract from nearby SNOTEL sites for dem_ts
    #Attempt to use model
    #Last resort, use constant value
    rho_s = 0.5
    #rho_s = 0.4
    #rho_s = 0.36

#Convert snow depth to swe
swe = dz * rho_s

if args.filter:
    print("Filtering SWE map")
#This will return warped, in-memory GDAL dataset objects
#Can also resample all inputs to a lower resolution (res=256)
ds_list = warplib.memwarp_multi_fn(dem_fn_list, extent='intersection', res='min')

#Load datasets to NumPy arrays
dem_2007, dem_2009 = [iolib.ds_getma(i) for i in ds_list]
dem_list = [dem_2007, dem_2009]
#dem_list = [iolib.ds_getma(i) for i in ds_list]

import matplotlib
matplotlib.pyplot.imshow(dem_2007)

matplotlib.pyplot.imshow(dem_2009)

titles = ['2007', '2009']
clim = malib.calcperc(dem_list[0], (2,98))
plot_panels(2, dem_list, clim, titles, 'inferno', 'Elevation (m WGS84)', fn='dem.png')

# Its possible sometimes to get date times from TIFFS but apparently these DEMS don't have any datetimes assigned.

# We can get the date times from the original *(unmerged) files though.

[timelib.fn_getdatetime(fn) for fn in 
 [
    '/Users/elischwat/Downloads/datasetsA/lewis_2009/dtm/lewis_2009_dtm_44.tif',
    '/Users/elischwat/Downloads/datasetsA/rainier_2007/rainier_2007_dtm_12.tif',
    '/Users/elischwat/Downloads/datasetsA/rainier_2007/rainier_2007_dtm_13.tif',
    '/Users/elischwat/Downloads/datasetsA/rainier_2007/rainier_2007_dtm_14.tif',
    '/Users/elischwat/Downloads/datasetsA/rainier_2007/rainier_2007_dtm_7.tif',
    '/Users/elischwat/Downloads/datasetsA/rainier_2007/rainier_2007_dtm_8.tif',
    '/Users/elischwat/Downloads/datasetsA/rainier_2007/rainier_2007_dtm_9.tif'
Beispiel #18
0
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
Beispiel #19
0
def main():
    parser = getparser()
    args = parser.parse_args()
    if args.seedmode == 'existing_velocity':
        if args.vx_fn is None or args.vy_fn is None:
            parser.error('"-seedmode existing_velocity" requires "-vx_fn" and "-vy_fn"')

    print('\n%s' % datetime.now())
    print('%s UTC\n' % datetime.utcnow())

    align = args.align
    seedmode = args.seedmode
    spr = args.refinement
    erode = args.erode
    #Correlator tile timeout
    #With proper seeding, correlation should be very fast
    #timeout = 360 
    timeout = 1200 
    threads = args.threads

    kernel = (args.kernel, args.kernel)
    #SGM correlator
    if spr > 3:
        #kernel = (7,7)
        kernel = (11,11)
        erode = 0

    #Smooth the output F.tif 
    smoothF = args.filter 

    res = args.tr
    #Resample input to something easier to work with
    #res = 4.0

    #Open input files
    fn1 = args.fn1
    fn2 = args.fn2 

    if not iolib.fn_check(fn1) or not iolib.fn_check(fn2):
        sys.exit("Unable to locate input files")

    if args.outdir is not None:
        outdir = args.outdir
    else:
        outdir = '%s__%s_vmap_%sm_%ipx_spm%i' % (os.path.splitext(os.path.split(fn1)[1])[0], \
                os.path.splitext(os.path.split(fn2)[1])[0], res, kernel[0], spr)

    #Note, can encounter filename length issues in boost, just use vmap prefix
    outprefix = '%s/vmap' % (outdir)
    if not os.path.exists(outdir):
        os.makedirs(outdir)

    #Check to see if inputs have geolocation and projection information
    ds1 = iolib.fn_getds(fn1)
    ds2 = iolib.fn_getds(fn2)

    if geolib.srs_check(ds1) and geolib.srs_check(ds2):
        ds1_clip_fn = os.path.join(outdir, os.path.splitext(os.path.basename(fn1))[0]+'_warp.tif')
        ds2_clip_fn = os.path.join(outdir, os.path.splitext(os.path.basename(fn2))[0]+'_warp.tif')

        if not os.path.exists(ds1_clip_fn) or not os.path.exists(ds2_clip_fn):
            #This should write out files to new subdir
            ds1_clip, ds2_clip = warplib.diskwarp_multi_fn([fn1, fn2], extent='intersection', res=res, r='average', outdir=outdir)
            ds1_clip = None
            ds2_clip = None
            #However, if inputs have identical extent/res/proj, then link to original files
            if not os.path.exists(ds1_clip_fn):
                os.symlink(os.path.abspath(fn1), ds1_clip_fn)
            if not os.path.exists(ds2_clip_fn):
                os.symlink(os.path.abspath(fn2), ds2_clip_fn)
            align = 'None'

        #Mask support - limit correlation only to rock/ice surfaces, no water/veg
        #This masks input images - guarantee we won't waste time correlating over vegetation
        #TODO: Add support to load arbitrary raster or shp mask
        if args.mask_input:
            ds1_masked_fn = os.path.splitext(ds1_clip_fn)[0]+'_masked.tif'
            ds2_masked_fn = os.path.splitext(ds2_clip_fn)[0]+'_masked.tif'

            if not os.path.exists(ds1_masked_fn) or not os.path.exists(ds2_masked_fn):
                #Load NLCD or bareground mask
                from demcoreg.dem_mask import get_lulc_mask

                ds1_clip = iolib.fn_getds(ds1_clip_fn)
                lulc_mask_fn = os.path.join(outdir, 'lulc_mask.tif')
                #if not os.path.exists(nlcd_mask_fn):
                lulc_mask = get_lulc_mask(ds1_clip, mask_glaciers=False, filter='not_forest')
                iolib.writeGTiff(lulc_mask, lulc_mask_fn, ds1_clip) 
                ds1_clip = None

                #Now apply to original images 
                #This could be problematic for huge inputs, see apply_mask.py
                #lulc_mask = lulc_mask.astype(int)
                for fn in (ds1_clip_fn, ds2_clip_fn):
                    ds = iolib.fn_getds(fn)
                    a = iolib.ds_getma(ds)
                    a = np.ma.array(a, mask=~(lulc_mask))
                    if a.count() > 0:
                        out_fn = os.path.splitext(fn)[0]+'_masked.tif'
                        iolib.writeGTiff(a,out_fn,ds)
                        a = None
                    else:
                        sys.exit("No unmasked pixels over bare earth")
            ds1_clip_fn = ds1_masked_fn
            ds2_clip_fn = ds2_masked_fn
    else:
        ds1_clip_fn = fn1
        ds2_clip_fn = fn2
        #Now let user specify alignment methods as option - don't hardcode
        #align = 'Homography'
        #align = 'AffineEpipolar'
    ds1 = None
    ds2 = None

    #Should have extra kwargs option here
    stereo_opt = get_stereo_opt(threads=threads, kernel=kernel, timeout=timeout, \
            erode=erode, spr=spr, align=align)
    
    #Stereo arguments
    #Latest version of ASP should accept tif without camera models
    #stereo_args = [ds1_clip_fn, ds2_clip_fn, outprefix]
    #Nope - still need to provide dummy camera models, and they must be unique files
    #Use the dummy.tsai file bundled in the vmap repo
    dummy_tsai = os.path.join(os.path.split(os.path.realpath(__file__))[0], 'dummy.tsai')
    dummy_tsai2 = os.path.splitext(dummy_tsai)[0]+'2.tsai'
    if not os.path.exists(dummy_tsai2):
        dummy_tsai2 = os.symlink(dummy_tsai, os.path.splitext(dummy_tsai)[0]+'2.tsai')
    stereo_args = [ds1_clip_fn, ds2_clip_fn, dummy_tsai, dummy_tsai2, outprefix]

    #Run stereo_pprc
    if not os.path.exists(outprefix+'-R_sub.tif'):
        run_cmd('stereo_pprc', stereo_opt+stereo_args, msg='0: Preprocessing')
        #Copy proj info to outputs, this should happen automatically now?
        for ext in ('L', 'R', 'L_sub', 'R_sub', 'lMask', 'rMask', 'lMask_sub', 'rMask_sub'):
            geolib.copyproj(ds1_clip_fn, '%s-%s.tif' % (outprefix,ext))

    #Prepare seeding for stereo_corr
    #TODO: these are untested after refactoring
    if not os.path.exists(outprefix+'_D_sub.tif'):
        #Don't need to do anything for default seed-mode 1
        if seedmode == 'sparse_disp':
            #Sparse correlation of full-res images
            stereo_opt.extend(['--corr-seed-mode', '3'])
            sparse_disp_opt = []
            sparse_disp_opt.extend(['--Debug', '--coarse', '512', '--fine', '256', '--no_epipolar_fltr']) 
            sparse_disp_opt.extend(['-P', str(threads)])
            sparse_disp_args = [outprefix+'-L.tif', outprefix+'-R.tif', outprefix]
            run_cmd('sparse_disp', sparse_disp_opt+sparse_disp_args, msg='0.5: D_sub generation')
        elif seedmode == 'existing_velocity':
            #User-input low-res velocity maps for seeding
            #TODO: Add functions that fetch best available velocities for Ant/GrIS or user-defined low-res velocities
            #Automatically query GoLive velocities here
            vx_fn = args.vx_fn 
            vy_fn = args.vy_fn 
            #Check for existence

            #HMA seeding
            vdir = '/nobackup/deshean/rpcdem/hma/velocity_jpl_amaury_2013-2015'
            vx_fn = os.path.join(vdir, 'PKH_WRS2_B8_2013_2015_snr5_n1_r170_res12.x_vel.TIF')
            vy_fn = os.path.join(vdir, 'PKH_WRS2_B8_2013_2015_snr5_n1_r170_res12.y_vel.TIF')

            if os.path.exists(vx_fn) and os.path.exists(vy_fn):
                ds1_clip = iolib.fn_getds(ds1_clip_fn)
                ds1_res = geolib.get_res(ds1_clip, square=True)[0]

                #Compute L_sub res - use this for output dimensions
                L_sub_fn = outprefix+'-L_sub.tif' 
                L_sub_ds = gdal.Open(L_sub_fn)
                L_sub_x_scale = float(ds1_clip.RasterXSize) / L_sub_ds.RasterXSize
                L_sub_y_scale = float(ds1_clip.RasterYSize) / L_sub_ds.RasterYSize
                L_sub_scale = np.max([L_sub_x_scale, L_sub_y_scale])
                L_sub_res = ds1_res * L_sub_scale

                #Since we are likely upsampling here, use cubicspline
                vx_ds_clip, vy_ds_clip = warplib.memwarp_multi_fn([vx_fn, vy_fn], extent=ds1_clip, \
                        t_srs=ds1_clip, res=L_sub_res, r='cubicspline')

                ds1_clip = None

                #Get vx and vy arrays
                vx = iolib.ds_getma(vx_ds_clip)
                vy = iolib.ds_getma(vy_ds_clip)

                #Determine time interval between inputs
                #Use to scaling of known low-res velocities
                t_factor = get_t_factor_fn(ds1_clip_fn, ds2_clip_fn, ds=vx_ds_clip)

                if t_factor is not None:
                    #Compute expected offset in scaled pixels 
                    dx = (vx*t_factor)/L_sub_res
                    dy = (vy*t_factor)/L_sub_res
                    #Note: Joughin and Rignot's values are positive y up!
                    #ASP is positive y down, so need to multiply these values by -1
                    #dy = -(vy*t_factor)/L_sub_res

                    #Should smooth/fill dx and dy

                    #If absolute search window is only 30x30
                    #Don't seed, just use fixed search window 
                    #search_window_area_thresh = 900
                    search_window_area_thresh = 0 
                    search_window = np.array([dx.min(), dy.min(), dx.max(), dy.max()])
                    dx_p = calcperc(dx, perc=(0.5, 99.5))
                    dy_p = calcperc(dy, perc=(0.5, 99.5))
                    search_window = np.array([dx_p[0], dy_p[0], dx_p[1], dy_p[1]])
                    search_window_area = (search_window[2]-search_window[0]) * (search_window[3]-search_window[1])
                    if search_window_area < search_window_area_thresh:
                        stereo_opt.extend(['--corr-seed-mode', '0'])
                        stereo_opt.append('--corr-search')
                        stereo_opt.extend([str(x) for x in search_window])
                        #pad_perc=0.1
                        #stereo_opt.extend(['--corr-sub-seed-percent', str(pad_perc)]
                    #Otherwise, generate a D_sub map from low-res velocity
                    else:
                        stereo_opt.extend(['--corr-seed-mode', '3'])
                        #This is relative to the D_sub scaled disparities
                        d_sub_fn = L_sub_fn.split('-L_sub')[0]+'-D_sub.tif' 
                        gen_d_sub(d_sub_fn, dx, dy)

    #If the above didn't generate a D_sub.tif for seeding, run stereo_corr to generate Low-res D_sub.tif
    if not os.path.exists(outprefix+'-D_sub.tif'):
        newopt = ['--compute-low-res-disparity-only',]
        run_cmd('stereo_corr', newopt+stereo_opt+stereo_args, msg='1.1: Low-res Correlation')
    #Copy projection info to D_sub
    geolib.copyproj(outprefix+'-L_sub.tif', outprefix+'-D_sub.tif')
      
    #Mask D_sub to limit correlation over bare earth surfaces
    #This _should_ be a better approach than masking input images, but stereo_corr doesn't honor D_sub
    #Still need to mask input images before stereo_pprc
    #Left this in here for reference, or if this changes in ASP
    if False:
        D_sub_ds = gdal.Open(outprefix+'-D_sub.tif', gdal.GA_Update)

        #Mask support - limit correlation only to rock/ice surfaces, no water/veg
        from demcoreg.dem_mask import get_nlcd, mask_nlcd
        nlcd_fn = get_nlcd()
        nlcd_ds = warplib.diskwarp_multi_fn([nlcd_fn,], extent=D_sub_ds, res=D_sub_ds, t_srs=D_sub_ds, r='near', outdir=outdir)[0]
        #validmask = mask_nlcd(nlcd_ds, valid='rock+ice')
        validmask = mask_nlcd(nlcd_ds, valid='not_forest', mask_glaciers=False)
        nlcd_mask_fn = os.path.join(outdir, 'nlcd_validmask.tif')
        iolib.writeGTiff(validmask, nlcd_mask_fn, nlcd_ds) 

        #Now apply to D_sub (band 3 is valid mask)
        #validmask = validmask.astype(int)
        for b in (1,2,3):
            dsub = iolib.ds_getma(D_sub_ds, b)
            dsub = np.ma.array(dsub, mask=~(validmask))
            D_sub_ds.GetRasterBand(b).WriteArray(dsub.filled())
        D_sub_ds = None

    #OK, finally run stereo_corr full-res integer correlation with appropriate seeding
    if not os.path.exists(outprefix+'-D.tif'):
        run_cmd('stereo_corr', stereo_opt+stereo_args, msg='1: Correlation')
        geolib.copyproj(ds1_clip_fn, outprefix+'-D.tif')

    #Run stereo_rfne
    if spr > 0:
        if not os.path.exists(outprefix+'-RD.tif'):
            run_cmd('stereo_rfne', stereo_opt+stereo_args, msg='2: Refinement')
            geolib.copyproj(ds1_clip_fn, outprefix+'-RD.tif')
        d_fn = make_ln(outdir, outprefix, '-RD.tif')
    else:
        ln_fn = outprefix+'-RD.tif'
        if os.path.lexists(ln_fn):
            os.remove(ln_fn)
        os.symlink(os.path.split(outprefix)[1]+'-D.tif', ln_fn)

    #Run stereo_fltr
    if not os.path.exists(outprefix+'-F.tif'):
        run_cmd('stereo_fltr', stereo_opt+stereo_args, msg='3: Filtering')
        geolib.copyproj(ds1_clip_fn, outprefix+'-F.tif')

    d_fn = make_ln(outdir, outprefix, '-F.tif')

    if smoothF and not os.path.exists(outprefix+'-F_smooth.tif'):
        print('Smoothing F.tif')
        from pygeotools.lib import filtlib 
        #Fill holes and smooth F
        F_fill_fn = outprefix+'-F_smooth.tif'
        F_ds = gdal.Open(outprefix+'-F.tif', gdal.GA_ReadOnly)
        #import dem_downsample_fill
        #F_fill_ds = dem_downsample_fill.gdalfill_ds(F_fill_ds)
        print('Creating F_smooth.tif')
        F_fill_ds = iolib.gtif_drv.CreateCopy(F_fill_fn, F_ds, 0, options=iolib.gdal_opt)
        F_ds = None
        for n in (1, 2):
            print('Smoothing band %i' % n)
            b = F_fill_ds.GetRasterBand(n)
            b_fill_bma = iolib.b_getma(b)
            #b_fill_bma = iolib.b_getma(dem_downsample_fill.gdalfill(b))
            #Filter extreme values (careful, could lose areas of valid data with fastest v)
            #b_fill_bma = filtlib.perc_fltr(b_fill_bma, perc=(0.01, 99.99))
            #These filters remove extreme values and fill data gaps
            #b_fill_bma = filtlib.median_fltr_skimage(b_fill_bma, radius=7, erode=0)
            #b_fill_bma = filtlib.median_fltr(b_fill_bma, fsize=7, origmask=True)
            #Gaussian filter
            b_fill_bma = filtlib.gauss_fltr_astropy(b_fill_bma, size=9)
            b.WriteArray(b_fill_bma)
        F_fill_ds = None
        d_fn = make_ln(outdir, outprefix, '-F_smooth.tif')

    print('\n%s' % datetime.now())
    print('%s UTC\n' % datetime.utcnow())

    #If time interval is specified, convert pixel displacements to rates
    if args.dt != 'none':
        #Check if vm.tif already exists
        #Should probably just overwrite by default
        #if os.path.exists(os.path.splitext(d_fn)[0]+'_vm.tif'):
        #    print("\nFound existing velocity magnitude map!\n"
        #else:
        #Generate output velocity products and figure
        #Requires that vmap repo is in PATH
        cmd = ['disp2v.py', d_fn]
        #Note: this will attempt to automatically determine control surfaces
        #disp2v.py will accept arbitrary mask, could pass through here
        if args.remove_offsets:
            cmd.append('-remove_offsets')
        cmd.extend(['-dt', args.dt])
        print("Converting disparities to velocities")
        print(cmd)
        subprocess.call(cmd)
Beispiel #20
0
outdir = 'stack_anomaly'
if not os.path.exists(outdir):
    os.makedirs(outdir)

#dem_fn_list = glob.glob('*8m_trans_warp.tif')
#stack = malib.DEMStack(dem_fn_list, med=True)
#dem_ref_fn = 'rainier_allgood_mos-tile-0_warp.tif'
#dem_ref = iolib.fn_getma(dem_ref_fn)

stack_fn = sys.argv[1]
#stack = malib.DEMStack(stack_fn=stack_fn, med=True)
#dem_ref = stack.stack_med
stack = malib.DEMStack(stack_fn=stack_fn)
dem_ref = stack.stack_mean
dem_ds = stack.get_ds()
dem_clim = malib.calcperc(dem_ref, (2,98))
dem_fn_list = stack.fn_list 
anomaly_stack = stack.ma_stack - dem_ref
anomaly_clim = np.max(np.abs(malib.calcperc(anomaly_stack, (1,99))))
anomaly_clim = (-anomaly_clim, anomaly_clim)

#for dem_fn in [dem_ref_fn]+dem_fn_list:
for n, dem_fn in enumerate(dem_fn_list):
    print('%i of %i: %s' % (n+1, len(dem_fn_list), dem_fn))
    #print(dem_fn)
    #dem_ds = iolib.fn_getds(dem_fn)
    #dem = iolib.ds_getma(dem_ds)
    dem_fn = stack.fn_list[n]
    #title = dem_fn
    title = None
    dem = stack.ma_stack[n]
Beispiel #21
0
def make_map(mb_dissolve_df=None,
             glac_df_mb=None,
             agg_df=None,
             col=('mb_mwea', 'mean'),
             border_df=None,
             crs=crs,
             extent=None,
             hs=None,
             hs_extent=None,
             clim=None,
             labels='val',
             title=None):

    fig, ax = plt.subplots(figsize=(10, 8))
    ax.set_aspect('equal')
    legend = add_legend(ax, sf=scaling_f)
    if title is not None:
        ax.set_title(title)

    if clim is None:
        #clim = (glac_df_mb[col].min(), glac_df_mb[col].max())
        clim = malib.calcperc_sym(mb_dissolve_df[col], perc=(1, 99))

    cmap = 'RdBu'
    if 'mb_mwea' in col:
        label = 'Mass Balance (m we/yr)'
    elif 'mb_Gta' in col:
        label = 'Mass Balance (Gt/yr)'
    elif 'meltwater' in col:
        label = 'Excess Meltwater Runoff (Gt/yr)'
        #Reverse, as these are negative values
        cmap = 'YlOrRd_r'
        #cmap = 'inferno'
        clim = malib.calcperc(mb_dissolve_df[col], perc=(0, 99))
    elif 't1' in col:
        cmap = 'inferno'
        label = 'Source Date (year)'

    #This is cartopy-enabled axes
    #ax = plt.axes(projection=crs)

    #Currently unsupported for AEA
    #gl = ax.gridlines(draw_labels=True, linewidth=0.5, color='gray', alpha=0.5, linestyle='--')

    if hs is not None:
        print("Plotting image")
        hs_style = {
            'cmap': 'gray',
            'origin': 'upper',
            'extent': cartopy_extent(hs_extent),
            'transform': crs
        }
        ax.imshow(hs, **hs_style)

    if border_df is not None:
        print("Plotting borders")
        border_style = {
            'facecolor': '0.65',
            'edgecolor': 'k',
            'linewidth': 0.7
        }
        border_df.plot(ax=ax, **border_style)

    if agg_df is not None:
        print("Plotting agg boundaries")
        #This was to get colored regions
        #agg_style = {'cmap':'cpt_rainbow', 'edgecolor':'none', 'linewidth':0, 'alpha':0.05}
        agg_style = {
            'cmap': 'summer',
            'edgecolor': 'none',
            'linewidth': 0,
            'alpha': 0.05
        }
        #agg_style = {'facecolor':'0.95','edgecolor':'k', 'linewidth':0.3, 'alpha':0.2}
        agg_df.plot(ax=ax, **agg_style)

    if glac_df_mb is not None:
        print("Plotting glacier polygons")
        glac_style = {'edgecolor': 'k', 'linewidth': 0.1, 'alpha': 0.2}
        #This plots mb color ramp for each glacier polygon
        #glac_ax = glac_df_mb.plot(ax=ax, column=col[0], cmap=cmap, vmin=clim[0], vmax=clim[1], **glac_style)
        #This plots outlines
        glac_ax = glac_df_mb.plot(ax=ax, facecolor='none', **glac_style)

    if agg_df is not None:
        agg_style = {'facecolor': 'none', 'edgecolor': 'w', 'linewidth': 0.5}
        agg_df.plot(ax=ax, **agg_style)

    #https://stackoverflow.com/questions/36008648/colorbar-on-geopandas
    # fake up the array of the scalar mappable so we can plot colorbar. Urgh...
    sc = plt.cm.ScalarMappable(cmap=cmap,
                               norm=plt.Normalize(vmin=clim[0], vmax=clim[1]))
    sc._A = []

    if mb_dissolve_df is not None:
        print("Plotting scatterplot of %s values" % (col, ))
        #Plot single values for region or basin
        x = mb_dissolve_df['centroid_x']
        y = mb_dissolve_df['centroid_y']
        #Scale by total glacier area in each polygon
        s = scaling_f * mb_dissolve_df[('Area_all', 'sum')]
        c = mb_dissolve_df[col]
        sc_style = {
            'cmap': cmap,
            'edgecolor': 'k',
            'linewidth': 0.5,
            'alpha': 0.8
        }
        sc = ax.scatter(x, y, s, c, vmin=clim[0], vmax=clim[1], **sc_style)
        #Add labels
        text_kw = {'family': 'sans-serif', 'fontsize': 8, 'color': 'k'}
        if labels is not None:
            print("Adding annotations")
            for k, v in mb_dissolve_df.iterrows():
                #lbl = '%0.2f +/- %0.2f' % (v[col], v[(col[0]+'_sigma',col[1])])
                if labels == 'name+val':
                    lbl = '%s\n%+0.2f' % (k, v[col])
                else:
                    lbl = '%+0.2f' % v[col]
                #ax.annotate(lbl, xy=(v['centroid_x'],v['centroid_y']), xytext=(1,0), textcoords='offset points', family='sans-serif', fontsize=6, color='darkgreen')
                txt = ax.annotate(lbl,
                                  xy=(v['centroid_x'], v['centroid_y']),
                                  ha='center',
                                  va='center',
                                  **text_kw)
                txt.set_path_effects([
                    path_effects.Stroke(linewidth=0.75, foreground='w'),
                    path_effects.Normal()
                ])

    #This is minx, miny, maxx, maxy
    if extent is None:
        #if glac_df_mb is not None:
        #    extent = glac_df_mb.total_bounds
        #else:
        extent = mb_dissolve_df.total_bounds

    #For cartopy axes
    #ax.set_extent(cartopy_extent(extent), crs=crs)
    #Pad extent so labels fit within map
    #extent = geolib.pad_extent(extent, perc=0.01, uniform=True)
    ax.set_xlim(extent[0], extent[2])
    ax.set_ylim(extent[1], extent[3])

    #Adding colorbar doesn't work with the cartopy axes
    pltlib.add_cbar(ax, sc, label=label)
    pltlib.add_scalebar(ax, res=1)
    pltlib.hide_ticks(ax)

    plt.tight_layout()

    return fig
Beispiel #22
0
def main2(args):
    #Should check that files exist
    dem1_fn = args.ref_fn
    dem2_fn = args.src_fn
    mode = args.mode
    apply_mask = not args.nomask
    max_offset_m = args.max_offset
    tiltcorr = args.tiltcorr

    #These are tolerances (in meters) to stop iteration
    tol = args.tol
    min_dx = tol
    min_dy = tol
    min_dz = tol

    #Maximum number of iterations
    max_n = 10

    outdir = args.outdir
    if outdir is None:
        outdir = os.path.splitext(dem2_fn)[0] + '_dem_align'

    if not os.path.exists(outdir):
        os.makedirs(outdir)

    outprefix = '%s_%s' % (os.path.splitext(os.path.split(dem2_fn)[-1])[0], \
            os.path.splitext(os.path.split(dem1_fn)[-1])[0])
    outprefix = os.path.join(outdir, outprefix)

    print("\nReference: %s" % dem1_fn)
    print("Source: %s" % dem2_fn)
    print("Mode: %s" % mode)
    print("Output: %s\n" % outprefix)

    dem2_ds = gdal.Open(dem2_fn, gdal.GA_ReadOnly)
    #Often the "ref" DEM is high-res lidar or similar
    #This is a shortcut to resample to match "source" DEM
    dem1_ds = warplib.memwarp_multi_fn([
        dem1_fn,
    ],
                                       res=dem2_ds,
                                       extent=dem2_ds,
                                       t_srs=dem2_ds)[0]
    #dem1_ds = gdal.Open(dem1_fn, gdal.GA_ReadOnly)

    #Create a copy to be updated in place
    dem2_ds_align = iolib.mem_drv.CreateCopy('', dem2_ds, 0)
    #dem2_ds_align = dem2_ds

    #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(dem1_ds,
                                                      dem2_ds_align,
                                                      dem2_fn,
                                                      mode,
                                                      max_offset_m,
                                                      apply_mask=apply_mask)
        if n == 1:
            static_mask_orig = static_mask
        xyz_shift_str_iter = "dx=%+0.2fm, dy=%+0.2fm, dz=%+0.2fm" % (dx, dy,
                                                                     dz)
        print("Incremental offset: %s" % xyz_shift_str_iter)

        #Should make an animation of this converging
        if fig is not None:
            dst_fn = outprefix + '_%s_iter%i_plot.png' % (mode, n)
            print("Writing offset plot: %s" % dst_fn)
            fig.gca().set_title(xyz_shift_str_iter)
            fig.savefig(dst_fn, dpi=300, bbox_inches='tight', pad_inches=0.1)

        #Apply the horizontal shift to the original dataset
        dem2_ds_align = coreglib.apply_xy_shift(dem2_ds_align,
                                                dx,
                                                dy,
                                                createcopy=False)
        dem2_ds_align = coreglib.apply_z_shift(dem2_ds_align,
                                               dz,
                                               createcopy=False)

        dx_total += dx
        dy_total += dy
        dz_total += dz
        print("Cumulative offset: dx=%+0.2fm, dy=%+0.2fm, dz=%+0.2fm" %
              (dx_total, dy_total, dz_total))

        #Fit plane to residuals and remove
        #Might be better to do this after converging
        """
        if tiltcorr:
            print("Applying planar tilt correction")
            gt = dem2_ds_align.GetGeoTransform()
            #Need to compute diff_euler here
            #Copy portions of compute_offset, create new function 
            vals, resid, coeff = geolib.ma_fitplane(diff_euler_align, gt, perc=(4, 96))
            dem2_ds_align = coreglib.apply_z_shift(dem2_ds_align, -vals, createcopy=False)
        """

        n += 1
        print("\n")
        #If magnitude of shift in all directions is less than tol
        #if n > max_n 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)
        if n > max_n or dm < tol:
            break

    #String to append to output filenames
    xyz_shift_str_cum = '_%s_x%+0.2f_y%+0.2f_z%+0.2f' % (mode, dx_total,
                                                         dy_total, dz_total)
    if tiltcorr:
        xyz_shift_str_cum += "_tiltcorr"

    #Compute original elevation difference
    if True:
        dem1_clip_ds, dem2_clip_ds = warplib.memwarp_multi([dem1_ds, dem2_ds], \
                res='max', extent='intersection', t_srs=dem2_ds)
        dem1_orig = iolib.ds_getma(dem1_clip_ds, 1)
        dem2_orig = iolib.ds_getma(dem2_clip_ds, 1)
        diff_euler_orig = dem2_orig - dem1_orig
        if not apply_mask:
            static_mask_orig = np.ma.getmaskarray(diff_euler_orig)
        diff_euler_orig_compressed = diff_euler_orig[~static_mask_orig]
        diff_euler_orig_stats = np.array(
            malib.print_stats(diff_euler_orig_compressed))

        #Write out original eulerian difference map
        print(
            "Writing out original euler difference map for common intersection before alignment"
        )
        dst_fn = outprefix + '_orig_dz_eul.tif'
        iolib.writeGTiff(diff_euler_orig, dst_fn, dem1_clip_ds)

    #Compute final elevation difference
    if True:
        dem1_clip_ds_align, dem2_clip_ds_align = warplib.memwarp_multi([dem1_ds, dem2_ds_align], \
                res='max', extent='intersection', t_srs=dem2_ds_align)
        dem1_align = iolib.ds_getma(dem1_clip_ds_align, 1)
        dem2_align = iolib.ds_getma(dem2_clip_ds_align, 1)
        diff_euler_align = dem2_align - dem1_align
        if not apply_mask:
            static_mask = np.ma.getmaskarray(diff_euler_align)
        diff_euler_align_compressed = diff_euler_align[~static_mask]
        diff_euler_align_stats = np.array(
            malib.print_stats(diff_euler_align_compressed))

        #Fit plane to residuals and remove
        if tiltcorr:
            print("Applying planar tilt correction")
            gt = dem1_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_fitplane(np.ma.array(diff_euler_align, mask=static_mask), \
                    gt, perc=(4, 96), origmask=False)
            #Remove planar offset from difference map
            diff_euler_align -= vals
            #Remove planar offset from aligned dem2
            #Note: dimensions of ds and vals will be different as vals are computed for clipped intersection
            #Recompute planar offset for dem2_ds_align extent
            xgrid, ygrid = geolib.get_xy_grids(dem2_ds_align)
            vals = coeff[0] * xgrid + coeff[1] * ygrid + coeff[2]
            dem2_ds_align = coreglib.apply_z_shift(dem2_ds_align,
                                                   -vals,
                                                   createcopy=False)
            if not apply_mask:
                static_mask = np.ma.getmaskarray(diff_euler_align)
            diff_euler_align_compressed = diff_euler_align[~static_mask]
            diff_euler_align_stats = np.array(
                malib.print_stats(diff_euler_align_compressed))
            print("Creating fitplane plot")
            fig, ax = plt.subplots(figsize=(6, 6))
            fitplane_clim = malib.calcperc(vals, (2, 98))
            im = ax.imshow(vals, cmap='cpt_rainbow', clim=fitplane_clim)
            res = float(geolib.get_res(dem2_clip_ds, square=True)[0])
            pltlib.add_scalebar(ax, res=res)
            pltlib.hide_ticks(ax)
            pltlib.add_cbar(ax, im, label='Fit plane residuals (m)')
            fig.tight_layout()
            dst_fn1 = outprefix + '%s_align_dz_eul_fitplane.png' % xyz_shift_str_cum
            print("Writing out figure: %s" % dst_fn1)
            fig.savefig(dst_fn1, dpi=300, bbox_inches='tight', pad_inches=0.1)

        #Compute higher-order fits?
        #Could also attempt to model along-track and cross-track artifacts

        #Write out aligned eulerian difference map for clipped extent with vertial offset removed
        dst_fn = outprefix + '%s_align_dz_eul.tif' % xyz_shift_str_cum
        print(
            "Writing out aligned difference map with median vertical offset removed"
        )
        iolib.writeGTiff(diff_euler_align, dst_fn, dem1_clip_ds)

    #Write out aligned dem_2 with vertial offset removed
    if True:
        dst_fn2 = outprefix + '%s_align.tif' % xyz_shift_str_cum
        print(
            "Writing out shifted dem2 with median vertical offset removed: %s"
            % dst_fn2)
        #Might be cleaner way to write out MEM ds directly to disk
        dem2_align = iolib.ds_getma(dem2_ds_align)
        iolib.writeGTiff(dem2_align, dst_fn2, dem2_ds_align)
        dem2_ds_align = None

    #Create output plot
    if True:
        print("Creating final plot")
        dem1_hs = geolib.gdaldem_mem_ma(dem1_orig, dem1_clip_ds, returnma=True)
        dem2_hs = geolib.gdaldem_mem_ma(dem2_orig, dem2_clip_ds, returnma=True)
        f, axa = plt.subplots(2, 3, figsize=(11, 8.5))
        for ax in axa.ravel()[:-1]:
            ax.set_facecolor('k')
            pltlib.hide_ticks(ax)
        dem_clim = malib.calcperc(dem1_orig, (2, 98))
        axa[0, 0].imshow(dem1_hs, cmap='gray')
        axa[0, 0].imshow(dem1_orig,
                         cmap='cpt_rainbow',
                         clim=dem_clim,
                         alpha=0.6)
        res = float(geolib.get_res(dem1_clip_ds, square=True)[0])
        pltlib.add_scalebar(axa[0, 0], res=res)
        axa[0, 0].set_title('Reference DEM')
        axa[0, 1].imshow(dem2_hs, cmap='gray')
        axa[0, 1].imshow(dem2_orig,
                         cmap='cpt_rainbow',
                         clim=dem_clim,
                         alpha=0.6)
        axa[0, 1].set_title('Source DEM')
        axa[0, 2].imshow(~static_mask_orig, clim=(0, 1), cmap='gray')
        axa[0, 2].set_title('Surfaces for co-registration')
        dz_clim = malib.calcperc_sym(diff_euler_orig_compressed, (5, 95))
        im = axa[1, 0].imshow(diff_euler_orig, cmap='RdBu', clim=dz_clim)
        pltlib.add_cbar(axa[1, 0], im, label=None)
        axa[1, 0].set_title('Elev. Diff. Before (m)')
        im = axa[1, 1].imshow(diff_euler_align, cmap='RdBu', clim=dz_clim)
        pltlib.add_cbar(axa[1, 1], im, label=None)
        axa[1, 1].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, 2].hist(diff_euler_orig_compressed,
                       bins,
                       color='g',
                       label='Before',
                       alpha=0.5)
        axa[1, 2].hist(diff_euler_align_compressed,
                       bins,
                       color='b',
                       label='After',
                       alpha=0.5)
        axa[1, 2].axvline(0, color='k', linewidth=0.5, linestyle=':')
        axa[1, 2].set_xlabel('Elev. Diff. (m)')
        axa[1, 2].set_ylabel('Count (px)')
        axa[1, 2].set_title("Source - Reference")
        #axa[1,2].legend(loc='upper right')
        #before_str = 'Before\nmean: %0.2f\nstd: %0.2f\nmed: %0.2f\nnmad: %0.2f' % tuple(diff_euler_orig_stats[np.array((3,4,5,6))])
        #after_str = 'After\nmean: %0.2f\nstd: %0.2f\nmed: %0.2f\nnmad: %0.2f' % tuple(diff_euler_align_stats[np.array((3,4,5,6))])
        before_str = 'Before\nmed: %0.2f\nnmad: %0.2f' % tuple(
            diff_euler_orig_stats[np.array((5, 6))])
        axa[1, 2].text(0.05,
                       0.95,
                       before_str,
                       va='top',
                       color='g',
                       transform=axa[1, 2].transAxes)
        after_str = 'After\nmed: %0.2f\nnmad: %0.2f' % tuple(
            diff_euler_align_stats[np.array((5, 6))])
        axa[1, 2].text(0.65,
                       0.95,
                       after_str,
                       va='top',
                       color='b',
                       transform=axa[1, 2].transAxes)

        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)

        dst_fn = outprefix + '%s_align.png' % xyz_shift_str_cum
        print("Writing out figure: %s" % dst_fn)
        f.savefig(dst_fn, dpi=300, bbox_inches='tight', pad_inches=0.1)

        #Removing residual planar tilt can introduce additional slope/aspect dependent offset
        #Want to run another round of main dem_align after removing planar tilt
        if tiltcorr:
            print("\n Rerunning after applying tilt correction \n")
            #Create copy of original arguments
            import copy
            args2 = copy.copy(args)
            #Use aligned, tilt-corrected DEM as input src_fn for second round
            args2.src_fn = dst_fn2
            #Assume we've already corrected most of the tilt during first round (also prevents endless loop)
            args2.tiltcorr = False
            main2(args2)
Beispiel #23
0
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import ImageGrid

from pygeotools.lib import iolib, timelib, geolib, malib
from imview.lib import pltlib

add_cbar = False

#dem_fn_list = glob.glob('*32m.tif')
#dem_ref_fn = 'rainier_allgood_mos-tile-0_warp.tif'
dem_fn_list = sys.argv[1:]

dems = np.ma.array([iolib.fn_getma_sub(fn) for fn in dem_fn_list])
dem_clim = malib.calcperc(dems, (2, 98))

w = 10.0
h = 7.5
f = plt.figure(figsize=(w, h))

n = len(dem_fn_list)
ncols = int(np.ceil(np.sqrt((float(n) * w) / h)))
nrows = int(np.ceil(float(n) / ncols))
#nrows = int(np.sqrt(n))+1
#ncols = nrows

if add_cbar:
    grid = ImageGrid(f,
                     111,
                     nrows_ncols=(nrows, ncols),
Beispiel #24
0
    z_fltr_mask = glas_pts_fltr_mask[:,zcol]
    mX_fltr_mask, mY_fltr_mask, mZ = geolib.cT_helper(x_fltr_mask, y_fltr_mask, 0, pt_srs, geolib.get_ds_srs(dem_mask_ds))
    pX_fltr_mask, pY_fltr_mask = geolib.mapToPixel(mX_fltr_mask, mY_fltr_mask, dem_mask_ds.GetGeoTransform())
    pX_fltr_mask = np.atleast_1d(pX_fltr_mask)
    pY_fltr_mask = np.atleast_1d(pY_fltr_mask)

    dz = z_fltr_mask - samp[samp_idx,0]

    if True:
        print("Creating plot of %i output points" % x_fltr.shape[0])
        fig_kw = {'figsize':(10,7.5)}
        fig, (ax1, ax2, ax3, ax4) = plt.subplots(1, 4, sharex=True, sharey=True, **fig_kw)

        #Plot DEM color shaded relief
        hs_ma = geolib.gdaldem_wrapper(dem_fn)
        hs_clim = malib.calcperc(hs_ma, perc=(0.5, 99.5))
        dem_clim = malib.calcperc(dem_ma)
        ax1.imshow(hs_ma, cmap='gray', clim=hs_clim)
        im1 = ax1.imshow(dem_ma, cmap=cpt_rainbow, clim=dem_clim, alpha=0.5)
        cbar = pltlib.add_cbar(ax1, im1, label='DEM Elev. (m WGS84)')
       
        #Plot all color points over shaded relief
        im2 = ax2.imshow(hs_ma, cmap='gray', clim=hs_clim, alpha=0.5)
        #Plot all points in black
        sc2 = ax2.scatter(pX_fltr, pY_fltr, s=0.5, c='k', edgecolors='none')
        #Plot valid in color
        c = z_fltr_mask 
        sc2 = ax2.scatter(pX_fltr_mask, pY_fltr_mask, s=0.5, c=c, cmap=cpt_rainbow, vmin=dem_clim[0], vmax=dem_clim[1], edgecolors='none')
        cbar = pltlib.add_cbar(ax2, sc2, label='Pt Elev. (m WGS84)')

        #Plot time
Beispiel #25
0
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
Beispiel #26
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)
Beispiel #27
0
def main():
    parser = get_parser()
    args = parser.parse_args()

    fn_list = args.fn_list

    print
    print "Reviewing %i images" % len(fn_list)
    print

    good = []
    bad = []

    good_fn = "good_list.txt"
    if args.prefix is not None:
        good_fn = args.prefix + '_' + good_fn
    good_f = open(good_fn, 'a', 0)

    bad_fn = "bad_list.txt"
    if args.prefix is not None:
        bad_fn = args.prefix + '_' + bad_fn
    bad_f = open(bad_fn, 'a', 0)

    fig = plt.figure()
    ax = fig.add_subplot(111)
    plt.ion()
    plt.show()

    #Use PIL Image
    basic = False

    for fn in fn_list:
        print fn
        plt.clf()
        if basic:
            im = mpimg.imread(fn)
            if im.ndim == 3:
                cmap = None
            plt.imshow(im, cmap=cmap)
        else:
            ds = gdal.Open(fn)
            a = iolib.gdal_getma_sub(ds)
            perc = malib.calcperc(a)
            cmap = 'cpt_rainbow'
            alpha = 1.0
            if '_hs' in fn:
                cmap = 'gray'
            else:
                hs_fn = os.path.splitext(fn)[0] + '_hs.tif'
                if os.path.exists(hs_fn):
                    hs_ds = gdal.Open(hs_fn)
                    hs = iolib.gdal_getma_sub(hs_ds)
                    hs_perc = malib.calcperc(hs)
                    plt.imshow(hs, cmap='gray', clim=hs_perc)
                    alpha = 0.5
            plt.imshow(a, cmap=cmap, clim=perc, alpha=alpha)
        fig.canvas.draw()

        if query_yes_no("{} good?".format(fn)):
            good.append(fn)
            good_f.write("%s\n" % fn)
        else:
            bad.append(fn)
            bad_f.write("%s\n" % fn)

    plt.close()

    print
    print "Good: %i" % (len(good))
    print good
    print
    print "Bad: %i" % (len(bad))
    print bad
    print

    good_f.close()
    bad_f.close()
Beispiel #28
0
    diff_euler_perc = 100.0 * diff_euler / dem1
    dst_fn = os.path.join(outdir, outprefix + '_dz_eul_perc.tif')
    print dst_fn
    iolib.writeGTiff(diff_euler_perc, dst_fn, dem1_ds, ndv=diffndv)

#def compute_dh_vs_z(ref_dem, dh, nbins=20, binwidth=None):
if False:
    print "Compute dh/dt vs. elevation"
    nbins = 20
    #binwidth = None
    binwidth = 50
    ref_dem = dem1
    dh = diff_euler
    if rates:
        dh = diff_euler / t_factor
    min, max = malib.calcperc(ref_dem)
    #If binwidth specified, override
    if binwidth is not None:
        nbins = None
    if nbins:
        edges = np.linspace(min, max, num=nbins)
        binwidth = edges[1] - edges[0]
    else:
        edges = np.arange(min, max, binwidth)
    diff_euler_bincenters = []
    diff_euler_binvals = []
    diff_euler_bincount = []
    for i in range(edges.size - 1):
        print "%i of %i: %0.1f to %0.1f m" % (i, edges.size - 1, edges[i],
                                              edges[i + 1])
        idx = np.logical_and((ref_dem > edges[i]).data,
Beispiel #29
0
        continue

    glac_geom_mask = geolib.geom2mask(glac_geom, ds_list[0])
    z1 = np.ma.array(iolib.ds_getma(ds_list[0]), mask=glac_geom_mask)
    z2 = np.ma.array(z2, mask=glac_geom_mask)
    dz = z2 - z1
    if dz.count() == 0:
        print("No valid dz pixels")
        continue

    filter_outliers = True
    #Remove clearly bogus pixels
    if filter_outliers:
        #bad_perc = (0.1, 99.9)
        bad_perc = (1, 99)
        rangelim = malib.calcperc(dz, bad_perc)
        dz = np.ma.masked_outside(dz, *rangelim)

    ds_res = geolib.get_res(ds_list[0])
    valid_area = dz.count() * ds_res[0] * ds_res[1]
    valid_area_perc = valid_area / glac_area
    min_valid_area_perc = 0.80
    if valid_area_perc < min_valid_area_perc:
        print(
            "Not enough valid pixels. %0.1f%% percent of glacier polygon area"
            % (100 * valid_area_perc))
        continue

    #Rasterize NED source dates
    if site == 'conus':
        z1_date_r_ds = iolib.mem_drv.CreateCopy('', ds_list[0])
Beispiel #30
0
def main():
    parser = getparser()
    args = parser.parse_args()
    hs_overlay = args.hs_overlay
    kmz = args.kmz
    opacity = args.alpha
    cmap = args.cmap

    fn = args.fn
    print(fn)
    ds = gdal.Open(fn) 
    b = ds.GetRasterBand(1)
    ndv = iolib.get_ndv_b(b)

    print("Loading input raster")
    a = iolib.b_getma(b)

    clim = args.clim
    if clim is None:
        clim = malib.calcperc(a, (2, 98))

    print("Generating color ramp")
    cramp_fn = os.path.splitext(fn)[0]+'_ramp.txt'
    ncolors = 21 
    csteps = np.linspace(0, 1, ncolors)
    cm = plt.get_cmap(cmap)
    #Compute raster values between specified min/max
    vals = np.linspace(clim[0], clim[1], ncolors)
    #Compute rgba for these values on the given color ramp
    cvals = cm(csteps, bytes=True)    
    #Combine into single array
    cramp = np.vstack((vals, cvals.T)).T
    #Set alpha to desired transparency
    cramp[:,-1] = opacity * 255
    header = '#val r g b a'
    footer = 'nv %s %s %s 0' % (ndv, ndv, ndv)
    np.savetxt(cramp_fn, cramp, fmt='%f %i %i %i %i', header=header, footer=footer, comments='')

    print("Generating gdaldem color-relief tif")
    color_fn = os.path.splitext(fn)[0]+'_color.tif'
    if not os.path.exists(color_fn):
        #cmd = 'gdaldem color-relief -nearest_color_entry -alpha %s %s %s' % (fn, cramp_fn, color_fn)
        cmd = ['gdaldem', 'color-relief', '-alpha']
        cmd.extend(iolib.gdal_opt_co)
        cmd.extend([fn, cramp_fn, color_fn])
        print(' '.join(cmd))
        subprocess.call(cmd, shell=False)

    if kmz:
        make_kmz(color_fn)

    if hs_overlay:
        print("Generating shaded relief")
        hs_fn = os.path.splitext(fn)[0]+'_hs_az315.tif'
        #Check to see if file exists, or if provided as input
        if not os.path.exists(hs_fn):
            cmd = ['gdaldem', 'hillshade']
            #cmd.extend('-compute_edges')
            cmd.extend(iolib.gdal_opt_co)
            cmd.extend([fn, hs_fn])
            print(' '.join(cmd))
            subprocess.call(cmd, shell=False)

        print("Loading shaded relief and calculating percentile stretch")
        hs = iolib.fn_getma(hs_fn)
        hs_clim = malib.calcperc(hs, (1, 99))
        #Since imagemagick was compiled with quantum depth 16, need to scale levels
        hs_clim = (hs_clim[0]*65535/255., hs_clim[1]*65535/255.)

        print("Generating color composite shaded relief")
        overlay_fn = os.path.splitext(color_fn)[0]+'_hs.tif'
        if not os.path.exists(overlay_fn):
            #Can also try hsvmerge.py
            #cmd = 'composite %s %s -dissolve "%i" %s' % (color_fn, hs_fn, opacity*100, overlay_fn)
            #This uses imagemagick composite function
            #For some reason, this level adjustment is not working
            #cmd = ['convert', hs_fn, color_fn, '-compose', 'dissolve', \
            cmd = ['convert', hs_fn, '-level', '%i,%i' % hs_clim, color_fn, '-compose', 'dissolve', \
            '-define', 'compose:args=%i' % int(opacity*100), '-composite', '-compress', 'LZW', overlay_fn]
            #cmd = ['composite', color_fn, hs_fn, '-dissolve', str(int(opacity*100)), '-compress', 'LZW', overlay_fn]
            print(' '.join(cmd))
            subprocess.call(cmd, shell=False)

            print("Updating georeferencing metadata")
            out_ndv = 0
            overlay_ds = gdal.Open(overlay_fn, gdal.GA_Update)
            overlay_ds.SetProjection(ds.GetProjection())
            overlay_ds.SetGeoTransform(ds.GetGeoTransform())
            for n in range(overlay_ds.RasterCount):
                overlay_ds.GetRasterBand(n+1).SetNoDataValue(out_ndv)
            overlay_ds = None

            #Rewrite with blocks and LZW-compression
            print("Creating tiled and compressed version")
            tmp_fn = '/tmp/temp_%s.tif' % os.getpid()
            cmd = ['gdal_translate',]
            cmd.extend(iolib.gdal_opt_co)
            cmd.extend((overlay_fn, tmp_fn))
            print(' '.join(cmd))
            subprocess.call(cmd, shell=False)
            shutil.move(tmp_fn, overlay_fn)

        if not os.path.exists(overlay_fn+'.ovr'):
            print("Generating overviews")
            cmd = ['gdaladdo', '-ro', '-r', 'average', '--config', \
            'COMPRESS_OVERVIEW', 'LZW', '--config', 'BIGTIFF_OVERVIEW', 'YES', \
            overlay_fn, '2', '4', '8', '16', '32', '64']
            print(' '.join(cmd))
            subprocess.call(cmd, shell=False)

        if kmz:
            make_kmz(overlay_fn)