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

    src_fn = args.src_fn
    new_ndv = args.new_ndv

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

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

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

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

    #Load masked array
    bma = iolib.ds_getma(ds)
    #Set new fill value
    bma.set_fill_value(new_ndv)
    #Fill ma with new value and write out
    iolib.writeGTiff(bma.filled(), out_fn, ds, ndv=new_ndv)
示例#2
0
def warp(src_ds, res=None, extent=None, t_srs=None, r='cubic', driver=mem_drv, dst_fn=None, dst_ndv=None, verbose=True):
    """Warp an input dataset with predetermined arguments specifying output res/extent/srs

    This is the function that actually calls gdal.ReprojectImage
    
    Parameters
    ----------
    src_ds : gdal.Dataset object
        Dataset to be warped
    res : float
        Desired output resolution
    extent : list of float
        Desired output extent in t_srs coordinate system
    t_srs : osr.SpatialReference()
        Desired output spatial reference
    r : str
        Desired resampling algorithm
    driver : GDAL Driver to use for warp 
        Either MEM or GTiff
    dst_fn : str
        Output filename (for disk warp)
    dst_ndv : float
        Desired output NoData Value

    Returns
    -------
    dst_ds : gdal.Dataset object
        Warped dataset (either in memory or on disk)

    """
    src_srs = geolib.get_ds_srs(src_ds)
    
    if t_srs is None:
        t_srs = geolib.get_ds_srs(src_ds)
    
    src_gt = src_ds.GetGeoTransform()
    #Note: get_res returns [x_res, y_res]
    #Could just use gt here and average x_res and y_res
    src_res = geolib.get_res(src_ds, t_srs=t_srs, square=True)[0]

    if res is None:
        res = src_res

    if extent is None:
        extent = geolib.ds_geom_extent(src_ds, t_srs=t_srs)
    
    #Note: GDAL Lanczos creates block artifacts
    #Wait for gdalwarp to support gaussian resampling
    #Want to use Lanczos for downsampling
    #if src_res < res:
    #    gra = gdal.GRA_Lanczos
    #See http://blog.codinghorror.com/better-image-resizing/
    # Suggests cubic for downsampling, bilinear for upsampling
    #    gra = gdal.GRA_Cubic
    #Cubic for upsampling
    #elif src_res >= res:
    #    gra = gdal.GRA_Bilinear

    gra = parse_rs_alg(r)

    #At this point, the resolution and extent values must be float
    #Extent must be list
    res = float(res)
    extent = [float(i) for i in extent]

    #Might want to move this to memwarp_multi, keep memwarp basic w/ gdal.GRA types

    #Create progress function
    prog_func = None
    if verbose:
        prog_func = gdal.TermProgress
    
    if dst_fn is None:
        #This is a dummy fn if only in mem, but can be accessed later via GetFileList()
        #Actually, no, doesn't look like the filename survivies
        dst_fn = ''
    
    #Compute output image dimensions
    dst_nl = int(round((extent[3] - extent[1])/res))
    dst_ns = int(round((extent[2] - extent[0])/res))
    #dst_nl = int(math.ceil((extent[3] - extent[1])/res))
    #dst_ns = int(math.ceil((extent[2] - extent[0])/res))
    #dst_nl = int(math.floor((extent[3] - extent[1])/res))
    #dst_ns = int(math.floor((extent[2] - extent[0])/res))
    if verbose:
        print('nl: %i ns: %i res: %0.3f' % (dst_nl, dst_ns, res))
    #Create output dataset
    src_b = src_ds.GetRasterBand(1)
    src_dt = src_b.DataType
    src_nl = src_ds.RasterYSize
    src_ns = src_ds.RasterXSize

    dst_ds = driver.Create(dst_fn, dst_ns, dst_nl, src_ds.RasterCount, src_dt) 

    dst_ds.SetProjection(t_srs.ExportToWkt())
    #Might be an issue to use src_gt rotation terms here with arbitrary extent/res
    dst_gt = [extent[0], res, src_gt[2], extent[3], src_gt[4], -res]
    dst_ds.SetGeoTransform(dst_gt)
   
    #This will smooth the input before downsampling to prevent aliasing, fill gaps
    #Pretty inefficent, as we need to create another intermediate dataset
    gauss = False 

    for n in range(1, src_ds.RasterCount+1):
        if dst_ndv is None:
            src_b = src_ds.GetRasterBand(n)
            src_ndv = iolib.get_ndv_b(src_b)
            dst_ndv = src_ndv
        b = dst_ds.GetRasterBand(n)
        b.SetNoDataValue(dst_ndv)
        b.Fill(dst_ndv)

        if gauss:
            from pygeotools.lib import filtlib
            #src_a = src_b.GetVirtualMemArray()
            #Compute resampling ratio to determine filter window size
            res_ratio = float(res)/src_res
            if verbose:
                print("Resampling factor: %0.3f" % res_ratio)
            #Might be more efficient to do iterative gauss filter with size 3, rather than larger windows
            f_size = math.floor(res_ratio/2.)*2+1
            #This is conservative to avoid filling holes with noise
            #f_size = math.floor(res_ratio/2.)*2-1
            if f_size <= 1:
                continue

            if verbose:
                print("Smoothing window size: %i" % f_size)
            #Create temp dataset to store filtered array - avoid overwriting original
            temp_ds = driver.Create('', src_ns, src_nl, src_ds.RasterCount, src_dt) 
            temp_ds.SetProjection(src_srs.ExportToWkt())
            temp_ds.SetGeoTransform(src_gt)
            temp_b = temp_ds.GetRasterBand(n)
            temp_b.SetNoDataValue(dst_ndv)
            temp_b.Fill(dst_ndv)

            src_a = iolib.b_getma(src_b)
            src_a = filtlib.gauss_fltr_astropy(src_a, size=f_size)
            #Want to run with maskfill, so only fills gaps, without expanding isolated points
            temp_b.WriteArray(src_a)
            src_ds = temp_ds
            
            #In theory, NN should be fine since we already smoothed.  In practice, cubic still provides slightly better results
            #gra = gdal.GRA_NearestNeighbour
    
    """
    if not verbose:
        #Suppress GDAL progress bar
        orig_stdout = sys.stdout
        sys.stdout = open(os.devnull, 'w')
    """

    #Note: default maxerror=0.0, second 0.0 argument
    gdal.ReprojectImage(src_ds, dst_ds, src_srs.ExportToWkt(), t_srs.ExportToWkt(), gra, 0.0, 0.0, prog_func)

    """
    if not verbose:
        sys.stdout.close()
        sys.stdout = orig_stdout
    """

    #Note: this is now done in diskwarp
    #Write out to disk
    #if driver != mem_drv:
    #    dst_ds.FlushCache()

    #Return GDAL dataset object in memory
    return dst_ds
示例#3
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)