def __init__(self, gt, cs, img): # Set Image Metadata self.img = img self.gt = gt self.x_size = self.img.shape[1] self.y_size = self.img.shape[0] # Set up the coordinate systems and transformation objects to/from # wgs84 self.cs = cs self.m_per_pix = self.cs.GetLinearUnits() if not self.cs.IsGeographic(): self.m_per_pix = self.m_per_pix * self.gt[1] self.m_north_south = self.y_size * self.m_per_pix self.m_east_west = self.x_size * self.m_per_pix new_cs_wkt = osr.GetWellKnownGeogCSAsWKT('wgs84') self.tf_to_wgs84 = georeg.coord_transform_from_wkt( self.cs.ExportToWkt(), new_cs_wkt) self.tf_wgs_to_geo = georeg.coord_transform_from_wkt( new_cs_wkt, self.cs.ExportToWkt()) c_g = np.zeros((4, 2)) # Upper left, upper right, lower left, lower right # Image frame = +x right, +y down... Numpy = +x down, +y right c_g[0, :] = georeg.geo_from_pix(np.array([0, 0]), self.gt) c_g[1, :] = georeg.geo_from_pix(np.array([self.x_size, 0]), self.gt) c_g[2, :] = georeg.geo_from_pix(np.array([0, self.y_size]), self.gt) c_g[3, :] = georeg.geo_from_pix(np.array([self.x_size, self.y_size]), self.gt) self.corners_geo = c_g self.corners_wgs = np.array( self.tf_to_wgs84.TransformPoints(c_g))[:, 0:2]
def check_hdf_metadata(self): """ This function makes sure that the HDF5 file has a valid image, and geometric coordinate system data, and appropriate transformation data """ # Check to see if the image is stored try: self.img = self.hdf[self.img_path] except KeyError: print('Could not find Image at: %s', self.img_path) self.x_size = self.img.shape[1] self.y_size = self.img.shape[0] self.shape = self.img.shape # if len(self.img.shape) > 2: # raise ValueError('Pointing to Image path with > 2 Dimensions') # Now grab the GeoRegistration data, both the geo transform and the # CS Wkt stored as attributes in /ophoto self.gt = self.hdf['/ophoto'].attrs['upper_left_corner_geo_transform'] self.cs = osr.SpatialReference( str(self.hdf['/ophoto'].attrs['coordinate_system'])) if self.cs.GetAttrValue('AUTHORITY', 1) is not None: self.epsg = self.cs.GetAttrValue('AUTHORITY', 1) crs = rasterio.crs.CRS.from_epsg(self.epsg) self.cs = osr.SpatialReference(crs.wkt) if self.cs.IsProjected(): self.m_per_pix = self.cs.GetLinearUnits() else: self.m_per_pix = 1.0 if not self.cs.IsGeographic(): self.m_per_pix = self.m_per_pix * self.gt[1] # Set Corner Lat-Lon new_cs_wkt = osr.GetWellKnownGeogCSAsWKT('wgs84') self.tf_to_wgs84 = georeg.coord_transform_from_wkt( self.cs.ExportToWkt(), new_cs_wkt) self.tf_wgs_to_geo = georeg.coord_transform_from_wkt( new_cs_wkt, self.cs.ExportToWkt()) c_g = np.zeros((4, 2)) # Upper left, upper right, lower left, lower right # Image frame = +x right, +y down... Numpy = +x down, +y right c_g[0, :] = georeg.geo_from_pix(np.array([0, 0]), self.gt) c_g[1, :] = georeg.geo_from_pix(np.array([self.x_size, 0]), self.gt) c_g[2, :] = georeg.geo_from_pix(np.array([0, self.y_size]), self.gt) c_g[3, :] = georeg.geo_from_pix(np.array([self.x_size, self.y_size]), self.gt) self.corners_geo = c_g try: self.corners_wgs = np.array( self.tf_to_wgs84.TransformPoints(c_g))[:, 0:2] except: self.hdf.close() raise ValueError("HDF5 WKT for reference system was most \ likely inusfficent to perform transform")
def __init__(self, vrt_file, **kwargs): self.is_closed = False self.vrt = rasterio.open(vrt_file, 'r') self.x_size = self.vrt.width self.y_size = self.vrt.height self.shape = self.vrt.shape self.num_bands = self.vrt.meta['count'] base_cs = self.vrt.crs osr_ref = osr.SpatialReference() osr_ref.ImportFromProj4(rasterio.crs.CRS.to_string(base_cs)) base_wkt = osr_ref.ExportToWkt() # Now grab the GeoRegistration data, both the geo transform and the # CS Wkt stored as attributes in /ophoto self.gt = self.vrt.get_transform() self.cs = osr.SpatialReference(yaml.dump(base_wkt)) if self.cs.IsProjected(): self.m_per_pix = self.cs.GetLinearUnits() else: self.m_per_pix = None if not self.cs.IsGeographic(): self.m_per_pix = self.m_per_pix * self.gt[1] # Set Corner Lat-Lon new_cs_wkt = osr.GetWellKnownGeogCSAsWKT('wgs84') self.tf_to_wgs84 = georeg.coord_transform_from_wkt( self.cs.ExportToWkt(), new_cs_wkt) self.tf_wgs_to_geo = georeg.coord_transform_from_wkt( new_cs_wkt, self.cs.ExportToWkt()) c_g = np.zeros((4, 2)) # Upper left, upper right, lower left, lower right # Image frame = +x right, +y down... Numpy = +x down, +y right c_g[0, :] = georeg.geo_from_pix(np.array([0, 0]), self.gt) c_g[1, :] = georeg.geo_from_pix(np.array([self.x_size, 0]), self.gt) c_g[2, :] = georeg.geo_from_pix(np.array([0, self.y_size]), self.gt) c_g[3, :] = georeg.geo_from_pix(np.array([self.x_size, self.y_size]), self.gt) self.corners_geo = c_g try: self.corners_wgs = np.array( self.tf_to_wgs84.TransformPoints(c_g))[:, 0:2] except: self.hdf.close() raise ValueError("HDF5 WKT for reference system was most \ likely inusfficent to perform transform")
def write_geotiff(filename, nc_vname, data, geotransform, projection, metadata): # get the size of the rasters and number of rasters to write out if data.ndim == 2: Xsize = data.shape[1] Ysize = data.shape[0] nR = 1 elif data.ndim == 3: Xsize = data.shape[2] Ysize = data.shape[1] nR = data.shape[0] else: raise Exception( "Data does not have correct number of dimensions (2 or 3)") # write out the GeoTIFF driver = gdal.GetDriverByName("GTiff") dst_ds = driver.Create(filename, Xsize, Ysize, nR, gdal.GDT_Byte, ["COMPRESS=LZW", "INTERLEAVE=BAND"]) # copy most of the information from the netCDF file dst_ds.SetGeoTransform(geotransform) # set a projection - WGS 84 if a projection isn't given if projection == "": proj = osr.GetWellKnownGeogCSAsWKT("WGS84") dst_ds.SetProjection(proj) else: dst_ds.SetProjection(projection) # set the color table rb = dst_ds.GetRasterBand(1) rb.WriteArray(data) # set the nodata value rb.SetNoDataValue(255) # only 2D data can have a color table if data.ndim == 2: # create the color table for the variable ct = load_color_table(nc_vname) rb.SetColorTable(ct) # set the metadata dst_ds.SetMetadata(metadata) dst_ds = None
def main(): first_time = time.time() ### Read input arguments ##### # parser = OptionParser() usage = "usage: %prog [options]" parser = OptionParser(usage=usage) parser.add_option('-q', '--quiet', dest='verbose', default=True, action='store_false', help='do not print status messages to stdout') parser.add_option('-i', '--ini', dest='inifile', default='coastal_inun.ini', nargs=1, help='ini configuration file') parser.add_option('-b', '--boundary', nargs=1, dest='boundary', help='boundary conditions file (NetCDF point time series file') parser.add_option('-v', '--boundary_variable', nargs=1, dest='boundary_variable', default='waterlevel', help='variable name of boundary conditions') parser.add_option('-s', '--sea_level_rise', dest='sea_level_rise_map', default='', help='Sea level rise map (GeoTIFF)') parser.add_option('-g', '--subsidence', dest='subsidence_map', default='', help='Subsidence map (GeoTIFF)') parser.add_option('-d', '--destination', dest='destination', default='', help='Destination file') parser.add_option('-t', '--time', dest='time', default='2010-01-01 00:00:00', help='Time stamp of flood condition') parser.add_option('-x', '--test', dest='test', default=None, help='test specific tile number; report intermediate outputs') # for testing: tile_settings, tempdir, resistance and dist_method options as command line options. # if not set, these options are read from ini (default) parser.add_option('-y', '--tile_settings', dest='tiles', default=None, help='filename of JSON tile settings') parser.add_option('-m', '--dist_method', dest='dist_method', default=None, help="calculate distance along 'ldd' or use the 'eucledian' distance ") parser.add_option('-r', '--resistance', dest='resistance', default=None, help="decrease in water level as function of distance from coast [m/m]") parser.add_option('--zrw', dest='zrw', default=None, help="zero resistance water percentage thresho") parser.add_option('-z', '--tempdir', dest='tempdir', default=None, help="output directory for temporary data") parser.add_option('-w', '--nworkers', dest='nworkers', default=cpu_count()-1, help="number of parallel workers; if 1 it runs sequential") (options, args) = parser.parse_args() if not os.path.exists(options.inifile): print('path to ini file cannot be found: {:s}'.format(options.inifile)) sys.exit(1) # file names and directory bookkeeping options.destination = os.path.abspath(options.destination) options.dest_path = os.path.split(options.destination)[0] logfilename = options.destination[:-3] + '.log' # create dir if not exist if not os.path.isdir(options.dest_path): os.makedirs(options.dest_path) # delete old destination and log files else: if os.path.isfile(options.destination): os.unlink(options.destination) if os.path.isfile(logfilename): os.unlink(logfilename) # set up the logger logger, ch = cl.setlogger(logfilename, 'COASTAL_INUN', options.verbose) logger.info('$Id: coastal_inun.py 528 2018-06-19 08:41:05Z eilan_dk $') ### READ CONFIG FILE # open config-file config = cl.open_conf(options.inifile) # read settings options.dem_file = os.path.abspath(cl.configget(config, 'maps', 'dem_file', True)) options.ldd_file = cl.configget(config, 'maps', 'ldd_file', None) if options.ldd_file is not None: options.ldd_file = os.path.abspath(options.ldd_file) options.water_perc_file = cl.configget(config, 'maps', 'water_perc_file', None) if options.water_perc_file is not None: options.water_perc_file = os.path.abspath(options.water_perc_file) options.egm_file = os.path.abspath(cl.configget(config, 'maps', 'egm_file', '')) options.x_var = cl.configget(config, 'boundary', 'x_var', 'station_x_coordinate') options.y_var = cl.configget(config, 'boundary', 'y_var', 'station_y_coordinate') options.x_tile = cl.configget(config, 'tiling', 'x_tile', 600, datatype='int') options.y_tile = cl.configget(config, 'tiling', 'y_tile', 600, datatype='int') options.x_overlap = cl.configget(config, 'tiling', 'x_overlap', 60, datatype='int') options.y_overlap = cl.configget(config, 'tiling', 'y_overlap', 60, datatype='int') if options.tiles is None: options.tiles = cl.configget(config, 'tiling', 'tiles', None) if options.tiles is not None: options.tiles = os.path.abspath(options.tiles) if options.resistance is None: options.resistance = cl.configget(config, 'flood_routine', 'resistance', 0.00050, datatype='float') else: options.resistance = float(options.resistance) if options.zrw is None: options.zrw = cl.configget(config, 'flood_routine', 'waterp_thresh', 1.0, datatype='float') else: options.zrw = float(options.zrw) if options.dist_method is None: options.dist_method = cl.configget(config, 'flood_routine', 'dist_method', 'eucledian') if options.tempdir is None: options.tempdir = os.path.abspath(cl.configget(config, 'flood_routine', 'tempdir', os.path.join(options.dest_path, 'temp{:s}'.format(str(uuid.uuid4()))))) options.nodatavalue = cl.configget(config, 'flood_routine', 'nodatavalue', -9999, datatype='float') options.srs = osr.GetWellKnownGeogCSAsWKT(cl.configget(config, 'flood_routine', 'srs', 'EPSG:4326')) # required input if not options.destination: # if destination is not given parser.error('destination not given') if not options.boundary: # if boundary conditions argument is not given #options.boundary='global_etc_rp_database.nc' parser.error('boundary conditions not given') if not os.path.exists(options.dem_file): logger.error('path to dem file {:s} cannot be found'.format(options.dem_file)) sys.exit(1) if options.dist_method not in ['ldd', 'eucledian']: logger.error("unknown value for distance method use 'ldd' or 'eucledian'") sys.exit(1) # check paths and set default to None if not given options.ldd_file = cl.check_input_fn(options.ldd_file, logger) options.egm_file = cl.check_input_fn(options.egm_file, logger) try: options.sea_level_rise_map = float(options.sea_level_rise_map) #constant SLR except: options.sea_level_rise_map = cl.check_input_fn(options.sea_level_rise_map, logger) options.subsidence_map = cl.check_input_fn(options.subsidence_map, logger) options.water_perc_file = cl.check_input_fn(options.water_perc_file, logger) # make sure tempdir is new empty folder if not os.path.isdir(options.tempdir): os.makedirs(options.tempdir) elif os.listdir(options.tempdir) == "": options.tempdir = options.tempdir # do nothing else: n = 1 options.tempdir = options.tempdir + '_{:03d}'.format(n) while os.path.isdir(options.tempdir): n += 1 options.tempdir = options.tempdir[:-4] + '_{:03d}'.format(n) os.makedirs(options.tempdir) # write info to logger logger.info('Destination file: {:s}'.format(options.destination)) logger.info('Temporary directory: {:s}'.format(options.tempdir)) logger.info('Time of flood conditions: {:s}'.format(options.time)) logger.info('DEM file: {:s}'.format(options.dem_file)) logger.info('LDD file: {:s}'.format(options.ldd_file)) logger.info('EGM file: {:s}'.format(options.egm_file)) logger.info('Water mask file: {:s}'.format(options.water_perc_file)) logger.info('Sea level rise map: {}'.format(options.sea_level_rise_map)) logger.info('Subsidence map: {:s}'.format(options.subsidence_map)) logger.info('Using tiling from json file: {:s}'.format(str(options.tiles is not None))) if options.tiles is None: logger.info('Columns per tile: {:d}'.format(options.x_tile)) logger.info('Rows per tile: {:d}'.format(options.y_tile)) logger.info('Columns overlap: {:d}'.format(options.x_overlap)) logger.info('Rows overlap: {:d}'.format(options.y_overlap)) logger.info('Flood resistance: {:.6f}'.format(options.resistance)) logger.info('Distance method: {:s}'.format(options.dist_method)) if options.test is None: logger.info('Running test: False') else: logger.info('Running test: True') ######################################################################### # PREPARE TILES AND OUTPUT ######################################################################### # add metadata from the section [metadata] metadata_global = {} meta_keys = config.options('metadata') for key in meta_keys: metadata_global[key] = config.get('metadata', key) # add a number of metadata variables that are mandatory metadata_global['config_file'] = os.path.abspath(options.inifile) metadata_var = {} metadata_var['units'] = 'm' metadata_var['standard_name'] = 'water_surface_height_above_reference_datum' metadata_var['long_name'] = 'Coastal flooding' metadata_var['comment'] = 'water_surface_reference_datum_altitude is given in file {:s}'.format(options.dem_file) # copy inifile to tempdir for reproducibility inifilename = options.destination[:-3] + '.ini' copyfile(options.inifile, inifilename) # Read extent from a GDAL compatible file try: x, y = cl.get_gdal_axes(options.dem_file, logging=logger) except: msg = 'Input file {:s} not a gdal compatible file'.format(options.dem_file) cl.close_with_error(logger, ch, msg) sys.exit(1) # open the variable with boundary conditions as preparation to read array parts try: with nc.Dataset(options.boundary, 'r') as a: # read history from boundary conditions try: history = a.history except: history = 'not provided' metadata_global['history'] = """Created by: $Id: coastal_inun.py 528 2018-06-19 08:41:05Z eilan_dk $, boundary conditions from {:s},\nhistory: {:s}""".format( os.path.abspath(options.boundary), history) except: msg = 'Input file {:s} not a netcdf compatible file'.format(options.boundary) cl.close_with_error(logger, ch, msg) sys.exit(1) # first -setup a NetCDF file nc_funcs.prepare_nc(options.destination, x, np.flipud(y), [datetime.datetime.strptime(options.time, '%Y-%m-%d %H:%M:%S')], metadata_global, units='Days since 1960-01-01 00:00:00') nc_funcs.append_nc(options.destination, 'inun', chunksizes=(1, min(options.y_tile, len(y)), min(options.x_tile, len(x))), fill_value=options.nodatavalue, metadata=metadata_var) # read tile settings is json file given if options.tiles is not None: with open(options.tiles, 'r') as data_file: tile_list = json.load(data_file) logger.info('raster tile setting read from {:s}'.format(options.tiles)) # otherwise, start discretizing else: logger.info('discretizing raster...') tile_list = cl.discretize_raster_bounds(options.dem_file, options.x_tile, options.y_tile, options.x_overlap, options.y_overlap, options.boundary, options.x_var, options.y_var) # write output to tempdir tiles_fn = options.destination[:-3] + '_tiles.json' with open(tiles_fn, 'w') as outfile: json.dump(tile_list, outfile) # add options to tiles list tile_list_out = [] for t in tile_list: t['options'] = options t['fn'] = os.path.join(options.tempdir, 'flood_{:05d}.tif'.format(t['i'])) tile_list_out.append(t) tile_list = tile_list_out # discretizing finished n_tiles = len(tile_list) logger.info('raster discretized in {:d} tiles'.format(n_tiles)) # find tiles with SRTM data and boundary conditions flood_tiles = [i for i, tile in enumerate(tile_list) if tile['has_DEM_data'] and tile['has_bounds']] logger.info('run {:d} tiles with SRTM data and boundary conditions'.format(len(flood_tiles))) # test with random subset of tiles if options.test is not None: tile_list = [tile for tile in tile_list if tile['i'] in [int(options.test)]] n_tiles = len(tile_list) logger.info('test with subset of {:d} tiles'.format(n_tiles)) ######################################################################### # PROCESS TILES ######################################################################### # initialize multiprocessing parameters nworkers = np.min([int(options.nworkers), n_tiles]) # number of cores to work with logger.info('start processing tiles with {:d} parallel processes'.format(nworkers)) time0 = time.time() # process tiles multicore if nworkers > 1: p = Pool(nworkers) try: p.map(process_tile, tile_list) except: traceback.print_exc() p.close() else: [process_tile(t) for t in tile_list] #[process_tile(t) for t in tile_list] # ############################################## seconds = float(time.time()-time0) hours, seconds = seconds // 3600, seconds % 3600 minutes, seconds = seconds // 60, seconds % 60 logger.info('finished processing {:d} tiles in {:02d}:{:02d}:{:02d}'.format( n_tiles, int(hours), int(minutes), int(seconds))) ######################################################################### # WRITE DATA TO NETCDF ######################################################################### # open the prepared netCDF file for appending nc_obj = nc.Dataset(options.destination, 'a') nc_var = nc_obj.variables['inun'] logger.info('start appending data to netcdf file') time0 = time.time() # read data from tempdir and append for tile in tile_list: # read data _, _, flood_cut, fill_val = gdal_readmap(tile['fn'], 'GTiff') flood_cut = np.flipud(flood_cut) if tile['start_row'] == 0: nc_var[0, -tile['end_row']:, tile['start_col']:tile['end_col']] = flood_cut else: nc_var[0, -tile['end_row']:-tile['start_row'], tile['start_col']:tile['end_col']] = flood_cut # now close nc file nc_obj.sync() nc_obj.close() seconds = float(time.time()-time0) hours, seconds = seconds // 3600, seconds % 3600 minutes, seconds = seconds // 60, seconds % 60 logger.info('finished writing {:d} tiles in {:02d}:{:02d}:{:02d}'.format( n_tiles, int(hours), int(minutes), int(seconds))) # cleanup temp dir if options.test is None: cl.cleanDir(options.tempdir, logger) # log total processing time seconds = float(time.time()-first_time) hours, seconds = seconds // 3600, seconds % 3600 minutes, seconds = seconds // 60, seconds % 60 logger.info('total processing time {:02d}:{:02d}:{:02d}'.format( int(hours), int(minutes), int(seconds))) # close logger logger, ch = cl.closeLogger(logger, ch) del logger, ch sys.exit(0)
def _get_gdal_metadata(self, filename): # let's do GDAL here ? if it fails do Hachoir from osgeo import gdal, osr, gdalconst ds = gdal.Open(filename, gdal.GA_ReadOnly) # TODO: get bounding box geotransform = ds.GetGeoTransform() projref = ds.GetProjectionRef() if not projref: # default to WGS84 projref = osr.GetWellKnownGeogCSAsWKT('EPSG:4326') spref = osr.SpatialReference(projref) # SRS # extract bbox # see http://svn.osgeo.org/gdal/trunk/gdal/swig/python/samples/gdalinfo.py # GDALInfoReportCorner # bbox = left,bottom,right,top # bbox = min Longitude , min Latitude , max Longitude , max Latitude # bbox in srs units # transform points into georeferenced coordinates left, top = self._geotransform(0.0, 0.0, geotransform) right, bottom = self._geotransform(ds.RasterXSize, ds.RasterYSize, geotransform) # transform points to dataset projection coordinates if not spref.IsLocal(): # TODO: check whether it really is not possible to transform local coordinate systems spref_latlon = spref.CloneGeogCS() trans = osr.CoordinateTransformation(spref_latlon, spref) left, top, _ = trans.TransformPoint(left, top, 0) right, bottom, _ = trans.TransformPoint(right, bottom, 0) srs = '{0}:{1}'.format( spref.GetAuthorityName( None), # 'PROJCS', 'GEOGCS', 'GEOGCS|UNIT', None spref.GetAuthorityCode(None)) else: srs = None # build metadata struct data = { 'size': (ds.RasterXSize, ds.RasterYSize), 'bands': ds.RasterCount, 'projection': projref, # WKT 'srs': srs, 'origin': (geotransform[0], geotransform[3]), 'Pxiel Size': (geotransform[1], geotransform[5]), 'bounds': { 'left': left, 'bottom': bottom, 'right': right, 'top': top } } data.update(ds.GetMetadata_Dict()) data.update(ds.GetMetadata_Dict('EXIF')) from libxmp.core import XMPMeta xmp = ds.GetMetadata('xml:XMP') or [] if xmp: data['xmp'] = {} for xmpentry in xmp: xmpmd = XMPMeta() xmpmd.parse_from_str(xmpentry) for xmpitem in self._traverseXMP(xmpmd): (schema, name, value, options) = xmpitem if options['IS_SCHEMA']: continue if options['ARRAY_IS_ALT']: # pick first element and move on data['xmp'][name] = xmpmd.get_array_item(schema, name, 1) continue # current item # ARRAY_IS_ALT .. ARRAY_IS_ALT_TEXT, pick first one (value is array + array is ordered) # -> array elements don't have special markers :( if options['ARRAY_IS_ALT']: pass if options['HAS_LANG']: pass if options['VALUE_IS_STRUCT']: pass if options['ARRAY_IS_ALTTEXT']: pass if options['VALUE_IS_ARRAY']: pass if options['ARRAY_IS_ORDERED']: pass # -> ALT ARRAY_VALUE??? # if options['VALUE_IS_ARRAY']: # else: data['xmp'][name] = value # EXIF could provide at least: # width, height, bistpersample, compression, planarconfiguration, # sampleformat, xmp-metadata (already parsed) # TODO: get driver metadata? # ds.GetDriver().getMetadata() # ds.GetDriver().ds.GetMetadataItem(gdal.DMD_XXX) # Extract GDAL metadata for numband in range(1, ds.RasterCount + 1): band = ds.GetRasterBand(numband) (min_, max_, mean, stddev) = band.ComputeStatistics(False) banddata = { 'data type': gdal.GetDataTypeName(band.DataType), # band.GetRasterColorTable().GetCount() ... color table with # count entries 'min': min_, 'max': max_, 'mean': mean, 'stddev': stddev, 'color interpretation': gdal.GetColorInterpretationName(band.GetColorInterpretation()), 'description': band.GetDescription(), 'nodata': band.GetNoDataValue(), 'size': (band.XSize, band.YSize), 'index': band.GetBand(), #band.GetCategoryNames(), GetRasterCategoryNames() .. ? #band.GetScale() } banddata.update(band.GetMetadata()) if not 'band' in data: data['band'] = [] data['band'].append(banddata) # extract Raster Attribute table (if any) rat = band.GetDefaultRAT() def _getColValue(rat, row, col): valtype = rat.GetTypeOfCol(col) if valtype == gdalconst.GFT_Integer: return rat.GetValueAsInt(row, col) if valtype == gdalconst.GFT_Real: return rat.GetValueAsDouble(row, col) if valtype == gdalconst.GFT_String: return rat.GetValueAsString(row, col) return None GFU_MAP = { gdalconst.GFU_Generic: 'Generic', gdalconst.GFU_Max: 'Max', gdalconst.GFU_MaxCount: 'MaxCount', gdalconst.GFU_Min: 'Min', gdalconst.GFU_MinMax: 'MinMax', gdalconst.GFU_Name: 'Name', gdalconst.GFU_PixelCount: 'PixelCount', gdalconst.GFU_Red: 'Red', gdalconst.GFU_Green: 'Green', gdalconst.GFU_Blue: 'Blue', gdalconst.GFU_Alpha: 'Alpha', gdalconst.GFU_RedMin: 'RedMin', gdalconst.GFU_GreenMin: 'GreenMin', gdalconst.GFU_BlueMin: 'BlueMin', gdalconst.GFU_AlphaMax: 'AlphaMin', gdalconst.GFU_RedMax: 'RedMax', gdalconst.GFU_GreenMax: 'GreenMax', gdalconst.GFU_BlueMin: 'BlueMax', gdalconst.GFU_AlphaMax: 'AlphaMax', } GFT_MAP = { gdalconst.GFT_Integer: 'Integer', gdalconst.GFT_Real: 'Real', gdalconst.GFT_String: 'String', } if rat: banddata['rat'] = { 'rows': [[ _getColValue(rat, rowidx, colidx) for colidx in range(0, rat.GetColumnCount()) ] for rowidx in range(0, rat.GetRowCount())], 'cols': [{ 'name': rat.GetNameOfCol(idx), 'type': GFT_MAP[rat.GetTypeOfCol(idx)], 'usage': GFU_MAP[rat.GetUsageOfCol(idx)], 'idx': idx } for idx in range(0, rat.GetColumnCount())], } # Assume if there is a RAT we have categorical data banddata['type'] = 'categorical' else: banddata['type'] = 'continuous' ds = None # HACHOIR Tif extractor: # ret = {} # for field in parser: # if field.name.startswith('ifd'): # data = { # 'img_height': field['img_height']['value'].value, # 'img_width': field['img_width']['value'].value, # 'bits_per_sample': field['bits_per_sample']['value'].value, # 'compression': field['compression']['value'].display # } # ret = data return data