def _make_src_affine(src_data_array): src_bounds = _get_bounds(src_data_array) src_left, src_bottom, src_right, src_top = src_bounds src_resolution_x, src_resolution_y = _get_resolution(src_data_array, as_tuple=True) return Affine.translation(src_left, src_top) * Affine.scale( src_resolution_x, src_resolution_y)
def sources_for_tile(tile): """Render a tile's source footprints.""" bounds = Bounds(mercantile.xy_bounds(tile), WEB_MERCATOR_CRS) shape = Affine.scale(scale) * (256, 256) resolution = get_resolution_in_meters(bounds, shape) # convert sources to a list to avoid passing the generator across thread boundaries return (tile, list(catalog.get_sources(bounds, resolution)))
def areagrid(outraster, c = 0.083333001, r = 6371007.2, minx = -180, miny = -90, w = 360, h = 180): """ Generates a global grid in geograpic coordinates with the area of each gridcell as the value of the cell Parameters: outraster = path to output raster file c = cellsize in decimal degrees r = radius of earth in desired units (e.g. 6371007.2m for sq. meters) minx, miny = the south west coordinate of the raster in degrees w, h = the width and height of the raster in degrees Returns: None """ c = float(c) r = float(r) # make a vector of ones [1,1,1, ... 1] of length equal to the number of cells from west to east. X = np.ones(round(w/c)) # make a vector counting from 0 to the number of cells from south to north. e.g. [0,1,2,...,179] for 1 deg cells. Y = np.arange(round(h/c)) # multiply all the numbers in the Y vector by the cell size, # so it extends from 0 to <180 (if the cell size is different than 1 deg) # then add the southernmost coordinate (-90deg). This makes a vector of -90 to +90 degrees North degN = Y*c + miny # convert degrees vector to radians radN = degN*np.pi/180.0 # convert the cell size to radians radc = c * np.pi/180.0 # calculate the area of the cell # there's some implicit geometry that's been done here already' # but basically it averages the width of the top of a cell and the bottom of a cell # and mutiplies it by the height of the cell (which is constant no matter how far or south north you are) # then by the square of the radius # since the angles are in radians it works out area correctly # you end up with a vector of cell area from south to north A = (np.sin(radN+radc/2)-np.sin(radN-radc/2)) * radc * r**2 # the outer product of any vector and a vector of ones just duplicates the first vector into columns in a matrix # basically we just copy the latitude vector across from east to west M = np.outer(A,X) cols = round(w/c) rows = round(h/c) # save the matrix as a raster with rasterio.open(outraster,'w', 'GTiff', width=cols, height=rows, dtype=M.dtype, crs={'init': 'EPSG:4326'}, transform=Affine.translation(-cols*c/2, rows*c/2) * Affine.scale(c, -c), count=1) as dst: dst.write_band(1,M)
def _get_affine_transform(self, bounding_box): lng1, lng2 = bounding_box.west, bounding_box.east lat1, lat2 = bounding_box.south, bounding_box.north x_scale = self.google_static_maps.image_w / (lng2 - lng1) y_scale = -self.google_static_maps.image_h / (lat2 - lat1) affine_translate = Affine.translation(-lng1, -lat2) affine_scale = Affine.scale(x_scale, y_scale) # affine_mirror = Affine(1, 0, 0, 0, -1, image_h) affine_transform = affine_scale * affine_translate return affine_transform
def example_reproject(): import idfpy from matplotlib import pyplot as plt from rasterio import Affine from rasterio.crs import CRS from rasterio.warp import reproject, Resampling import numpy as np with idfpy.open('bxk1-d-ck.idf') as src: a = src.read(masked=True) nr, nc = src.header['nrow'], src.header['ncol'] dx, dy = src.header['dx'], src.header['dy'] src_transform = Affine.from_gdal(*src.geotransform) # define new grid transform (same extent, 10 times resolution) dst_transform = Affine.translation(src_transform.c, src_transform.f) dst_transform *= Affine.scale(dx / 10., -dy / 10.) # define coordinate system (here RD New) src_crs = CRS.from_epsg(28992) # initialize new data array b = np.empty((10*nr, 10*nc)) # reproject using Rasterio reproject( source=a, destination=b, src_transform=src_transform, dst_transform=dst_transform, src_crs=src_crs, dst_crs=src_crs, resampling=Resampling.bilinear, ) # result as masked array b = np.ma.masked_equal(b, a.fill_value) # plot images fig, axes = plt.subplots(nrows=2, ncols=1) axes[0].imshow(a.filled(np.nan)) axes[0].set_title('bxk1 original') axes[1].imshow(b.filled(np.nan)) axes[1].set_title('bxk1 resampled') plt.show()
def example_reproject(): import idfpy from matplotlib import pyplot as plt from rasterio import Affine from rasterio.crs import CRS from rasterio.warp import reproject, Resampling import numpy as np with idfpy.open('bxk1-d-ck.idf') as src: a = src.read(masked=True) nr, nc = src.header['nrow'], src.header['ncol'] dx, dy = src.header['dx'], src.header['dy'] src_transform = Affine.from_gdal(*src.geotransform) # define new grid transform (same extent, 10 times resolution) dst_transform = Affine.translation(src_transform.c, src_transform.f) dst_transform *= Affine.scale(dx / 10., -dy / 10.) # define coordinate system (here RD New) src_crs = CRS.from_epsg(28992) # initialize new data array b = np.empty((10 * nr, 10 * nc)) # reproject using Rasterio reproject( source=a, destination=b, src_transform=src_transform, dst_transform=dst_transform, src_crs=src_crs, dst_crs=src_crs, resampling=Resampling.bilinear, ) # result as masked array b = np.ma.masked_equal(b, a.fill_value) # plot images fig, axes = plt.subplots(nrows=2, ncols=1) axes[0].imshow(a.filled(np.nan)) axes[0].set_title('bxk1 original') axes[1].imshow(b.filled(np.nan)) axes[1].set_title('bxk1 resampled') plt.show()
def main(): for i in range(2): dat = nc.Dataset(innc[i]) print dat #sum monthly values for 2010 dat2010 = dat.variables[varname[i]][600:611,:,:].sum(0) cols = 720 rows = 360 d = 1/2.0 with rasterio.open(outras[i],'w', 'GTiff', width=cols, height=rows, dtype=dat2010.dtype, crs={'init': 'EPSG:4326'}, transform=A.translation(-cols*d/2, rows*d/2) * A.scale(d, -d), count=1) as dst: dst.write_band(1,dat2010)
def export_array(modelgrid, filename, a, nodata=-9999, fieldname='value', **kwargs): """ Write a numpy array to Arc Ascii grid or shapefile with the model reference. Parameters ---------- filename : str Path of output file. Export format is determined by file extention. '.asc' Arc Ascii grid '.tif' GeoTIFF (requries rasterio package) '.shp' Shapefile a : 2D numpy.ndarray Array to export nodata : scalar Value to assign to np.nan entries (default -9999) fieldname : str Attribute field name for array values (shapefile export only). (default 'values') kwargs: keyword arguments to np.savetxt (ascii) rasterio.open (GeoTIFF) or flopy.export.shapefile_utils.write_grid_shapefile2 Notes ----- Rotated grids will be either be unrotated prior to export, using scipy.ndimage.rotate (Arc Ascii format) or rotation will be included in their transform property (GeoTiff format). In either case the pixels will be displayed in the (unrotated) projected geographic coordinate system, so the pixels will no longer align exactly with the model grid (as displayed from a shapefile, for example). A key difference between Arc Ascii and GeoTiff (besides disk usage) is that the unrotated Arc Ascii will have a different grid size, whereas the GeoTiff will have the same number of rows and pixels as the original. """ if filename.lower().endswith(".asc"): if len(np.unique(modelgrid.delr)) != len(np.unique(modelgrid.delc)) != 1 \ or modelgrid.delr[0] != modelgrid.delc[0]: raise ValueError('Arc ascii arrays require a uniform grid.') xoffset, yoffset = modelgrid.xoffset, modelgrid.yoffset cellsize = modelgrid.delr[0] # * self.length_multiplier fmt = kwargs.get('fmt', '%.18e') a = a.copy() a[np.isnan(a)] = nodata if modelgrid.angrot != 0: try: from scipy.ndimage import rotate a = rotate(a, modelgrid.angrot, cval=nodata) height_rot, width_rot = a.shape xmin, ymin, xmax, ymax = modelgrid.extent dx = (xmax - xmin) / width_rot dy = (ymax - ymin) / height_rot cellsize = np.max((dx, dy)) xoffset, yoffset = xmin, ymin except ImportError: print('scipy package required to export rotated grid.') filename = '.'.join( filename.split('.')[:-1]) + '.asc' # enforce .asc ending nrow, ncol = a.shape a[np.isnan(a)] = nodata txt = 'ncols {:d}\n'.format(ncol) txt += 'nrows {:d}\n'.format(nrow) txt += 'xllcorner {:f}\n'.format(xoffset) txt += 'yllcorner {:f}\n'.format(yoffset) txt += 'cellsize {}\n'.format(cellsize) # ensure that nodata fmt consistent w values txt += 'NODATA_value {}\n'.format(fmt) % (nodata) with open(filename, 'w') as output: output.write(txt) with open(filename, 'ab') as output: np.savetxt(output, a, **kwargs) print('wrote {}'.format(filename)) elif filename.lower().endswith(".tif"): if len(np.unique(modelgrid.delr)) != len(np.unique(modelgrid.delc)) != 1 \ or modelgrid.delr[0] != modelgrid.delc[0]: raise ValueError('GeoTIFF export require a uniform grid.') try: import rasterio from rasterio import Affine except ImportError: print('GeoTIFF export requires the rasterio package.') return dxdy = modelgrid.delc[0] # * self.length_multiplier trans = Affine.translation(modelgrid.xoffset, modelgrid.yoffset) * \ Affine.rotation(modelgrid.angrot) * \ Affine.scale(dxdy, -dxdy) # third dimension is the number of bands a = a.copy() if len(a.shape) == 2: a = np.reshape(a, (1, a.shape[0], a.shape[1])) if a.dtype.name == 'int64': a = a.astype('int32') dtype = rasterio.int32 elif a.dtype.name == 'int32': dtype = rasterio.int32 elif a.dtype.name == 'float64': dtype = rasterio.float64 elif a.dtype.name == 'float32': dtype = rasterio.float32 else: msg = 'ERROR: invalid dtype "{}"'.format(a.dtype.name) raise TypeError(msg) meta = {'count': a.shape[0], 'width': a.shape[2], 'height': a.shape[1], 'nodata': nodata, 'dtype': dtype, 'driver': 'GTiff', 'crs': modelgrid.proj4, 'transform': trans } meta.update(kwargs) with rasterio.open(filename, 'w', **meta) as dst: dst.write(a) print('wrote {}'.format(filename)) elif filename.lower().endswith(".shp"): from ..export.shapefile_utils import write_grid_shapefile2 epsg = kwargs.get('epsg', None) prj = kwargs.get('prj', None) if epsg is None and prj is None: epsg = modelgrid.epsg write_grid_shapefile2(filename, modelgrid, array_dict={fieldname: a}, nan_val=nodata, epsg=epsg, prj=prj)
import rasterio from rasterio import Affine as A from rasterio.warp import reproject, RESAMPLING tempdir = '/tmp' tiffname = os.path.join(tempdir, 'example.tif') with rasterio.drivers(): # Consider a 512 x 512 raster centered on 0 degrees E and 0 degrees N # with each pixel covering 15". rows, cols = src_shape = (512, 512) dpp = 1.0/240 # decimal degrees per pixel # The following is equivalent to # A(dpp, 0, -cols*dpp/2, 0, -dpp, rows*dpp/2). src_transform = A.translation(-cols*dpp/2, rows*dpp/2) * A.scale(dpp, -dpp) src_crs = {'init': 'EPSG:4326'} source = numpy.ones(src_shape, numpy.uint8)*255 # Prepare to reproject this rasters to a 1024 x 1024 dataset in # Web Mercator (EPSG:3857) with origin at -8928592, 2999585. dst_shape = (1024, 1024) dst_transform = A.from_gdal(-237481.5, 425.0, 0.0, 237536.4, 0.0, -425.0) dst_transform = dst_transform.to_gdal() dst_crs = {'init': 'EPSG:3857'} destination = numpy.zeros(dst_shape, numpy.uint8) reproject( source, destination, src_transform=src_transform,
def _make_src_affine(src_data_array): src_bounds = _get_bounds(src_data_array) src_left, src_bottom, src_right, src_top = src_bounds src_resolution_x, src_resolution_y = _get_resolution(src_data_array, as_tuple=True) return Affine.translation(src_left, src_top) * Affine.scale(src_resolution_x, src_resolution_y)
def main(): # load and average netcdfs arr = None for f in NETCDFS: ds = nc.Dataset(f,'r') if arr is None: print ds.variables.keys() arr = np.asarray(ds.variables['lwe_thickness']) / len(NETCDFS) else: arr += np.asarray(ds.variables['lwe_thickness']) / len(NETCDFS) # multiply by scale factor ds = nc.Dataset(SCALER,'r') print ds.variables.keys() scaler = np.asarray(ds.variables['SCALE_FACTOR']) print scaler.shape arr = arr*scaler # extract error grids m_err = np.asarray(ds.variables['MEASUREMENT_ERROR']) l_err = np.asarray(ds.variables['LEAKAGE_ERROR']) t_err = np.sqrt(m_err*m_err + l_err*l_err) # compute slopes, coefficients print arr.shape slope_arr = np.zeros(arr.shape[1:]) r2_arr = np.zeros(arr.shape[1:]) p_arr = np.zeros(arr.shape[1:]) print slope_arr.shape time = np.arange(arr.shape[0]) print time.shape for i in range(arr.shape[1]): for j in range(arr.shape[2]): b1, b0, r2, p, sd = stats.linregress(arr[:,i,j], time) slope_arr[i,j]=b1 r2_arr[i,j]=r2 p_arr[i,j]=p # dump to csv np.savetxt(SLOPE,slope_arr,delimiter=',') np.savetxt(R2,r2_arr,delimiter=',') np.savetxt(P,p_arr,delimiter=',') np.savetxt(ERR,t_err,delimiter=',') # rescale to WGS84 and dump to tif bands rows = arr.shape[1] cols = arr.shape[2] d = 1 transform = A.translation(-cols*d/2,-rows*d/2) * A.scale(d,d) print transform slope_arr = np.roll(slope_arr.astype(rio.float64),180) r2_arr = np.roll(r2_arr.astype(rio.float64),180) p_arr = np.roll(p_arr.astype(rio.float64),180) t_err = np.roll(t_err.astype(rio.float64),180) with rio.open(OUT, 'w', 'GTiff', width=cols, height=rows, dtype=rio.float64, crs={'init': 'EPSG:4326'}, transform=transform, count=4) as out: out.write_band(1, slope_arr) out.write_band(2, r2_arr) out.write_band(3, p_arr) out.write_band(4, t_err)
def __make_rastertiles_Z__(src_dataset: rio.DatasetReader, world_size: float, tile_size: int, zoom: int) -> list(): # get bands src_bands = src_dataset.read() # structure for store tiles tiles = [] # get bounds src_bbox = src_dataset.bounds src_bbox = [src_bbox.left, src_bbox.top, src_bbox.right, src_bbox.bottom] # get pixel size pixel_size = __pixel_size__(world_size, tile_size, zoom) # get all quadrant quadrants = __make_quadrants__(src_bbox, zoom, world_size, 1) for xmin, ymin, xmax, ymax in quadrants: # get bbox of quadrant Xmin, Ymin, Xmax, Ymax = list( __tile_world_bbox__(xmin, ymin, zoom, world_size, tile_size)) # get pixel size pixel_size = __pixel_size__(world_size, tile_size, zoom) # make dst shape (3, tsize, tsize), 3 is fix because it's an image RGB dst_shape = (3, tile_size, tile_size) # make transform with orig (Xmin, Ymin) and scale (psize, -psize) dst_transform = A.translation(Xmin, Ymin) * A.scale( pixel_size, -pixel_size) dtype = src_dataset.dtypes[0] if dtype == rio.uint8: datatype = 1 elif dtype == rio.uint16: datatype = 2 elif dtype == rio.int16: datatype = 3 elif dtype == rio.uint32: datatype = 4 elif dtype == rio.int32: datatype = 5 elif dtype == rio.float32: datatype = 6 elif dtype == rio.float64: datatype = 7 else: assert False # init dst bands dst_bands = np.zeros(dst_shape, dtype=dtype) count = dst_bands.shape[0] nodata = 0 if src_dataset.nodata is None else src_dataset.nodata # make reprojection for each bands for i in range(count): try: reproject(source=src_bands[i], destination=dst_bands[i], src_transform=src_dataset.transform, src_crs=src_dataset.crs, src_nodata=nodata, dst_transform=dst_transform, dst_crs=src_dataset.crs) except IndexError: continue gdal_bands = [{ 'data': dst_bands[x], 'nodata_value': nodata } for x in range(count)] gdal_raster = GDALRaster({ 'srid': WEB_MERCATOR_SRID, 'width': tile_size, 'height': tile_size, 'datatype': datatype, 'nr_of_bands': count, 'origin': [Xmin, Ymin], 'scale': [pixel_size, -pixel_size], 'bands': gdal_bands }) tiles.append((zoom, xmin, ymin, gdal_raster)) del src_bands # return structure return tiles
def reproject_grids(src_array, dst_array, metadata_src, metadata_dst): """ Reproject precipitation fields to the domain of another precipitation field. Parameters ---------- src_array: array-like Three-dimensional array of shape (t, x, y) containing a time series of precipitation fields. These precipitation fields will be reprojected. dst_array: array-like Array containing a precipitation field or a time series of precipitation fields. The src_array will be reprojected to the domain of dst_array. metadata_src: dict Metadata dictionary containing the projection, x- and ypixelsize, x1 and y2 attributes of the src_array as described in the documentation of :py:mod:`pysteps.io.importers`. metadata_dst: dict Metadata dictionary containing the projection, x- and ypixelsize, x1 and y2 attributes of the dst_array. Returns ------- r_rprj: array-like Three-dimensional array of shape (t, x, y) containing the precipitation fields of src_array, but reprojected to the domain of dst_array. metadata: dict Metadata dictionary containing the projection, x- and ypixelsize, x1 and y2 attributes of the reprojected src_array. """ if not RASTERIO_IMPORTED: raise MissingOptionalDependency( "rasterio package is required for the reprojection module, but it is " "not installed" ) # Extract the grid info from src_array src_crs = metadata_src["projection"] x1_src = metadata_src["x1"] y2_src = metadata_src["y2"] xpixelsize_src = metadata_src["xpixelsize"] ypixelsize_src = metadata_src["ypixelsize"] src_transform = A.translation(float(x1_src), float(y2_src)) * A.scale( float(xpixelsize_src), float(-ypixelsize_src) ) # Extract the grid info from dst_array dst_crs = metadata_dst["projection"] x1_dst = metadata_dst["x1"] y2_dst = metadata_dst["y2"] xpixelsize_dst = metadata_dst["xpixelsize"] ypixelsize_dst = metadata_dst["ypixelsize"] dst_transform = A.translation(float(x1_dst), float(y2_dst)) * A.scale( float(xpixelsize_dst), float(-ypixelsize_dst) ) # Initialise the reprojected array r_rprj = np.zeros((src_array.shape[0], dst_array.shape[-2], dst_array.shape[-1])) # For every timestep, reproject the precipitation field of src_array to # the domain of dst_array if metadata_src["yorigin"] != metadata_dst["yorigin"]: src_array = src_array[:, ::-1, :] for i in range(src_array.shape[0]): reproject( src_array[i, :, :], r_rprj[i, :, :], src_transform=src_transform, src_crs=src_crs, dst_transform=dst_transform, dst_crs=dst_crs, resampling=Resampling.nearest, dst_nodata=np.nan, ) # Update the metadata metadata = metadata_src.copy() for key in [ "projection", "yorigin", "xpixelsize", "ypixelsize", "x1", "x2", "y1", "y2", "cartesian_unit", ]: metadata[key] = metadata_dst[key] return r_rprj, metadata
def tile(sceneid, tile_x, tile_y, tile_z, rgb=(4, 3, 2), r_bds=(0, 16000), g_bds=(0, 16000), b_bds=(0, 16000), tilesize=256, pan=False): """Create mercator tile from Landsat-8 data and encodes it in base64. Attributes ---------- sceneid : str Landsat sceneid. For scenes after May 2017, sceneid have to be LANDSAT_PRODUCT_ID. tile_x : int Mercator tile X index. tile_y : int Mercator tile Y index. tile_z : int Mercator tile ZOOM level. rgb : tuple, int, optional (default: (4, 3, 2)) Bands index for the RGB combination. r_bds : tuple, int, optional (default: (0, 16000)) First band (red) DN min and max values (DN * 10,000) used for the linear rescaling. g_bds : tuple, int, optional (default: (0, 16000)) Second band (green) DN min and max values (DN * 10,000) used for the linear rescaling. b_bds : tuple, int, optional (default: (0, 16000)) Third band (blue) DN min and max values (DN * 10,000) used for the linear rescaling. tilesize : int, optional (default: 256) Output image size. pan : boolean, optional (default: False) If True, apply pan-sharpening. Returns ------- out : numpy ndarray (type: uint8) """ scene_params = utils.landsat_parse_scene_id(sceneid) meta_data = utils.landsat_get_mtl(sceneid).get('L1_METADATA_FILE') landsat_address = '{}/{}'.format(LANDSAT_BUCKET, scene_params['key']) wgs_bounds = toa_utils._get_bounds_from_metadata( meta_data['PRODUCT_METADATA']) if not utils.tile_exists(wgs_bounds, tile_z, tile_x, tile_y): raise TileOutsideBounds('Tile {}/{}/{} is outside image bounds'.format( tile_z, tile_x, tile_y)) mercator_tile = mercantile.Tile(x=tile_x, y=tile_y, z=tile_z) tile_bounds = mercantile.xy_bounds(mercator_tile) # define a list of bands Min and Max Values (from input) histo_cuts = dict(zip(rgb, [r_bds, g_bds, b_bds])) ms_tile_size = int(tilesize / 2) if pan else tilesize addresses = ['{}_B{}.TIF'.format(landsat_address, band) for band in rgb] _tiler = partial(utils.tile_band_worker, bounds=tile_bounds, tilesize=ms_tile_size) with futures.ThreadPoolExecutor(max_workers=3) as executor: out = np.stack(list(executor.map(_tiler, addresses))) if pan: pan_address = '{}_B8.TIF'.format(landsat_address) matrix_pan = utils.tile_band_worker(pan_address, tile_bounds, tilesize) w, s, e, n = tile_bounds pan_transform = transform.from_bounds(w, s, e, n, tilesize, tilesize) vis_transform = pan_transform * Affine.scale(2.) out = pansharpen(out, vis_transform, matrix_pan, pan_transform, np.int16, 'EPSG:3857', 'EPSG:3857', 0.2, method='Brovey', src_nodata=0) sun_elev = meta_data['IMAGE_ATTRIBUTES']['SUN_ELEVATION'] for bdx, band in enumerate(rgb): multi_reflect = meta_data['RADIOMETRIC_RESCALING'].get( 'REFLECTANCE_MULT_BAND_{}'.format(band)) add_reflect = meta_data['RADIOMETRIC_RESCALING'].get( 'REFLECTANCE_ADD_BAND_{}'.format(band)) out[bdx] = 10000 * reflectance.reflectance( out[bdx], multi_reflect, add_reflect, sun_elev, src_nodata=0) out[bdx] = np.where( out[bdx] > 0, utils.linear_rescale(out[bdx], in_range=histo_cuts.get(band), out_range=[1, 255]), 0) return out.astype(np.uint8)
def tile(sceneid, tile_x, tile_y, tile_z, rgb=(4, 3, 2), tilesize=256, pan=False): """Create mercator tile from Landsat-8 data. Attributes ---------- sceneid : str Landsat sceneid. For scenes after May 2017, sceneid have to be LANDSAT_PRODUCT_ID. tile_x : int Mercator tile X index. tile_y : int Mercator tile Y index. tile_z : int Mercator tile ZOOM level. rgb : tuple, int, optional (default: (4, 3, 2)) Bands index for the RGB combination. tilesize : int, optional (default: 256) Output image size. pan : boolean, optional (default: False) If True, apply pan-sharpening. Returns ------- data : numpy ndarray mask: numpy array """ if not isinstance(rgb, tuple): rgb = tuple((rgb, )) scene_params = utils.landsat_parse_scene_id(sceneid) meta_data = utils.landsat_get_mtl(sceneid).get('L1_METADATA_FILE') landsat_address = '{}/{}'.format(LANDSAT_BUCKET, scene_params['key']) wgs_bounds = toa_utils._get_bounds_from_metadata( meta_data['PRODUCT_METADATA']) if not utils.tile_exists(wgs_bounds, tile_z, tile_x, tile_y): raise TileOutsideBounds( 'Tile {}/{}/{} is outside image bounds'.format( tile_z, tile_x, tile_y)) mercator_tile = mercantile.Tile(x=tile_x, y=tile_y, z=tile_z) tile_bounds = mercantile.xy_bounds(mercator_tile) ms_tile_size = int(tilesize / 2) if pan else tilesize addresses = ['{}_B{}.TIF'.format(landsat_address, band) for band in rgb] _tiler = partial(utils.tile_band_worker, bounds=tile_bounds, tilesize=ms_tile_size, nodata=0) with futures.ThreadPoolExecutor(max_workers=3) as executor: data, masks = zip(*list(executor.map(_tiler, addresses))) data = np.concatenate(data) mask = np.all(masks, axis=0).astype(np.uint8) * 255 if pan: pan_address = '{}_B8.TIF'.format(landsat_address) matrix_pan, mask = utils.tile_band_worker(pan_address, tile_bounds, tilesize, nodata=0) w, s, e, n = tile_bounds pan_transform = transform.from_bounds(w, s, e, n, tilesize, tilesize) vis_transform = pan_transform * Affine.scale(2.) data = pansharpen(data, vis_transform, matrix_pan, pan_transform, np.int16, 'EPSG:3857', 'EPSG:3857', 0.2, method='Brovey', src_nodata=0) sun_elev = meta_data['IMAGE_ATTRIBUTES']['SUN_ELEVATION'] for bdx, band in enumerate(rgb): if int(band) > 9: # TIRS multi_rad = meta_data['RADIOMETRIC_RESCALING'].get( 'RADIANCE_MULT_BAND_{}'.format(band)) add_rad = meta_data['RADIOMETRIC_RESCALING'].get( 'RADIANCE_ADD_BAND_{}'.format(band)) k1 = meta_data['TIRS_THERMAL_CONSTANTS'].get( 'K1_CONSTANT_BAND_{}'.format(band)) k2 = meta_data['TIRS_THERMAL_CONSTANTS'].get( 'K2_CONSTANT_BAND_{}'.format(band)) data[bdx] = brightness_temp.brightness_temp( data[bdx], multi_rad, add_rad, k1, k2) else: multi_reflect = meta_data['RADIOMETRIC_RESCALING'].get( 'REFLECTANCE_MULT_BAND_{}'.format(band)) add_reflect = meta_data['RADIOMETRIC_RESCALING'].get( 'REFLECTANCE_ADD_BAND_{}'.format(band)) data[bdx] = 10000 * reflectance.reflectance( data[bdx], multi_reflect, add_reflect, sun_elev) return data, mask
import rasterio.crs # order depends on convention transform = A(geotransform) with rasterio.Env(): # As source: a 512 x 512 raster centered on 0 degrees E and 0 # degrees N, each pixel covering 15". rows, cols = src_shape = (512, 512) d = 1.0/240 # decimal degrees per pixel # The following is equivalent to # A(d, 0, -cols*d/2, 0, -d, rows*d/2). src_transform = A.translation(-cols*d/2, rows*d/2) * A.scale(d, -d) src_crs = {'init': 'EPSG:4326'} source = np.ones(src_shape, np.uint8)*255 # Destination: a 1024 x 1024 dataset in Web Mercator (EPSG:3857) # with origin at 0.0, 0.0. dst_shape = (1024, 1024) dst_transform = [-237481.5, 425.0, 0.0, 237536.4, 0.0, -425.0] dst_crs = {'init': 'EPSG:3857'} destination = np.zeros(dst_shape, np.uint8) reproject( source, destination, src_transform=src_transform, src_crs=src_crs,
def main(): # load and average netcdfs arr = None for f in NETCDFS: ds = nc.Dataset(f, 'r') if arr is None: print ds.variables.keys() arr = np.asarray(ds.variables['lwe_thickness']) / len(NETCDFS) else: arr += np.asarray(ds.variables['lwe_thickness']) / len(NETCDFS) # multiply by scale factor ds = nc.Dataset(SCALER, 'r') print ds.variables.keys() scaler = np.asarray(ds.variables['SCALE_FACTOR']) print scaler.shape arr = arr * scaler # extract error grids m_err = np.asarray(ds.variables['MEASUREMENT_ERROR']) l_err = np.asarray(ds.variables['LEAKAGE_ERROR']) t_err = np.sqrt(m_err * m_err + l_err * l_err) # compute slopes, coefficients print arr.shape slope_arr = np.zeros(arr.shape[1:]) r2_arr = np.zeros(arr.shape[1:]) p_arr = np.zeros(arr.shape[1:]) print slope_arr.shape time = np.arange(arr.shape[0]) print time.shape for i in range(arr.shape[1]): for j in range(arr.shape[2]): b1, b0, r2, p, sd = stats.linregress(arr[:, i, j], time) slope_arr[i, j] = b1 r2_arr[i, j] = r2 p_arr[i, j] = p # dump to csv np.savetxt(SLOPE, slope_arr, delimiter=',') np.savetxt(R2, r2_arr, delimiter=',') np.savetxt(P, p_arr, delimiter=',') np.savetxt(ERR, t_err, delimiter=',') # rescale to WGS84 and dump to tif bands rows = arr.shape[1] cols = arr.shape[2] d = 1 transform = A.translation(-cols * d / 2, -rows * d / 2) * A.scale(d, d) print transform slope_arr = np.roll(slope_arr.astype(rio.float64), 180) r2_arr = np.roll(r2_arr.astype(rio.float64), 180) p_arr = np.roll(p_arr.astype(rio.float64), 180) t_err = np.roll(t_err.astype(rio.float64), 180) with rio.open(OUT, 'w', 'GTiff', width=cols, height=rows, dtype=rio.float64, crs={'init': 'EPSG:4326'}, transform=transform, count=4) as out: out.write_band(1, slope_arr) out.write_band(2, r2_arr) out.write_band(3, p_arr) out.write_band(4, t_err)
def export_array(modelgrid, filename, a, nodata=-9999, fieldname='value', **kwargs): """Write a numpy array to Arc Ascii grid or shapefile with the model reference. Parameters ---------- filename : str Path of output file. Export format is determined by file extention. '.asc' Arc Ascii grid '.tif' GeoTIFF (requries rasterio package) '.shp' Shapefile a : 2D numpy.ndarray Array to export nodata : scalar Value to assign to np.nan entries (default -9999) fieldname : str Attribute field name for array values (shapefile export only). (default 'values') kwargs: keyword arguments to np.savetxt (ascii) rasterio.open (GeoTIFF) or flopy.export.shapefile_utils.write_grid_shapefile2 Notes ----- Rotated grids will be either be unrotated prior to export, using scipy.ndimage.rotate (Arc Ascii format) or rotation will be included in their transform property (GeoTiff format). In either case the pixels will be displayed in the (unrotated) projected geographic coordinate system, so the pixels will no longer align exactly with the model grid (as displayed from a shapefile, for example). A key difference between Arc Ascii and GeoTiff (besides disk usage) is that the unrotated Arc Ascii will have a different grid size, whereas the GeoTiff will have the same number of rows and pixels as the original. """ if filename.lower().endswith(".asc"): if len(np.unique(modelgrid.delr)) != len(np.unique(modelgrid.delc)) != 1 \ or modelgrid.delr[0] != modelgrid.delc[0]: raise ValueError('Arc ascii arrays require a uniform grid.') xoffset, yoffset = modelgrid.xoffset, modelgrid.yoffset cellsize = modelgrid.delr[0] # * self.length_multiplier fmt = kwargs.get('fmt', '%.18e') a = a.copy() a[np.isnan(a)] = nodata if modelgrid.angrot != 0: try: from scipy.ndimage import rotate a = rotate(a, modelgrid.angrot, cval=nodata) height_rot, width_rot = a.shape xmin, ymin, xmax, ymax = modelgrid.extent dx = (xmax - xmin) / width_rot dy = (ymax - ymin) / height_rot cellsize = np.max((dx, dy)) # cellsize = np.cos(np.radians(self.rotation)) * cellsize xoffset, yoffset = xmin, ymin except ImportError: print('scipy package required to export rotated grid.') pass filename = '.'.join( filename.split('.')[:-1]) + '.asc' # enforce .asc ending nrow, ncol = a.shape a[np.isnan(a)] = nodata txt = 'ncols {:d}\n'.format(ncol) txt += 'nrows {:d}\n'.format(nrow) txt += 'xllcorner {:f}\n'.format(xoffset) txt += 'yllcorner {:f}\n'.format(yoffset) txt += 'cellsize {}\n'.format(cellsize) # ensure that nodata fmt consistent w values txt += 'NODATA_value {}\n'.format(fmt) % (nodata) with open(filename, 'w') as output: output.write(txt) with open(filename, 'ab') as output: np.savetxt(output, a, **kwargs) print('wrote {}'.format(filename)) elif filename.lower().endswith(".tif"): if len(np.unique(modelgrid.delr)) != len(np.unique(modelgrid.delc)) != 1 \ or modelgrid.delr[0] != modelgrid.delc[0]: raise ValueError('GeoTIFF export require a uniform grid.') try: import rasterio from rasterio import Affine except: print('GeoTIFF export requires the rasterio package.') return dxdy = modelgrid.delc[0] # * self.length_multiplier trans = Affine.translation(modelgrid.xoffset, modelgrid.yoffset) * \ Affine.rotation(modelgrid.angrot) * \ Affine.scale(dxdy, -dxdy) # third dimension is the number of bands a = a.copy() if len(a.shape) == 2: a = np.reshape(a, (1, a.shape[0], a.shape[1])) if a.dtype.name == 'int64': a = a.astype('int32') dtype = rasterio.int32 elif a.dtype.name == 'int32': dtype = rasterio.int32 elif a.dtype.name == 'float64': dtype = rasterio.float64 elif a.dtype.name == 'float32': dtype = rasterio.float32 else: msg = 'ERROR: invalid dtype "{}"'.format(a.dtype.name) raise TypeError(msg) meta = {'count': a.shape[0], 'width': a.shape[2], 'height': a.shape[1], 'nodata': nodata, 'dtype': dtype, 'driver': 'GTiff', 'crs': modelgrid.proj4, 'transform': trans } meta.update(kwargs) with rasterio.open(filename, 'w', **meta) as dst: dst.write(a) print('wrote {}'.format(filename)) elif filename.lower().endswith(".shp"): from ..export.shapefile_utils import write_grid_shapefile2 epsg = kwargs.get('epsg', None) prj = kwargs.get('prj', None) if epsg is None and prj is None: epsg = modelgrid.epsg write_grid_shapefile2(filename, modelgrid, array_dict={fieldname: a}, nan_val=nodata, epsg=epsg, prj=prj)
import rasterio from rasterio import Affine as A from rasterio.warp import reproject, RESAMPLING tempdir = '/tmp' tiffname = os.path.join(tempdir, 'example.tif') with rasterio.drivers(): # Consider a 512 x 512 raster centered on 0 degrees E and 0 degrees N # with each pixel covering 15". rows, cols = src_shape = (512, 512) dpp = 1.0 / 240 # decimal degrees per pixel # The following is equivalent to # A(dpp, 0, -cols*dpp/2, 0, -dpp, rows*dpp/2). src_transform = A.translation(-cols * dpp / 2, rows * dpp / 2) * A.scale( dpp, -dpp) src_crs = {'init': 'EPSG:4326'} source = numpy.ones(src_shape, numpy.uint8) * 255 # Prepare to reproject this rasters to a 1024 x 1024 dataset in # Web Mercator (EPSG:3857) with origin at -8928592, 2999585. dst_shape = (1024, 1024) dst_transform = A.from_gdal(-237481.5, 425.0, 0.0, 237536.4, 0.0, -425.0) dst_transform = dst_transform.to_gdal() dst_crs = {'init': 'EPSG:3857'} destination = numpy.zeros(dst_shape, numpy.uint8) reproject(source, destination, src_transform=src_transform, src_crs=src_crs,
def __make_imagetiles_Z__(src_dataset: rio.DatasetReader, world_size: float, tile_size: int, zoom: int) -> list(): # structure for store tiles tiles = [] # get bounding box src_bbox = src_dataset.bounds src_bbox = [src_bbox.left, src_bbox.top, src_bbox.right, src_bbox.bottom] # get pixel size pixel_size = __pixel_size__(world_size, tile_size, zoom) # get all quadrant quadrants = __make_quadrants__(src_bbox, zoom, world_size, 1) for xmin, ymin, xmax, ymax in quadrants: # get bbox of quadrant Xmin, Ymin, Xmax, Ymax = list( __tile_world_bbox__(xmin, ymin, zoom, world_size, tile_size)) # get pixel size pixel_size = __pixel_size__(world_size, tile_size, zoom) # make dst shape (3, tsize, tsize), 3 is fix because it's an image RGB dst_shape = (3, tile_size, tile_size) # make transform with orig (Xmin, Ymin) and scale (psize, -psize) dst_transform = A.translation(Xmin, Ymin) * A.scale( pixel_size, -pixel_size) # init dst bands dst_bands = np.zeros(dst_shape, dtype=np.uint8) # make reprojection for each bands for i in range(3): reproject(source=src_dataset.read(i + 1), destination=dst_bands[i], src_transform=src_dataset.transform, src_crs=src_dataset.crs, dst_transform=dst_transform, dst_crs=src_dataset.crs) # switch channel fst to channel last dst_bands = np.rollaxis(dst_bands, 0, 3) # make alpha band for no data dst_sum = np.sum(dst_bands, axis=2) alpha = np.zeros((tile_size, tile_size, 3)) alpha[dst_sum > 0] = np.array([255, 255, 255]) # convert alpha as pilimage pil_alpha = Image.fromarray(alpha.astype(dtype=np.uint8)).convert('L') # convert dst_bands as pilimage & put alpha pil_tile = Image.fromarray(dst_bands) pil_tile.putalpha(pil_alpha) # write in a buffer as bytes buffer = BytesIO() pil_tile.save(fp=buffer, format="PNG") # push all in ret structure tiles.append((zoom, xmin, ymin, buffer)) # return structure return tiles
def tile(sceneid, tile_x, tile_y, tile_z, bands=("4", "3", "2"), tilesize=256, pan=False): """ Create mercator tile from Landsat-8 data. Attributes ---------- sceneid : str Landsat sceneid. For scenes after May 2017, sceneid have to be LANDSAT_PRODUCT_ID. tile_x : int Mercator tile X index. tile_y : int Mercator tile Y index. tile_z : int Mercator tile ZOOM level. bands : tuple, str, optional (default: ("4", "3", "2")) Bands index for the RGB combination. tilesize : int, optional (default: 256) Output image size. pan : boolean, optional (default: False) If True, apply pan-sharpening. Returns ------- data : numpy ndarray mask: numpy array """ if not isinstance(bands, tuple): bands = tuple((bands, )) for band in bands: if band not in LANDSAT_BANDS: raise InvalidBandName( "{} is not a valid Landsat band name".format(band)) scene_params = _landsat_parse_scene_id(sceneid) meta_data = _landsat_get_mtl(sceneid).get("L1_METADATA_FILE") landsat_address = "{}/{}".format(LANDSAT_BUCKET, scene_params["key"]) wgs_bounds = toa_utils._get_bounds_from_metadata( meta_data["PRODUCT_METADATA"]) if not utils.tile_exists(wgs_bounds, tile_z, tile_x, tile_y): raise TileOutsideBounds("Tile {}/{}/{} is outside image bounds".format( tile_z, tile_x, tile_y)) mercator_tile = mercantile.Tile(x=tile_x, y=tile_y, z=tile_z) tile_bounds = mercantile.xy_bounds(mercator_tile) ms_tile_size = int(tilesize / 2) if pan else tilesize addresses = ["{}_B{}.TIF".format(landsat_address, band) for band in bands] _tiler = partial(utils.tile_read, bounds=tile_bounds, tilesize=ms_tile_size, nodata=0) with futures.ThreadPoolExecutor(max_workers=MAX_THREADS) as executor: data, masks = zip(*list(executor.map(_tiler, addresses))) data = np.concatenate(data) mask = np.all(masks, axis=0).astype(np.uint8) * 255 if pan: pan_address = "{}_B8.TIF".format(landsat_address) matrix_pan, mask = utils.tile_read(pan_address, tile_bounds, tilesize, nodata=0) w, s, e, n = tile_bounds pan_transform = transform.from_bounds(w, s, e, n, tilesize, tilesize) vis_transform = pan_transform * Affine.scale(2.0) data = pansharpen( data, vis_transform, matrix_pan, pan_transform, np.int16, "EPSG:3857", "EPSG:3857", 0.2, method="Brovey", src_nodata=0, ) sun_elev = meta_data["IMAGE_ATTRIBUTES"]["SUN_ELEVATION"] for bdx, band in enumerate(bands): if int(band) > 9: # TIRS multi_rad = meta_data["RADIOMETRIC_RESCALING"].get( "RADIANCE_MULT_BAND_{}".format(band)) add_rad = meta_data["RADIOMETRIC_RESCALING"].get( "RADIANCE_ADD_BAND_{}".format(band)) k1 = meta_data["TIRS_THERMAL_CONSTANTS"].get( "K1_CONSTANT_BAND_{}".format(band)) k2 = meta_data["TIRS_THERMAL_CONSTANTS"].get( "K2_CONSTANT_BAND_{}".format(band)) data[bdx] = brightness_temp.brightness_temp( data[bdx], multi_rad, add_rad, k1, k2) else: multi_reflect = meta_data["RADIOMETRIC_RESCALING"].get( "REFLECTANCE_MULT_BAND_{}".format(band)) add_reflect = meta_data["RADIOMETRIC_RESCALING"].get( "REFLECTANCE_ADD_BAND_{}".format(band)) data[bdx] = 10000 * reflectance.reflectance( data[bdx], multi_reflect, add_reflect, sun_elev) return data, mask