def test_from_epsg_string(): crs_dict = crs.from_string('epsg:4326') assert crs_dict['init'].lower() == 'epsg:4326' # Test with invalid EPSG code with pytest.raises(ValueError): assert crs.from_string('epsg:xyz')
def test_from_string(): wgs84_crs = crs.from_string('+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs') assert wgs84_crs == {'no_defs': True, 'ellps': 'WGS84', 'datum': 'WGS84', 'proj': 'longlat'} # Make sure this doesn't get handled using the from_epsg() even though 'epsg' is in the string epsg_init_crs = crs.from_string('+units=m +init=epsg:26911 +no_defs=True') assert epsg_init_crs == {'units': 'm', 'init': 'epsg:26911', 'no_defs': True}
def test_from_proj4_json(): json_str = '{"proj": "longlat", "ellps": "WGS84", "datum": "WGS84"}' crs_dict = crs.from_string(json_str) assert crs_dict == json.loads(json_str) # Test with invalid JSON code with pytest.raises(ValueError): assert crs.from_string('{foo: bar}')
def test_is_projected(): assert is_projected_crs({'init': 'EPSG:3857'}) is True assert is_projected_crs({'init': 'EPSG:4326'}) is False lcc_crs = crs.from_string('+lon_0=-95 +ellps=GRS80 +y_0=0 +no_defs=True +proj=lcc +x_0=0 +units=m +lat_2=77 +lat_1=49 +lat_0=0') assert is_projected_crs(lcc_crs) is True wgs84_crs = crs.from_string('+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs') assert is_projected_crs(wgs84_crs) is False
def test_bare_parameters(): """ Make sure that bare parameters (e.g., no_defs) are handled properly, even if they come in with key=True. This covers interaction with pyproj, which makes presents bare parameters as key=<bool>.""" # Example produced by pyproj crs_dict = crs.from_string('+lon_0=-95 +ellps=GRS80 +y_0=0 +no_defs=True +proj=lcc +x_0=0 +units=m +lat_2=77 +lat_1=49 +lat_0=0') assert crs_dict.get('no_defs', False) is True crs_dict = crs.from_string('+lon_0=-95 +ellps=GRS80 +y_0=0 +no_defs=False +proj=lcc +x_0=0 +units=m +lat_2=77 +lat_1=49 +lat_0=0') assert crs_dict.get('no_defs', True) is False
def test_is_geographic(): assert is_geographic_crs({'init': 'EPSG:4326'}) is True assert is_geographic_crs({'init': 'EPSG:3857'}) is False wgs84_crs = crs.from_string('+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs') assert is_geographic_crs(wgs84_crs) is True nad27_crs = crs.from_string('+proj=longlat +ellps=clrk66 +datum=NAD27 +no_defs') assert is_geographic_crs(nad27_crs) is True lcc_crs = crs.from_string('+lon_0=-95 +ellps=GRS80 +y_0=0 +no_defs=True +proj=lcc +x_0=0 +units=m +lat_2=77 +lat_1=49 +lat_0=0') assert is_geographic_crs(lcc_crs) is False
def test_is_same_crs(): crs1 = {'init': 'EPSG:4326'} crs2 = {'init': 'EPSG:3857'} assert is_same_crs(crs1, crs1) is True assert is_same_crs(crs1, crs2) is False wgs84_crs = crs.from_string('+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs') assert is_same_crs(crs1, wgs84_crs) is True # Make sure that same projection with different parameter are not equal lcc_crs1 = crs.from_string('+lon_0=-95 +ellps=GRS80 +y_0=0 +no_defs=True +proj=lcc +x_0=0 +units=m +lat_2=77 +lat_1=49 +lat_0=0') lcc_crs2 = crs.from_string('+lon_0=-95 +ellps=GRS80 +y_0=0 +no_defs=True +proj=lcc +x_0=0 +units=m +lat_2=77 +lat_1=45 +lat_0=0') assert is_same_crs(lcc_crs1, lcc_crs2) is False
def convert(package_name, blocksize=256, compression=1): """ Convets a GA packaged product containing GTiff's and converts to a single KEA file format. """ acqs = acquisitions(package_name) bands = len(acqs) geobox = gridded_geo_box(acqs[0]) cols, rows = geobox.get_shape_xy() crs = from_string(geobox.crs.ExportToProj4()) dtype = acqs[0].data(window=((0, 1), (0, 1))).dtype.name no_data = acqs[0].no_data tiles = generate_tiles(cols, rows, blocksize, blocksize) fname_fmt = '{}_compress{}_blocksize{}.kea' base_name = basename(dirname(acqs[0].dir_name)) fname = pjoin(acqs[0].dir_name, fname_fmt.format(base_name, compression, blocksize)) kwargs = {'driver': 'KEA', 'count': bands, 'width': cols, 'height': rows, 'crs': crs, 'transform': geobox.affine, 'dtype': dtype, 'nodata': no_data, 'deflate': compression, 'imageblocksize': blocksize} with rasterio.open(fname, 'w', **kwargs) as src: for tile in tiles: img, _ = stack_data(acqs, window=tile) src.write(img, range(1, len(acqs) + 1), window=tile)
def test_empty_json(): with pytest.raises(CRSError): crs.from_string('{}') with pytest.raises(CRSError): crs.from_string('[]') with pytest.raises(CRSError): crs.from_string('')
def project2wgs(gtiff, output): with rio.Env(): with rio.open(gtiff) as src: out_kwargs = src.meta.copy() out_kwargs['driver'] = 'GTiff' print(out_kwargs) res = (0.01, 0.01) dst_crs = crs.from_string('+units=m +init=epsg:4326') #dst_width, dst_height = src.width, src.height xmin, ymin, xmax, ymax = [ -127.8294048826629989, 5.1830409679864857, -59.0561278820333229, 49.9999999955067977 ] dst_transform = Affine(res[0], 0, xmin, 0, -res[1], ymax) dst_width = max(int(ceil((xmax - xmin) / res[0])), 1) dst_height = max(int(ceil((ymax - ymin) / res[1])), 1) print(dst_transform) out_kwargs.update({ 'crs': dst_crs, 'transform': dst_transform, 'affine': dst_transform, 'width': dst_width, 'height': dst_height }) print(out_kwargs) with rio.open(output, 'w', **out_kwargs) as dst: reproject(source=rio.band(src, 1), destination=rio.band(dst, 1), src_transform=src.affine, src_crs=src.crs, src_nodata=src.nodata, dst_transform=out_kwargs['transform'], dst_crs=out_kwargs['crs'], dst_nodata=src.nodata, resampling=0, num_threads=2)
def project2wgs(gtiff, output): with rio.Env(): with rio.open(gtiff) as src: out_kwargs = src.meta.copy() out_kwargs['driver'] = 'GTiff' print(out_kwargs) res = (0.01, 0.01) dst_crs = crs.from_string('+units=m +init=epsg:4326') #dst_width, dst_height = src.width, src.height xmin, ymin, xmax, ymax = [-127.8294048826629989,5.1830409679864857, -59.0561278820333229,49.9999999955067977] dst_transform = Affine(res[0], 0, xmin, 0, -res[1], ymax) dst_width = max(int(ceil((xmax - xmin) / res[0])), 1) dst_height = max(int(ceil((ymax - ymin) / res[1])), 1) print(dst_transform) out_kwargs.update({ 'crs': dst_crs, 'transform': dst_transform, 'affine': dst_transform, 'width': dst_width, 'height': dst_height }) print(out_kwargs) with rio.open(output, 'w', **out_kwargs) as dst: reproject( source=rio.band(src, 1), destination=rio.band(dst, 1), src_transform=src.affine, src_crs=src.crs, src_nodata=src.nodata, dst_transform=out_kwargs['transform'], dst_crs=out_kwargs['crs'], dst_nodata=src.nodata, resampling=0, num_threads=2)
def rasterise_vector(vector_filename, shape=None, transform=None, crs=None, raster_filename=None, dtype='uint32'): """ Given a full file pathname to a vector file, rasterise the vectors geometry by either provding the raster shape and transform, or a raster file on disk. :param vector_filename: A full file pathname to an OGR compliant vector file. :param shape: Optional. If provided, then shape is a tuple containing the (height, width) of an array. If omitted, then `shape` will be retrieved via the raster provided in `raster_filename`. :param transform: Optional. If provided, then an `Affine` containing the transformation matrix parameters. If omitted, then `transform` will be retrieved via the `raster_filename`. :param crs: Optional. If provided, then WKT should be provided. If omitted, then `crs` will be retreived via the `raster_filename`. :param raster_filename: A full file pathname to a GDAL compliant raster file. :return: A `NumPy` array of the same dimensions provided by either the `shape` or `raster_filename`. :notes: The vector file will be re-projected as required in order to match the same crs as provided by `crs` or by `raster_filename`. """ with fiona.open(vector_filename, 'r') as v_src: if raster_filename is not None: with rasterio.open(raster_filename, 'r') as r_src: transform = r_src.affine shape = r_src.shape crs = r_src.crs r_bounds = tuple(r_src.bounds) else: ul = (0, 0) * transform lr = (shape[1], shape[0]) * transform min_x, max_x = min(ul[0], lr[0]), max(ul[0], lr[0]) min_y, max_y = min(ul[1], lr[1]), max(ul[1], lr[1]) r_bounds = (min_x, min_y, max_x, max_y) # convert the crs_wkt to a dict styled proj4 sr = osr.SpatialReference() sr.ImportFromWkt(crs) if CRS_CLASS: crs = CRS.from_string(sr.ExportToProj4()) else: crs = from_string(sr.ExportToProj4()) # rasterio has a CRS class that makes for easier crs comparison if CRS_CLASS: v_crs = CRS(v_src.crs) same_crs = v_crs == crs # fiona may update to the class crs in future, but for now... crs = crs.to_dict() else: same_crs = is_same_crs(v_src.crs, crs) # use rtree where possible for speedy shape reduction if RTREE: shapes = {} index = rtree.index.Index() # get crs, check if the same as the image and project as needed if not same_crs: for feat in v_src: new_geom = transform_geom(v_src.crs, crs, feat['geometry']) fid = int(feat['id']) shapes[fid] = (new_geom, fid + 1) index.insert(fid, shp(new_geom).bounds) else: for feat in v_src: fid = int(feat['id']) shapes[fid] = (feat['geometry'], fid + 1) index.insert(fid, shp(feat['geometry']).bounds) # we check the bounding box of each geometry object against # the image bounding box. Basic pre-selection to filter which # vectors are to be rasterised # bounding box intersection fids = index.intersection(r_bounds) selected_shapes = [shapes[fid] for fid in fids] else: selected_shapes = [] r_poly = box(*r_bounds) if not same_crs: for feat in v_src: new_geom = transform_geom(v_src.crs, crs, feat['geometry']) fid = int(feat['id']) geom = shp(new_geom) if geom.intersects(r_poly): selected_shapes.append((new_geom, fid + 1)) else: for feat in v_src: fid = int(feat['id']) geom = shp(feat['geometry']) if geom.intersects(r_poly): selected_shapes.append((feat['geometry'], fid + 1)) rasterised = rasterize(selected_shapes, out_shape=shape, fill=0, transform=transform, dtype=dtype) return rasterised
def cog_windowed_read(image_path, tile_ind, chan_inds=(1, ), final_proj=None): """Get raster data from a cloud-optimized-geotiff using a tile's bounds. Parameters ---------- image_path: str COG file path as local file or path to remote image. tile_ind: dict or str Dictionary with keys `z`, `x`, `y` defined or str in `z-x-y` format. chan_inds: tuple of int Channel indicies to grab from COG. Usually, `(1)` for L and `(1, 2, 3)` for RGB. final_proj: str Output projection for data if a projection different from the COG is needed. Returns ------- window_data: np.ndarray Array containing data values requested in tile_ind. """ if isinstance(tile_ind, dict): tile = Tile.from_tms(tile_ind['x'], tile_ind['y'], tile_ind['z']) elif isinstance(tile_ind, str): z, x, y = [int(val) for val in tile_ind.split('-')] tile = Tile.from_tms(x, y, z) else: raise ValueError( 'Could not parse `tile_ind` as string or dict: {}'.format( tile_ind)) with rasterio.open(image_path) as cog_image: p1 = Proj({'init': 'epsg:4326'}) p2 = Proj(**cog_image.crs) # Convert tile lat/lon bounds to COG ref frame # (pygeotile bounds are (LL, UR)) window_bounds = dict() window_bounds['west'], window_bounds['north'] = \ transform(p1, p2, tile.bounds[0].longitude, tile.bounds[1].latitude) window_bounds['east'], window_bounds['south'] = \ transform(p1, p2, tile.bounds[1].longitude, tile.bounds[0].latitude) # Get image origin point and resolution from the COG tif_bounds = dict(north=cog_image.bounds.top, west=cog_image.bounds.left) x_res, y_res = cog_image.transform[0], cog_image.transform[4] # Calculate the pixel indices of the window top = int((window_bounds['north'] - tif_bounds['north']) / y_res) left = int((window_bounds['west'] - tif_bounds['west']) / x_res) bottom = int((window_bounds['south'] - tif_bounds['north']) / y_res) right = int((window_bounds['east'] - tif_bounds['west']) / x_res) window_pixels = ((top, bottom), (left, right)) # Access the pixels of TIF image # XXX Seems to force data to the output shape window_data = np.empty((len(chan_inds), 256, 256), cog_image.profile['dtype']) for ci in chan_inds: cog_image.read(ci, window=window_pixels, out=window_data[ci - 1], boundless=True) # If user wants a specific transform, do that now if final_proj is not None: profile = cog_image.profile dst_crs = crs.from_string(final_proj) # Calculate the ideal dimensions and transformation in the new crs # XXX Possible to define resolution here dst_affine, dst_width, dst_height = calculate_default_transform( cog_image.crs, dst_crs, 256, 256, left=left, bottom=bottom, right=right, top=top) profile.update({ 'crs': dst_crs, 'transform': dst_affine, 'affine': dst_affine, 'width': dst_width, 'height': dst_height }) # Create an array for the projected window window_data_proj = np.empty( (len(chan_inds), dst_height, dst_width), cog_image.profile['dtype']) reproject(source=window_data, src_crs=cog_image.crs, src_transform=cog_image.affine, destination=window_data_proj, dst_transform=dst_affine, dst_crs=dst_crs, resampling=Resampling.nearest) return np.moveaxis(window_data_proj, 0, -1) return np.moveaxis(window_data, 0, -1)
def warp(ctx, files, output, driver, like, dst_crs, dimensions, src_bounds, x_dst_bounds, bounds, res, resampling, threads, check_invert_proj, force_overwrite, creation_options): """ Warp a raster dataset. If a template raster is provided using the --like option, the coordinate reference system, affine transform, and dimensions of that raster will be used for the output. In this case --dst-crs, --bounds, --res, and --dimensions options are ignored. \b $ rio warp input.tif output.tif --like template.tif The output coordinate reference system may be either a PROJ.4 or EPSG:nnnn string, \b --dst-crs EPSG:4326 --dst-crs '+proj=longlat +ellps=WGS84 +datum=WGS84' or a JSON text-encoded PROJ.4 object. \b --dst-crs '{"proj": "utm", "zone": 18, ...}' If --dimensions are provided, --res and --bounds are ignored. Resolution is calculated based on the relationship between the raster bounds in the target coordinate system and the dimensions, and may produce rectangular rather than square pixels. \b $ rio warp input.tif output.tif --dimensions 100 200 \\ > --dst-crs EPSG:4326 If --bounds are provided, --res is required if --dst-crs is provided (defaults to source raster resolution otherwise). \b $ rio warp input.tif output.tif \\ > --bounds -78 22 -76 24 --res 0.1 --dst-crs EPSG:4326 """ verbosity = (ctx.obj and ctx.obj.get('verbosity')) or 1 output, files = resolve_inout( files=files, output=output, force_overwrite=force_overwrite) resampling = Resampling[resampling] # get integer code for method if not len(res): # Click sets this as an empty tuple if not provided res = None else: # Expand one value to two if needed res = (res[0], res[0]) if len(res) == 1 else res with Env(CPL_DEBUG=verbosity > 2, CHECK_WITH_INVERT_PROJ=check_invert_proj) as env: with rasterio.open(files[0]) as src: l, b, r, t = src.bounds out_kwargs = src.meta.copy() out_kwargs['driver'] = driver # Sort out the bounds options. src_bounds = bounds or src_bounds dst_bounds = x_dst_bounds if src_bounds and dst_bounds: raise click.BadParameter( "Source and destination bounds may not be specified " "simultaneously.") if like: with rasterio.open(like) as template_ds: dst_crs = template_ds.crs dst_transform = template_ds.affine dst_height = template_ds.height dst_width = template_ds.width elif dst_crs is not None: try: dst_crs = crs.from_string(dst_crs) except ValueError as err: raise click.BadParameter( str(err), param='dst_crs', param_hint='dst_crs') if dimensions: # Calculate resolution appropriate for dimensions # in target. dst_width, dst_height = dimensions try: xmin, ymin, xmax, ymax = transform_bounds( src.crs, dst_crs, *src.bounds) except CRSError as err: raise click.BadParameter( str(err), param='dst_crs', param_hint='dst_crs') dst_transform = Affine( (xmax - xmin) / float(dst_width), 0, xmin, 0, (ymin - ymax) / float(dst_height), ymax ) elif src_bounds or dst_bounds: if not res: raise click.BadParameter( "Required when using --bounds.", param='res', param_hint='res') if src_bounds: try: xmin, ymin, xmax, ymax = transform_bounds( src.crs, dst_crs, *src_bounds) except CRSError as err: raise click.BadParameter( str(err), param='dst_crs', param_hint='dst_crs') else: xmin, ymin, xmax, ymax = dst_bounds dst_transform = Affine(res[0], 0, xmin, 0, -res[1], ymax) dst_width = max(int(ceil((xmax - xmin) / res[0])), 1) dst_height = max(int(ceil((ymax - ymin) / res[1])), 1) else: try: dst_transform, dst_width, dst_height = calculate_default_transform( src.crs, dst_crs, src.width, src.height, *src.bounds, resolution=res) except CRSError as err: raise click.BadParameter( str(err), param='dst_crs', param_hint='dst_crs') elif dimensions: # Same projection, different dimensions, calculate resolution. dst_crs = src.crs dst_width, dst_height = dimensions dst_transform = Affine( (r - l) / float(dst_width), 0, l, 0, (b - t) / float(dst_height), t ) elif src_bounds or dst_bounds: # Same projection, different dimensions and possibly # different resolution. if not res: res = (src.affine.a, -src.affine.e) dst_crs = src.crs xmin, ymin, xmax, ymax = (src_bounds or dst_bounds) dst_transform = Affine(res[0], 0, xmin, 0, -res[1], ymax) dst_width = max(int(ceil((xmax - xmin) / res[0])), 1) dst_height = max(int(ceil((ymax - ymin) / res[1])), 1) elif res: # Same projection, different resolution. dst_crs = src.crs dst_transform = Affine(res[0], 0, l, 0, -res[1], t) dst_width = max(int(ceil((r - l) / res[0])), 1) dst_height = max(int(ceil((t - b) / res[1])), 1) else: dst_crs = src.crs dst_transform = src.affine dst_width = src.width dst_height = src.height # When the bounds option is misused, extreme values of # destination width and height may result. if (dst_width < 0 or dst_height < 0 or dst_width > MAX_OUTPUT_WIDTH or dst_height > MAX_OUTPUT_HEIGHT): raise click.BadParameter( "Invalid output dimensions: {0}.".format( (dst_width, dst_height))) out_kwargs.update({ 'crs': dst_crs, 'transform': dst_transform, 'affine': dst_transform, 'width': dst_width, 'height': dst_height }) out_kwargs.update(**creation_options) with rasterio.open(output, 'w', **out_kwargs) as dst: for i in range(1, src.count + 1): reproject( source=rasterio.band(src, i), destination=rasterio.band(dst, i), src_transform=src.affine, src_crs=src.crs, # src_nodata=#TODO dst_transform=out_kwargs['transform'], dst_crs=out_kwargs['crs'], # dst_nodata=#TODO resampling=resampling, num_threads=threads)
# get the historicals for climatology ds_hist = xr.open_dataset( fn_hist ) ds_hist = ds_hist[ variable ].sel( time=slice( '01-1961', '12-1990' ) ) ds_hist = ds_hist - 273.15 climatology = ds_hist.groupby( 'time.month' ).mean( axis=0 ) # create anomalies anomalies = ds.groupby( 'time.month' ) - climatology count, height, width = ds.shape affine = transform_from_latlon( np.flipud(ds.lat), ds.lon ) # can we window the data here? # this will involve generating a window object using rasterio and extracting using slicing. meta = { 'crs':crs.from_string( pacific ), 'affine':affine, 'dtype':'float64', 'driver':'MEM', 'height': height, 'width': width, 'count':count } dat = np.flipud( ds.data ) out_fn = '' with rasterio.open( out_fn, 'w', **meta ) as rst: window = rst.window( *bounds.as_matrix().ravel().tolist() ) rst.write( dat ) # read it back from window new_affine = rst.window_transform( window )
def warp( ctx, input, output, driver, like, dst_crs, dimensions, bounds, res, resampling, threads, creation_options): """ Warp a raster dataset. Currently, the output is always overwritten. This will be changed in a later version. If a template raster is provided using the --like option, the coordinate reference system, affine transform, and dimensions of that raster will be used for the output. In this case --dst-crs, --bounds, --res, and --dimensions options are ignored. \b $ rio warp input.tif output.tif --like template.tif The output coordinate reference system may be either a PROJ.4 or EPSG:nnnn string, \b --dst-crs EPSG:4326 --dst-crs '+proj=longlat +ellps=WGS84 +datum=WGS84' or a JSON text-encoded PROJ.4 object. \b --dst-crs '{"proj": "utm", "zone": 18, ...}' If --dimensions are provided, --res and --bounds are ignored. Resolution is calculated based on the relationship between the raster bounds in the target coordinate system and the dimensions, and may produce rectangular rather than square pixels. \b $ rio warp input.tif output.tif --dimensions 100 200 --dst-crs EPSG:4326 If --bounds are provided, --res is required if --dst-crs is provided (defaults to source raster resolution otherwise). Bounds are in the source coordinate reference system. \b $ rio warp input.tif output.tif --bounds -78 22 -76 24 --dst-crs \\ EPSG:4326 --res 0.1 """ verbosity = (ctx.obj and ctx.obj.get('verbosity')) or 1 resampling = getattr(RESAMPLING, resampling) # get integer code for method if not len(res): # Click sets this as an empty tuple if not provided res = None else: # Expand one value to two if needed res = (res[0], res[0]) if len(res) == 1 else res with rasterio.drivers(CPL_DEBUG=verbosity > 2): with rasterio.open(input) as src: l, b, r, t = src.bounds out_kwargs = src.meta.copy() out_kwargs['driver'] = driver if like: with rasterio.open(like) as template_ds: dst_crs = template_ds.crs dst_transform = template_ds.affine dst_height = template_ds.height dst_width = template_ds.width elif dst_crs: try: dst_crs = crs.from_string(dst_crs) except ValueError: raise click.BadParameter('invalid crs format', param=dst_crs, param_hint=dst_crs) if dimensions: # Calculate resolution appropriate for dimensions in target dst_width, dst_height = dimensions xmin, ymin, xmax, ymax = transform_bounds(src.crs, dst_crs, *src.bounds) dst_transform = Affine( (xmax - xmin) / float(dst_width), 0, xmin, 0, (ymin - ymax) / float(dst_height), ymax ) elif bounds: if not res: raise click.BadParameter('Required when using --bounds', param='res', param_hint='res') xmin, ymin, xmax, ymax = transform_bounds(src.crs, dst_crs, *bounds) dst_transform = Affine(res[0], 0, xmin, 0, -res[1], ymax) dst_width = max(int(ceil((xmax - xmin) / res[0])), 1) dst_height = max(int(ceil((ymax - ymin) / res[1])), 1) else: dst_transform, dst_width, dst_height = calculate_default_transform( src.crs, dst_crs, src.width, src.height, *src.bounds, resolution=res) elif dimensions: # Same projection, different dimensions, calculate resolution dst_crs = src.crs dst_width, dst_height = dimensions dst_transform = Affine( (r - l) / float(dst_width), 0, l, 0, (b - t) / float(dst_height), t ) elif bounds: # Same projection, different dimensions and possibly different # resolution if not res: res = (src.affine.a, -src.affine.e) dst_crs = src.crs xmin, ymin, xmax, ymax = bounds dst_transform = Affine(res[0], 0, xmin, 0, -res[1], ymax) dst_width = max(int(ceil((xmax - xmin) / res[0])), 1) dst_height = max(int(ceil((ymax - ymin) / res[1])), 1) elif res: # Same projection, different resolution dst_crs = src.crs dst_transform = Affine(res[0], 0, l, 0, -res[1], t) dst_width = max(int(ceil((r - l) / res[0])), 1) dst_height = max(int(ceil((t - b) / res[1])), 1) else: dst_crs = src.crs dst_transform = src.affine dst_width = src.width dst_height = src.height out_kwargs.update({ 'crs': dst_crs, 'transform': dst_transform, 'affine': dst_transform, 'width': dst_width, 'height': dst_height }) out_kwargs.update(**creation_options) with rasterio.open(output, 'w', **out_kwargs) as dst: for i in range(1, src.count + 1): reproject( source=rasterio.band(src, i), destination=rasterio.band(dst, i), src_transform=src.affine, src_crs=src.crs, # src_nodata=#TODO dst_transform=out_kwargs['transform'], dst_crs=out_kwargs['crs'], # dst_nodata=#TODO resampling=resampling, num_threads=threads)
import numpy as np import rasterio from rasterio.warp import calculate_default_transform, reproject, Resampling from rasterio import crs rgb = 'tests/data/world.tif' out = '/tmp/reproj.tif' # Reproject to NAD83(HARN) / Hawaii zone 3 (ftUS) - Transverse Mercator dst_crs = crs.from_string("EPSG:3759") with rasterio.Env(CHECK_WITH_INVERT_PROJ=True): with rasterio.open(rgb) as src: profile = src.profile # Calculate the ideal dimensions and transformation in the new crs dst_affine, dst_width, dst_height = calculate_default_transform( src.crs, dst_crs, src.width, src.height, *src.bounds) # update the relevant parts of the profile profile.update({ 'crs': dst_crs, 'transform': dst_affine, 'width': dst_width, 'height': dst_height }) # Reproject and write each band with rasterio.open(out, 'w', **profile) as dst: for i in range(1, src.count + 1): src_array = src.read(i)
# get the historicals for climatology ds_hist = xr.open_dataset(fn_hist) ds_hist = ds_hist[variable].sel(time=slice('01-1961', '12-1990')) ds_hist = ds_hist - 273.15 climatology = ds_hist.groupby('time.month').mean(axis=0) # create anomalies anomalies = ds.groupby('time.month') - climatology count, height, width = ds.shape affine = transform_from_latlon(np.flipud(ds.lat), ds.lon) # can we window the data here? # this will involve generating a window object using rasterio and extracting using slicing. meta = { 'crs': crs.from_string(pacific), 'affine': affine, 'dtype': 'float64', 'driver': 'MEM', 'height': height, 'width': width, 'count': count } dat = np.flipud(ds.data) out_fn = '' with rasterio.open(out_fn, 'w', **meta) as rst: window = rst.window(*bounds.as_matrix().ravel().tolist()) rst.write(dat) # read it back from window
import numpy as np import rasterio from rasterio.warp import calculate_default_transform, reproject, Resampling from rasterio import crs rgb = 'tests/data/world.tif' out = '/tmp/reproj.tif' # Reproject to NAD83(HARN) / Hawaii zone 3 (ftUS) - Transverse Mercator dst_crs = crs.from_string("EPSG:3759") with rasterio.drivers(CHECK_WITH_INVERT_PROJ=True): with rasterio.open(rgb) as src: profile = src.profile # Calculate the ideal dimensions and transformation in the new crs dst_affine, dst_width, dst_height = calculate_default_transform( src.crs, dst_crs, src.width, src.height, *src.bounds) # update the relevant parts of the profile profile.update({ 'crs': dst_crs, 'transform': dst_affine, 'affine': dst_affine, 'width': dst_width, 'height': dst_height }) # Reproject and write each band with rasterio.open(out, 'w', **profile) as dst:
def miniaturize(source, destination, offset, size, pattern, ignore_pattern, dst_crs): """ Miniaturize an ESPA download """ ox, oy = offset sx, sy = size window = ((oy, oy + sy), (ox, ox + sx)) if dst_crs: try: dst_crs = crs.from_string(dst_crs) except ValueError: raise click.BadParameter('Invalid crs format', param=dst_crs, param_hint=dst_crs) source_id = os.path.basename(source).split(os.extsep, 1)[0] with temp_expand(source) as source: ignore = [] for _ignore_pattern in ignore_pattern: ignore.extend(fnmatch.filter(os.listdir(source), _ignore_pattern)) sources = sorted([os.path.join(source, f) for f in fnmatch.filter(os.listdir(source), pattern)]) ancillary = set([os.path.join(source, f) for f in os.listdir(source) if f not in ignore]).difference(sources) if not sources: raise click.ClickException('Cannot find any files in {}' .format(source)) with tarfile.open(destination, 'w:gz') as tardest: for _anc in ancillary: _anc_id = os.path.join(source_id, os.path.basename(_anc)) tardest.add(_anc, arcname=_anc_id) click.echo('Added {} to {}' .format(_anc_id, destination)) for src in sources: src_name = os.path.join(source_id, os.path.basename(src)) # Copy over window with rasterio.open(src, 'r') as src_ds: meta = src_ds.meta.copy() meta.update({ 'width': sx, 'height': sy, 'count': 1, }) affine, width, height = calculate_default_transform( src_ds.crs, dst_crs or src_ds.crs, sx, sy, *src_ds.window_bounds(window), src_ds.res ) meta.update({ 'affine': affine, 'transform': affine, 'width': width, 'height': height, 'crs': dst_crs or src_ds.crs }) with temp_file() as dst: with rasterio.open(dst, 'w', **meta) as dst_ds: if dst_crs: reproject( source=rasterio.band(src_ds, 1), destination=rasterio.band(dst_ds, 1), src_transform=src_ds.affine, src_crs=src_ds.crs, dst_transform=dst_ds.affine, dst_crs=dst_ds.crs, src_nodata=src_ds.nodata, dst_nodata=dst_ds.nodata, resampling=RESAMPLING.nearest ) else: dst_ds.write_band( 1, src_ds.read(1, window=window)) tardest.add(dst, arcname=src_name) click.echo('Added {} to {}' .format(src_name, destination)) click.echo('Complete')
def crs(self): sr = osr.SpatialReference() sr.ImportFromWkt(self.header['WKT'][0]) crs = from_string(sr.ExportToProj4()) return crs
def warp(ctx, files, output, driver, like, dst_crs, dimensions, src_bounds, x_dst_bounds, bounds, res, resampling, src_nodata, dst_nodata, threads, check_invert_proj, force_overwrite, creation_options): """ Warp a raster dataset. If a template raster is provided using the --like option, the coordinate reference system, affine transform, and dimensions of that raster will be used for the output. In this case --dst-crs, --bounds, --res, and --dimensions options are ignored. \b $ rio warp input.tif output.tif --like template.tif The output coordinate reference system may be either a PROJ.4 or EPSG:nnnn string, \b --dst-crs EPSG:4326 --dst-crs '+proj=longlat +ellps=WGS84 +datum=WGS84' or a JSON text-encoded PROJ.4 object. \b --dst-crs '{"proj": "utm", "zone": 18, ...}' If --dimensions are provided, --res and --bounds are ignored. Resolution is calculated based on the relationship between the raster bounds in the target coordinate system and the dimensions, and may produce rectangular rather than square pixels. \b $ rio warp input.tif output.tif --dimensions 100 200 \\ > --dst-crs EPSG:4326 If --bounds are provided, --res is required if --dst-crs is provided (defaults to source raster resolution otherwise). \b $ rio warp input.tif output.tif \\ > --bounds -78 22 -76 24 --res 0.1 --dst-crs EPSG:4326 """ verbosity = (ctx.obj and ctx.obj.get('verbosity')) or 1 output, files = resolve_inout( files=files, output=output, force_overwrite=force_overwrite) resampling = Resampling[resampling] # get integer code for method if not len(res): # Click sets this as an empty tuple if not provided res = None else: # Expand one value to two if needed res = (res[0], res[0]) if len(res) == 1 else res with rasterio.Env(CPL_DEBUG=verbosity > 2, CHECK_WITH_INVERT_PROJ=check_invert_proj): with rasterio.open(files[0]) as src: l, b, r, t = src.bounds out_kwargs = src.meta.copy() out_kwargs['driver'] = driver # Sort out the bounds options. src_bounds = bounds or src_bounds dst_bounds = x_dst_bounds if src_bounds and dst_bounds: raise click.BadParameter( "Source and destination bounds may not be specified " "simultaneously.") if like: with rasterio.open(like) as template_ds: dst_crs = template_ds.crs dst_transform = template_ds.affine dst_height = template_ds.height dst_width = template_ds.width elif dst_crs is not None: try: dst_crs = crs.from_string(dst_crs) except ValueError as err: raise click.BadParameter( str(err), param='dst_crs', param_hint='dst_crs') if dimensions: # Calculate resolution appropriate for dimensions # in target. dst_width, dst_height = dimensions try: xmin, ymin, xmax, ymax = transform_bounds( src.crs, dst_crs, *src.bounds) except CRSError as err: raise click.BadParameter( str(err), param='dst_crs', param_hint='dst_crs') dst_transform = Affine( (xmax - xmin) / float(dst_width), 0, xmin, 0, (ymin - ymax) / float(dst_height), ymax ) elif src_bounds or dst_bounds: if not res: raise click.BadParameter( "Required when using --bounds.", param='res', param_hint='res') if src_bounds: try: xmin, ymin, xmax, ymax = transform_bounds( src.crs, dst_crs, *src_bounds) except CRSError as err: raise click.BadParameter( str(err), param='dst_crs', param_hint='dst_crs') else: xmin, ymin, xmax, ymax = dst_bounds dst_transform = Affine(res[0], 0, xmin, 0, -res[1], ymax) dst_width = max(int(ceil((xmax - xmin) / res[0])), 1) dst_height = max(int(ceil((ymax - ymin) / res[1])), 1) else: try: dst_transform, dst_width, dst_height = calculate_default_transform( src.crs, dst_crs, src.width, src.height, *src.bounds, resolution=res) except CRSError as err: raise click.BadParameter( str(err), param='dst_crs', param_hint='dst_crs') elif dimensions: # Same projection, different dimensions, calculate resolution. dst_crs = src.crs dst_width, dst_height = dimensions dst_transform = Affine( (r - l) / float(dst_width), 0, l, 0, (b - t) / float(dst_height), t ) elif src_bounds or dst_bounds: # Same projection, different dimensions and possibly # different resolution. if not res: res = (src.affine.a, -src.affine.e) dst_crs = src.crs xmin, ymin, xmax, ymax = (src_bounds or dst_bounds) dst_transform = Affine(res[0], 0, xmin, 0, -res[1], ymax) dst_width = max(int(ceil((xmax - xmin) / res[0])), 1) dst_height = max(int(ceil((ymax - ymin) / res[1])), 1) elif res: # Same projection, different resolution. dst_crs = src.crs dst_transform = Affine(res[0], 0, l, 0, -res[1], t) dst_width = max(int(ceil((r - l) / res[0])), 1) dst_height = max(int(ceil((t - b) / res[1])), 1) else: dst_crs = src.crs dst_transform = src.affine dst_width = src.width dst_height = src.height # If src_nodata is not None, update the dst metadata NODATA # value to src_nodata (will be overridden by dst_nodata if it is not None if src_nodata is not None: # Update the dst nodata value out_kwargs.update({ 'nodata': src_nodata }) # Validate a manually set destination NODATA value # against the input datatype. if dst_nodata is not None: if src_nodata is None and src.meta['nodata'] is None: raise click.BadParameter( "--src-nodata must be provided because dst-nodata is not None") else: # Update the dst nodata value out_kwargs.update({ 'nodata': dst_nodata }) # When the bounds option is misused, extreme values of # destination width and height may result. if (dst_width < 0 or dst_height < 0 or dst_width > MAX_OUTPUT_WIDTH or dst_height > MAX_OUTPUT_HEIGHT): raise click.BadParameter( "Invalid output dimensions: {0}.".format( (dst_width, dst_height))) out_kwargs.update({ 'crs': dst_crs, 'transform': dst_transform, 'affine': dst_transform, 'width': dst_width, 'height': dst_height }) out_kwargs.update(**creation_options) with rasterio.open(output, 'w', **out_kwargs) as dst: for i in range(1, src.count + 1): reproject( source=rasterio.band(src, i), destination=rasterio.band(dst, i), src_transform=src.affine, src_crs=src.crs, src_nodata=src_nodata, dst_transform=out_kwargs['transform'], dst_crs=out_kwargs['crs'], dst_nodata=dst_nodata, resampling=resampling, num_threads=threads)
def warp(ctx, input, output, driver, like, dst_crs, dimensions, bounds, res, resampling, threads, creation_options): """ Warp a raster dataset. Currently, the output is always overwritten. This will be changed in a later version. If a template raster is provided using the --like option, the coordinate reference system, affine transform, and dimensions of that raster will be used for the output. In this case --dst-crs, --bounds, --res, and --dimensions options are ignored. \b $ rio warp input.tif output.tif --like template.tif The output coordinate reference system may be either a PROJ.4 or EPSG:nnnn string, \b --dst-crs EPSG:4326 --dst-crs '+proj=longlat +ellps=WGS84 +datum=WGS84' or a JSON text-encoded PROJ.4 object. \b --dst-crs '{"proj": "utm", "zone": 18, ...}' If --dimensions are provided, --res and --bounds are ignored. Resolution is calculated based on the relationship between the raster bounds in the target coordinate system and the dimensions, and may produce rectangular rather than square pixels. \b $ rio warp input.tif output.tif --dimensions 100 200 --dst-crs EPSG:4326 If --bounds are provided, --res is required if --dst-crs is provided (defaults to source raster resolution otherwise). Bounds are in the source coordinate reference system. \b $ rio warp input.tif output.tif --bounds -78 22 -76 24 --dst-crs \\ EPSG:4326 --res 0.1 """ verbosity = (ctx.obj and ctx.obj.get("verbosity")) or 1 resampling = getattr(RESAMPLING, resampling) # get integer code for method if not len(res): # Click sets this as an empty tuple if not provided res = None else: # Expand one value to two if needed res = (res[0], res[0]) if len(res) == 1 else res with rasterio.drivers(CPL_DEBUG=verbosity > 2): with rasterio.open(input) as src: l, b, r, t = src.bounds out_kwargs = src.meta.copy() out_kwargs["driver"] = driver if like: with rasterio.open(like) as template_ds: dst_crs = template_ds.crs dst_transform = template_ds.affine dst_height = template_ds.height dst_width = template_ds.width elif dst_crs: try: dst_crs = crs.from_string(dst_crs) except ValueError: raise click.BadParameter("invalid crs format", param=dst_crs, param_hint=dst_crs) if dimensions: # Calculate resolution appropriate for dimensions in target dst_width, dst_height = dimensions xmin, ymin, xmax, ymax = transform_bounds(src.crs, dst_crs, *src.bounds) dst_transform = Affine( (xmax - xmin) / float(dst_width), 0, xmin, 0, (ymin - ymax) / float(dst_height), ymax ) elif bounds: if not res: raise click.BadParameter("Required when using --bounds", param="res", param_hint="res") xmin, ymin, xmax, ymax = transform_bounds(src.crs, dst_crs, *bounds) dst_transform = Affine(res[0], 0, xmin, 0, -res[1], ymax) dst_width = max(int(ceil((xmax - xmin) / res[0])), 1) dst_height = max(int(ceil((ymax - ymin) / res[1])), 1) else: dst_transform, dst_width, dst_height = calculate_default_transform( src.crs, dst_crs, src.width, src.height, *src.bounds, resolution=res ) elif dimensions: # Same projection, different dimensions, calculate resolution dst_crs = src.crs dst_width, dst_height = dimensions dst_transform = Affine((r - l) / float(dst_width), 0, l, 0, (b - t) / float(dst_height), t) elif bounds: # Same projection, different dimensions and possibly different # resolution if not res: res = (src.affine.a, -src.affine.e) dst_crs = src.crs xmin, ymin, xmax, ymax = bounds dst_transform = Affine(res[0], 0, xmin, 0, -res[1], ymax) dst_width = max(int(ceil((xmax - xmin) / res[0])), 1) dst_height = max(int(ceil((ymax - ymin) / res[1])), 1) elif res: # Same projection, different resolution dst_crs = src.crs dst_transform = Affine(res[0], 0, l, 0, -res[1], t) dst_width = max(int(ceil((r - l) / res[0])), 1) dst_height = max(int(ceil((t - b) / res[1])), 1) else: dst_crs = src.crs dst_transform = src.affine dst_width = src.width dst_height = src.height out_kwargs.update( { "crs": dst_crs, "transform": dst_transform, "affine": dst_transform, "width": dst_width, "height": dst_height, } ) out_kwargs.update(**creation_options) with rasterio.open(output, "w", **out_kwargs) as dst: for i in range(1, src.count + 1): reproject( source=rasterio.band(src, i), destination=rasterio.band(dst, i), src_transform=src.affine, src_crs=src.crs, # src_nodata=#TODO dst_transform=out_kwargs["transform"], dst_crs=out_kwargs["crs"], # dst_nodata=#TODO resampling=resampling, num_threads=threads, )