Exemple #1
0
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')
Exemple #2
0
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}
Exemple #3
0
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')
Exemple #4
0
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}')
Exemple #5
0
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}')
Exemple #6
0
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
Exemple #7
0
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
Exemple #8
0
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
Exemple #9
0
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
Exemple #10
0
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
Exemple #11
0
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
Exemple #12
0
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
Exemple #13
0
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
Exemple #14
0
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)
Exemple #15
0
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('')
Exemple #16
0
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)
Exemple #17
0
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)
Exemple #20
0
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 )
Exemple #22
0
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)
Exemple #23
0
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
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
Exemple #26
0
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:
Exemple #27
0
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')
Exemple #28
0
 def crs(self):
     sr = osr.SpatialReference()
     sr.ImportFromWkt(self.header['WKT'][0])
     crs = from_string(sr.ExportToProj4())
     return crs
Exemple #29
0
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)
Exemple #30
0
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,
                    )