def raster_overlap(file_A, file_B, outpath, NoData_A=None, NoData_B=None): """ Finds overlaping area between two raster images. this function examines two images and outputs a raster identifying pixels where both rasters have non-NoData values. Output raster has 1's where both images have data and 0's where one or both images are missing data. inputs: file_A the first file file_B the second file outpath the output filename for the desired output. must end in ".tif" NoData_A the NoData value of file A NoData_B the NoData value of file B This function automatically invokes clip_and_snap null_define """ if not is_rast(file_A) or not is_rast(file_B): raise Exception(' both inputs must be rasters!') # load the rasters as numpy arays. a, metaA = to_numpy(file_A) b, metaB = to_numpy(file_B) # set no_datas if NoData_A is None: NoData_A = metaA.NoData_Value if NoData_B is None: NoData_B = metaB.NoData_Value # spatially match the rasters print('preparing input rasters!') clip_and_snap(file_A, file_B, outpath.replace(".shp", ".tif"), NoData_B) # reload the rasters as numpy arrays now that spatial matching is done a, metaA = to_numpy(file_A) b, metaB = to_numpy(file_B) # create work matrix and find the overlap print('Finding overlaping pixels!') Workmatrix = a.mask + b.mask Workmatrix = Workmatrix.astype('uint8') Workmatrix[Workmatrix == 1] = 2 print('Saving overlap file!') metaA.numpy_datatype = 'uint8' from_numpy(Workmatrix, metaA, outpath.replace(".shp", ".tif"), NoData_Value=2) arcpy.RasterToPolygon_conversion(outpath.replace(".shp", ".tif"), outpath.replace(".tif", ".shp"), 'NO_SIMPLIFY') return metaA, metaB
def raster_overlap(file_A, file_B, outpath, NoData_A = None, NoData_B = None): """ Finds overlaping area between two raster images. this function examines two images and outputs a raster identifying pixels where both rasters have non-NoData values. Output raster has 1's where both images have data and 0's where one or both images are missing data. :param file_A: the first file :param file_B: the second file :param outpath: the output filename for the desired output. must end in ".tif" :param NoData_A: the NoData value of file A :param NoData_B: the NoData value of file B :return outpath: filepath to raster created by this function. This function automatically invokes * clip_and_snap * null_define """ if not is_rast(file_A) or not is_rast(file_B): raise Exception('both inputs must be rasters!') # load the rasters as numpy arays. a, metaA = to_numpy(file_A) b, metaB = to_numpy(file_B) # set no_datas if NoData_A is None: NoData_A = metaA.NoData_Value if NoData_B is None: NoData_B = metaB.NoData_Value # spatially match the rasters print('preparing input rasters!') clip_and_snap(file_A, file_B, outpath.replace(".shp",".tif"), NoData_B) # reload the rasters as numpy arrays now that spatial matching is done a, metaA = to_numpy(file_A) b, metaB = to_numpy(file_B) # create work matrix and find the overlap print('Finding overlaping pixels!') Workmatrix = a.mask + b.mask Workmatrix = Workmatrix.astype('uint8') Workmatrix[Workmatrix == 1] = 2 print('Saving overlap file!') metaA.numpy_datatype = 'uint8' from_numpy(Workmatrix, metaA, outpath.replace(".shp",".tif"), NoData_Value = 2) arcpy.RasterToPolygon_conversion(outpath.replace(".shp",".tif"), outpath.replace(".tif",".shp"), 'NO_SIMPLIFY') return outpath
def enf_rastlist(filelist): """ ensures a list of inputs filepaths contains only valid raster types """ # first place the input through the same requirements of any filelist filelist = core.enf_filelist(filelist) new_filelist = [] for filename in filelist: if os.path.isfile(filename): if is_rast(filename): new_filelist.append(filename) return new_filelist
def enf_rastlist(filelist): """ ensures a list of inputs filepaths contains only valid raster types """ # first place the input through the same requirements of any filelist filelist = core.enf_filelist(filelist) new_filelist = [] for filename in filelist: if os.path.isfile(filename): if is_rast(filename): new_filelist.append(filename) return new_filelist
def enf_rastlist(filelist): """ Ensures a list of inputs filepaths contains only valid raster types :param filelist: a list of filepaths that contains some raster filetypes :return new_filelist: a list of filepaths with all non-raster files removed """ # first place the input through the same requirements of any filelist filelist = core.enf_filelist(filelist) new_filelist = [] for filename in filelist: if os.path.isfile(filename): if is_rast(filename): new_filelist.append(filename) return new_filelist
def to_numpy(raster, numpy_datatype = None): """ Wrapper for arcpy.RasterToNumpyArray with better metadata handling This is just a wraper for the RasterToNumPyArray function within arcpy, but it also extracts out all the spatial referencing information that will probably be needed to save the raster after desired manipulations have been performed. also see raster.from_numpy function in this module. inputs: Raster Any raster supported by the arcpy.RasterToNumPyArray function numpy_datatype must be a string equal to any of the types listed at the following address [http://docs.scipy.org/doc/numpy/user/basics.types.html] for example: 'uint8' or 'int32' or 'float32' outputs: numpy_rast the numpy array version of the input raster Metadata An object with the following attributes. .Xmin the left edge .Ymin the bottom edge .Xmax the right edge .Ymax the top edge .Xsize the number of columns .Ysize the number of rows .cellWidth resolution in x direction .cellHeight resolution in y direction .projection the projection information to give the raster .NoData_Value the numerical value which represents NoData in this raster Usage example: call this function with " rast,Metadata = to_numpy(Raster) " perform numpy manipulations as you please then save the array with " raster.from_numpy(rast,Metadata,output) " """ # create a metadata object and assign attributes to it # read in the raster as an array if is_rast(raster): numpy_rast = arcpy.RasterToNumPyArray(raster) ys, xs = numpy_rast.shape meta = metadata(raster, xs, ys) if numpy_datatype is None: numpy_datatype = meta.numpy_datatype numpy_rast = numpy_rast.astype(numpy_datatype) # mask NoData values from the array if 'float' in numpy_datatype: numpy_rast[numpy_rast == meta.NoData_Value] = numpy.nan numpy_rast = numpy.ma.masked_array(numpy_rast, numpy.isnan(numpy_rast), dtype = numpy_datatype) elif 'int' in numpy_datatype: # (numpy.nan not supported by ints) mask = numpy.zeros(numpy_rast.shape) mask[numpy_rast != meta.NoData_Value] = False # do not mask mask[numpy_rast == meta.NoData_Value] = True # mask numpy_rast = numpy.ma.masked_array(numpy_rast, mask, dtype = numpy_datatype) else: raise Exception("Raster '{0}'does not exist".format(raster)) return numpy_rast, meta
def project_resample(filelist, reference_file, outdir=False, resampling_type=None, cell_size=None): """ Wrapper for multiple arcpy projecting functions. Projects to reference file Inputs a filelist and a reference file, then projects all rasters or feature classes in the filelist to match the projection of the reference file. Writes new files with a "_p" appended to the end of the input filenames. This also will perform resampling. Inputs: filelist list of files to be projected outdir optional desired output directory. If none is specified, output files will be named with '_p' as a suffix. reference_file Either a file with the desired projection, or a .prj file. resampling type exactly as the input for arcmaps project_Raster_management function cell_size exactly as the input for arcmaps project_Raster_management function Output: Spatial reference spatial referencing information for further checking. """ output_filelist = [] # sanitize inputs core.exists(reference_file) rasterlist = enf_rastlist(filelist) featurelist = core.enf_featlist(filelist) cleanlist = rasterlist + featurelist # ensure output directory exists if not os.path.exists(outdir): os.makedirs(outdir) # grab data about the spatial reference of the reference file. (prj or otherwise) if reference_file[-3:] == 'prj': Spatial_Reference = arcpy.SpatialReference(reference_file) else: Spatial_Reference = arcpy.Describe(reference_file).spatialReference # determine cell size if cell_size is None: cx = arcpy.GetRasterProperties_management(reference_file, "CELLSIZEX").getOutput(0) cy = arcpy.GetRasterProperties_management(reference_file, "CELLSIZEY").getOutput(0) cell_size = "{0} {1}".format(cx, cy) # determine wether coordinate system is projected or geographic and print info if Spatial_Reference.type == 'Projected': print('Found {0} projected coord system'.format( Spatial_Reference.PCSName)) else: print('Found {0} geographic coord system'.format( Spatial_Reference.GCSName)) for filename in cleanlist: # create the output filename outname = core.create_outname(outdir, filename, 'p') output_filelist.append(Spatial_Reference) # use ProjectRaster_management for rast files if is_rast(filename): arcpy.ProjectRaster_management(filename, outname, Spatial_Reference, resampling_type, cell_size) print('Wrote projected and resampled file to {0}'.format(outname)) # otherwise, use Project_management for featureclasses and featurelayers else: arcpy.Project_management(filename, outname, Spatial_Reference) print('Wrote projected file to {0}'.format(outname)) print("finished projecting!") return output_filelist
def to_numpy(raster, numpy_datatype = None): """ Wrapper for arcpy.RasterToNumpyArray with better metadata handling This is just a wraper for the RasterToNumPyArray function within arcpy, but it also extracts out all the spatial referencing information that will probably be needed to save the raster after desired manipulations have been performed. also see raster.from_numpy function in this module. inputs: Raster Any raster supported by the arcpy.RasterToNumPyArray function numpy_datatype must be a string equal to any of the types listed at the following address [http://docs.scipy.org/doc/numpy/user/basics.types.html] for example: 'uint8' or 'int32' or 'float32' outputs: numpy_rast the numpy array version of the input raster Metadata An object with the following attributes. .Xmin the left edge .Ymin the bottom edge .Xmax the right edge .Ymax the top edge .Xsize the number of columns .Ysize the number of rows .cellWidth resolution in x direction .cellHeight resolution in y direction .projection the projection information to give the raster .NoData_Value the numerical value which represents NoData in this raster Usage example: call this function with " rast,Metadata = to_numpy(Raster) " perform numpy manipulations as you please then save the array with " raster.from_numpy(rast,Metadata,output) " """ # create a metadata object and assign attributes to it # perform some checks to convert to supported data format if not is_rast(raster): try: print("Raster '{0}' may not be supported, converting to tif".format(raster)) tifraster = raster + ".tif" if not os.path.exists(raster + ".tif"): arcpy.CompositeBands_management(raster, tifraster) raster = tifraster except: raise Exception("Raster type could not be recognized") # read in the raster as a numpy array numpy_rast = arcpy.RasterToNumPyArray(raster) # build metadata for multi band raster if len(numpy_rast.shape) == 3: zs, ys, xs = numpy_rast.shape meta = [] for i in range(zs): bandpath = raster + "\\Band_{0}".format(i+1) meta.append(metadata(bandpath, xs, ys)) if numpy_datatype is None: numpy_datatype = meta[0].numpy_datatype # build metadata for single band raster else: ys, xs = numpy_rast.shape meta = metadata(raster, xs, ys) if numpy_datatype is None: numpy_datatype = meta.numpy_datatype numpy_rast = numpy_rast.astype(numpy_datatype) # mask NoData values from the array if 'float' in numpy_datatype: numpy_rast[numpy_rast == meta.NoData_Value] = numpy.nan numpy_rast = numpy.ma.masked_array(numpy_rast, numpy.isnan(numpy_rast), dtype = numpy_datatype) elif 'int' in numpy_datatype: # (numpy.nan not supported by ints) mask = numpy.zeros(numpy_rast.shape) mask[numpy_rast != meta.NoData_Value] = False # do not mask mask[numpy_rast == meta.NoData_Value] = True # mask numpy_rast = numpy.ma.masked_array(numpy_rast, mask, dtype = numpy_datatype) return numpy_rast, meta
def gap_fill_interpolate(in_rasterpath, out_rasterpath, model=None, max_cell_dist=None, min_points=None): """ Fills gaps in raster data by spatial kriging interpolation. This should only be used to fill small gaps in continuous datasets (like a DEM), and in instances where it makes sense. This function creates a feature class layer of points where pixels are not NoData, then performs a "kriging" interpolation on the point data to rebuild a uniform grid with a value at every location, thus filling gaps. WARNING: This script is processing intensive and may take a while to run even for modestly sized datasets. :param in_rasterpath: input filepath to raster to fill gaps :param out_rasterpath: filepath to store output gap filled raster in :param model: type of kriging model to run, options include "SPHERICAL", "CIRCULAR", "EXPONENTIAL", "GAUSSIAN", and "LINEAR" :param max_cell_dist: The maximum number of cells to interpolate between, data gaps which do not have at least "min_points" points within this distance will not be filled. :param min_points: Minimum number of surrounding points to use in determining value at missing cell. :return out_rasterpath: Returns path to file created by this function """ # check inputs if not is_rast(in_rasterpath): raise Exception( "input raster path {0} is invalid!".format(in_rasterpath)) if max_cell_dist is None: max_cell_dist = 10 if min_points is None: min_points = 4 if model is None: model = "SPHERICAL" # set environments arcpy.env.overwriteOutput = True arcpy.env.snapRaster = in_rasterpath arcpy.CheckOutExtension("Spatial") # make a point shapefile version of input raster print("Creating point grid from input raster") head, tail = os.path.split(in_rasterpath) shp_path = core.create_outname(head, tail, "shp", "shp") dbf_path = shp_path.replace(".shp", ".dbf") field = "GRID_CODE" arcpy.RasterToPoint_conversion(in_rasterpath, shp_path, "VALUE") # find the bad rows who GRID_CODE is 1, these should be NoData print("Finding points with NoData entries") bad_row_FIDs = [] rows = arcpy.UpdateCursor(dbf_path) for row in rows: grid_code = getattr(row, field) if grid_code == 1: bad_row_FIDs.append(row.FID) del rows # go back through the list and perform the deletions numbad = len(bad_row_FIDs) print("Deleting {0} points with NoData values".format(numbad)) rows = arcpy.UpdateCursor(dbf_path) for i, row in enumerate(rows): if row.FID in bad_row_FIDs: rows.deleteRow(row) # set up the parameters for kriging print("Setting up for kriging") _, meta = to_numpy(in_rasterpath) model = model cell_size = meta.cellHeight # from input raster lagSize = None majorRange = None partialSill = None nugget = None distance = float(cell_size) * float(max_cell_dist) # fn input min_points = min_points # fn input a = arcpy.sa.KrigingModelOrdinary() kmodel = arcpy.sa.KrigingModelOrdinary("SPHERICAL", lagSize=lagSize, majorRange=majorRange, partialSill=partialSill, nugget=nugget) kradius = arcpy.sa.RadiusFixed(distance=distance, minNumberOfPoints=min_points) # execute kriging print("Performing interpolation by kriging, this may take a while!") outkriging = arcpy.sa.Kriging(shp_path, field, kmodel, cell_size=cell_size, search_radius=kradius) outkriging.save(out_rasterpath) return out_rasterpath
def project_resample(filelist, reference_file, outdir = False, resampling_type = None, cell_size = None): """ Wrapper for multiple arcpy projecting functions. Projects to reference file Inputs a filelist and a reference file, then projects all rasters or feature classes in the filelist to match the projection of the reference file. Writes new files with a "_p" appended to the end of the input filenames. This also will perform resampling. Inputs: filelist list of files to be projected outdir optional desired output directory. If none is specified, output files will be named with '_p' as a suffix. reference_file Either a file with the desired projection, or a .prj file. resampling type exactly as the input for arcmaps project_Raster_management function cell_size exactly as the input for arcmaps project_Raster_management function Output: Spatial reference spatial referencing information for further checking. """ output_filelist = [] # sanitize inputs core.exists(reference_file) rasterlist = enf_rastlist(filelist) featurelist = core.enf_featlist(filelist) cleanlist = rasterlist + featurelist # ensure output directory exists if not os.path.exists(outdir): os.makedirs(outdir) # grab data about the spatial reference of the reference file. (prj or otherwise) if reference_file[-3:]=='prj': Spatial_Reference = arcpy.SpatialReference(reference_file) else: Spatial_Reference = arcpy.Describe(reference_file).spatialReference # determine cell size if cell_size is None: cx = arcpy.GetRasterProperties_management(reference_file, "CELLSIZEX").getOutput(0) cy = arcpy.GetRasterProperties_management(reference_file, "CELLSIZEY").getOutput(0) cell_size = "{0} {1}".format(cx,cy) # determine wether coordinate system is projected or geographic and print info if Spatial_Reference.type == 'Projected': print('Found {0} projected coord system'.format(Spatial_Reference.PCSName)) else: print('Found {0} geographic coord system'.format(Spatial_Reference.GCSName)) for filename in cleanlist: # create the output filename outname = core.create_outname(outdir, filename, 'p') output_filelist.append(Spatial_Reference) # use ProjectRaster_management for rast files if is_rast(filename): arcpy.ProjectRaster_management(filename, outname, Spatial_Reference, resampling_type, cell_size) print('Wrote projected and resampled file to {0}'.format(outname)) # otherwise, use Project_management for featureclasses and featurelayers else: arcpy.Project_management(filename,outname,Spatial_Reference) print('Wrote projected file to {0}'.format(outname)) print("finished projecting!") return output_filelist
def gap_fill_interpolate(in_rasterpath, out_rasterpath, model = None, max_cell_dist = None, min_points = None): """ Fills gaps in raster data by spatial kriging interpolation. This should only be used to fill small gaps in continuous datasets (like a DEM), and in instances where it makes sense. This function creates a feature class layer of points where pixels are not NoData, then performs a "kriging" interpolation on the point data to rebuild a uniform grid with a value at every location, thus filling gaps. WARNING: This script is processing intensive and may take a while to run even for modestly sized datasets. :param in_rasterpath: input filepath to raster to fill gaps :param out_rasterpath: filepath to store output gap filled raster in :param model: type of kriging model to run, options include "SPHERICAL", "CIRCULAR", "EXPONENTIAL", "GAUSSIAN", and "LINEAR" :param max_cell_dist: The maximum number of cells to interpolate between, data gaps which do not have at least "min_points" points within this distance will not be filled. :param min_points: Minimum number of surrounding points to use in determining value at missing cell. :return out_rasterpath: Returns path to file created by this function """ # check inputs if not is_rast(in_rasterpath): raise Exception("input raster path {0} is invalid!".format(in_rasterpath)) if max_cell_dist is None: max_cell_dist = 10 if min_points is None: min_points = 4 if model is None: model = "SPHERICAL" # set environments arcpy.env.overwriteOutput = True arcpy.env.snapRaster = in_rasterpath arcpy.CheckOutExtension("Spatial") # make a point shapefile version of input raster print("Creating point grid from input raster") head, tail = os.path.split(in_rasterpath) shp_path = core.create_outname(head, tail, "shp", "shp") dbf_path = shp_path.replace(".shp",".dbf") field = "GRID_CODE" arcpy.RasterToPoint_conversion(in_rasterpath, shp_path, "VALUE") # find the bad rows who GRID_CODE is 1, these should be NoData print("Finding points with NoData entries") bad_row_FIDs = [] rows = arcpy.UpdateCursor(dbf_path) for row in rows: grid_code = getattr(row, field) if grid_code == 1: bad_row_FIDs.append(row.FID) del rows # go back through the list and perform the deletions numbad = len(bad_row_FIDs) print("Deleting {0} points with NoData values".format(numbad)) rows = arcpy.UpdateCursor(dbf_path) for i, row in enumerate(rows): if row.FID in bad_row_FIDs: rows.deleteRow(row) # set up the parameters for kriging print("Setting up for kriging") _, meta = to_numpy(in_rasterpath) model = model cell_size = meta.cellHeight # from input raster lagSize = None majorRange = None partialSill = None nugget = None distance = float(cell_size) * float(max_cell_dist) # fn input min_points = min_points # fn input a = arcpy.sa.KrigingModelOrdinary() kmodel = arcpy.sa.KrigingModelOrdinary("SPHERICAL", lagSize = lagSize, majorRange = majorRange, partialSill = partialSill, nugget = nugget) kradius = arcpy.sa.RadiusFixed(distance = distance, minNumberOfPoints = min_points) # execute kriging print("Performing interpolation by kriging, this may take a while!") outkriging = arcpy.sa.Kriging(shp_path, field, kmodel, cell_size = cell_size, search_radius = kradius) outkriging.save(out_rasterpath) return out_rasterpath
def to_numpy(raster, numpy_datatype=None): """ Wrapper for arcpy.RasterToNumpyArray with better metadata handling This is just a wraper for the RasterToNumPyArray function within arcpy, but it also extracts out all the spatial referencing information that will probably be needed to save the raster after desired manipulations have been performed. also see raster.from_numpy function in this module. inputs: Raster Any raster supported by the arcpy.RasterToNumPyArray function numpy_datatype must be a string equal to any of the types listed at the following address [http://docs.scipy.org/doc/numpy/user/basics.types.html] for example: 'uint8' or 'int32' or 'float32' outputs: numpy_rast the numpy array version of the input raster Metadata An object with the following attributes. .Xmin the left edge .Ymin the bottom edge .Xmax the right edge .Ymax the top edge .Xsize the number of columns .Ysize the number of rows .cellWidth resolution in x direction .cellHeight resolution in y direction .projection the projection information to give the raster .NoData_Value the numerical value which represents NoData in this raster Usage example: call this function with " rast,Metadata = to_numpy(Raster) " perform numpy manipulations as you please then save the array with " raster.from_numpy(rast,Metadata,output) " """ # create a metadata object and assign attributes to it # perform some checks to convert to supported data format if not is_rast(raster): try: print( "Raster '{0}' may not be supported, converting to tif".format( raster)) tifraster = raster + ".tif" if not os.path.exists(raster + ".tif"): arcpy.CompositeBands_management(raster, tifraster) raster = tifraster except: raise Exception("Raster type could not be recognized") # read in the raster as a numpy array numpy_rast = arcpy.RasterToNumPyArray(raster) # build metadata for multi band raster if len(numpy_rast.shape) == 3: zs, ys, xs = numpy_rast.shape meta = [] for i in range(zs): bandpath = raster + "\\Band_{0}".format(i + 1) meta.append(metadata(bandpath, xs, ys)) if numpy_datatype is None: numpy_datatype = meta[0].numpy_datatype # build metadata for single band raster else: ys, xs = numpy_rast.shape meta = metadata(raster, xs, ys) if numpy_datatype is None: numpy_datatype = meta.numpy_datatype numpy_rast = numpy_rast.astype(numpy_datatype) # mask NoData values from the array if 'float' in numpy_datatype: numpy_rast[numpy_rast == meta.NoData_Value] = numpy.nan numpy_rast = numpy.ma.masked_array(numpy_rast, numpy.isnan(numpy_rast), dtype=numpy_datatype) elif 'int' in numpy_datatype: # (numpy.nan not supported by ints) mask = numpy.zeros(numpy_rast.shape) mask[numpy_rast != meta.NoData_Value] = False # do not mask mask[numpy_rast == meta.NoData_Value] = True # mask numpy_rast = numpy.ma.masked_array(numpy_rast, mask, dtype=numpy_datatype) return numpy_rast, meta
def to_numpy(raster, numpy_datatype = None): """ Wrapper for arcpy.RasterToNumpyArray with better metadata handling This is just a wraper for the RasterToNumPyArray function within arcpy, but it also extracts out all the spatial referencing information that will probably be needed to save the raster after desired manipulations have been performed. also see raster.from_numpy function in this module. :param raster: Any raster supported by the arcpy.RasterToNumPyArray function :param numpy_datatype: must be a string equal to any of the types listed at the following address [http://docs.scipy.org/doc/numpy/user/basics.types.html] for example: 'uint8' or 'int32' or 'float32' :return numpy_rast: the numpy array version of the input raster :return Metadata: a metadata object. see ``raster.metadata`` """ # perform some checks to convert to supported data format if not is_rast(raster): try: print("Raster '{0}' may not be supported, converting to tif".format(raster)) tifraster = raster + ".tif" if not os.path.exists(raster + ".tif"): arcpy.CompositeBands_management(raster, tifraster) raster = tifraster except: raise Exception("Raster type could not be recognized") # read in the raster as a numpy array numpy_rast = arcpy.RasterToNumPyArray(raster) # build metadata for multi band raster if len(numpy_rast.shape) == 3: zs, ys, xs = numpy_rast.shape meta = [] for i in range(zs): bandpath = raster + "\\Band_{0}".format(i+1) meta.append(metadata(bandpath, xs, ys)) if numpy_datatype is None: numpy_datatype = meta[0].numpy_datatype # build metadata for single band raster else: ys, xs = numpy_rast.shape meta = metadata(raster, xs, ys) if numpy_datatype is None: numpy_datatype = meta.numpy_datatype numpy_rast = numpy_rast.astype(numpy_datatype) # mask NoData values from the array if 'float' in numpy_datatype: numpy_rast[numpy_rast == meta.NoData_Value] = numpy.nan numpy_rast = numpy.ma.masked_array(numpy_rast, numpy.isnan(numpy_rast), dtype = numpy_datatype) elif 'int' in numpy_datatype: # (numpy.nan not supported by ints) mask = numpy.zeros(numpy_rast.shape) mask[numpy_rast != meta.NoData_Value] = False # do not mask mask[numpy_rast == meta.NoData_Value] = True # mask numpy_rast = numpy.ma.masked_array(numpy_rast, mask, dtype = numpy_datatype) return numpy_rast, meta
def to_numpy(raster, numpy_datatype=None): """ Wrapper for arcpy.RasterToNumpyArray with better metadata handling This is just a wraper for the RasterToNumPyArray function within arcpy, but it also extracts out all the spatial referencing information that will probably be needed to save the raster after desired manipulations have been performed. also see raster.from_numpy function in this module. :param raster: Any raster supported by the arcpy.RasterToNumPyArray function :param numpy_datatype: must be a string equal to any of the types listed at the following address [http://docs.scipy.org/doc/numpy/user/basics.types.html] for example: 'uint8' or 'int32' or 'float32' :return numpy_rast: the numpy array version of the input raster :return Metadata: a metadata object. see ``raster.metadata`` """ # perform some checks to convert to supported data format if not is_rast(raster): try: print( "Raster '{0}' may not be supported, converting to tif".format( raster)) tifraster = raster + ".tif" if not os.path.exists(raster + ".tif"): arcpy.CompositeBands_management(raster, tifraster) raster = tifraster except: raise Exception("Raster type could not be recognized") # read in the raster as a numpy array numpy_rast = arcpy.RasterToNumPyArray(raster) # build metadata for multi band raster if len(numpy_rast.shape) == 3: zs, ys, xs = numpy_rast.shape meta = [] for i in range(zs): bandpath = raster + "\\Band_{0}".format(i + 1) meta.append(metadata(bandpath, xs, ys)) if numpy_datatype is None: numpy_datatype = meta[0].numpy_datatype # build metadata for single band raster else: ys, xs = numpy_rast.shape meta = metadata(raster, xs, ys) if numpy_datatype is None: numpy_datatype = meta.numpy_datatype numpy_rast = numpy_rast.astype(numpy_datatype) # mask NoData values from the array if 'float' in numpy_datatype: numpy_rast[numpy_rast == meta.NoData_Value] = numpy.nan numpy_rast = numpy.ma.masked_array(numpy_rast, numpy.isnan(numpy_rast), dtype=numpy_datatype) elif 'int' in numpy_datatype: # (numpy.nan not supported by ints) mask = numpy.zeros(numpy_rast.shape) mask[numpy_rast != meta.NoData_Value] = False # do not mask mask[numpy_rast == meta.NoData_Value] = True # mask numpy_rast = numpy.ma.masked_array(numpy_rast, mask, dtype=numpy_datatype) return numpy_rast, meta