Exemple #1
0
def test_window_function():
    with rasterio.open('tests/data/RGB.byte.tif') as src:
        left, bottom, right, top = src.bounds
        dx, dy = src.res
        height = src.height
        width = src.width
        assert from_bounds(
            left + EPS, bottom + EPS, right - EPS, top - EPS, src.transform,
            height, width) == ((0, height), (0, width))
        assert from_bounds(
            left, top - 400, left + 400, top, src.transform,
            height, width) == ((0, 2), (0, 2))
        assert from_bounds(
            left, top - 2 * dy - EPS, left + 2 * dx - EPS, top, src.transform,
            height, width) == ((0, 2), (0, 2))

        # bounds cropped
        assert from_bounds(
            left - 2 * dx, top - 2 * dy, left + 2 * dx, top + 2 * dy,
            src.transform, height, width) == ((0, 2), (0, 2))

        # boundless
        assert from_bounds(
            left - 2 * dx, top - 2 * dy, left + 2 * dx, top + 2 * dy,
            src.transform, boundless=True) == ((-2, 2), (-2, 2))
Exemple #2
0
def extract_image(rst, polygon):

    with MemoryFile() as memfile:

        meta = rst.meta.copy()
        meta["count"] = 4

        rgb = mask(rst, [polygon])[0]
        a = raster_geometry_mask(rst, [polygon],
                                 invert=True)[0].astype(rio.uint8)
        a = np.where(a == 1, 255, 0).astype(rio.uint8)
        img_data = np.stack((rgb[0], rgb[1], rgb[2], a))

        with memfile.open(**meta) as masked:
            masked.write(img_data)

            r = masked.read(1,
                            window=from_bounds(*polygon.bounds, rst.transform))
            g = masked.read(2,
                            window=from_bounds(*polygon.bounds, rst.transform))
            b = masked.read(3,
                            window=from_bounds(*polygon.bounds, rst.transform))
            a = masked.read(4,
                            window=from_bounds(*polygon.bounds, rst.transform))

    img = Image.fromarray(np.dstack((r, g, b, a)))
    return img
Exemple #3
0
def test_issue_2138():
    """WindowError is raised if bounds and transform are inconsistent"""
    w, s, e, n = 1.0, 45.7, 1.2, 45.9
    a = 0.001
    transform = Affine.translation(w, n) * Affine.scale(a, -a)
    with pytest.raises(WindowError):
        from_bounds(w, n, e, s, transform)
Exemple #4
0
def test_window_function_valuerror():
    with rasterio.open('tests/data/RGB.byte.tif') as src:
        left, bottom, right, top = src.bounds

        with pytest.raises(ValueError):
            # No height or width
            from_bounds(left + EPS, bottom + EPS, right - EPS, top - EPS,
                        src.transform)
Exemple #5
0
    def window(self, left, bottom, right, top, boundless=False):
        """Get the window corresponding to the bounding coordinates.

        Parameters
        ----------
        left : float
            Left (west) bounding coordinate
        bottom : float
            Bottom (south) bounding coordinate
        right : float
            Right (east) bounding coordinate
        top : float
            Top (north) bounding coordinate
        boundless: boolean, optional
            If boundless is False, window is limited
            to extent of this dataset.

        Returns
        -------
        window: tuple
            ((row_start, row_stop), (col_start, col_stop))
            corresponding to the bounding coordinates

        """

        transform = guard_transform(self.transform)
        return windows.from_bounds(
            left, bottom, right, top, transform=transform,
            height=self.height, width=self.width, boundless=boundless)
Exemple #6
0
    def write(self, process_tile, data):
        """
        Write data from process tiles into GeoTIFF file(s).

        Parameters
        ----------
        process_tile : ``BufferedTile``
            must be member of process ``TilePyramid``
        """
        data = prepare_array(data,
                             masked=True,
                             nodata=self.output_params["nodata"],
                             dtype=self.profile(process_tile)["dtype"])

        if data.mask.all():
            logger.debug("data empty, nothing to write")
        else:
            # Convert from process_tile to output_tiles and write
            for tile in self.pyramid.intersecting(process_tile):
                out_tile = BufferedTile(tile, self.pixelbuffer)
                write_window = from_bounds(
                    *out_tile.bounds,
                    transform=self.rio_file.transform,
                    height=self.rio_file.height,
                    width=self.rio_file.width).round_lengths(
                        pixel_precision=0).round_offsets(pixel_precision=0)
                if _window_in_out_file(write_window, self.rio_file):
                    logger.debug("write data to window: %s", write_window)
                    self.rio_file.write(
                        extract_from_array(in_raster=data,
                                           in_affine=process_tile.affine,
                                           out_tile=out_tile)
                        if process_tile != out_tile else data,
                        window=write_window,
                    )
Exemple #7
0
    def reproject_band(self, band, src_transform, bbox):
        # shift dst_transform
        # bbox --> (left, bottom, right, top)
        assert self.out_res in ["10", "30", "20", "60"
                                ], "output resolution must be 10, 20, 30 or 60"

        transform_out_res = self.transform_dict[self.out_res][0]

        dst_transform = rasterio.Affine(
            transform_out_res.a, transform_out_res.b,
            bbox[0] if transform_out_res.a > 0 else bbox[2],
            transform_out_res.d, transform_out_res.e,
            bbox[3] if transform_out_res.e < 0 else bbox[1])

        window_read = windows.from_bounds(*bbox, dst_transform)
        shape_new = tuple([int(round(s)) for s in windows.shape(window_read)])
        data_new_proj = np.ndarray(shape=shape_new, dtype=band.dtype)

        reproject(band,
                  data_new_proj,
                  src_transform=src_transform,
                  src_crs=self.crs,
                  dst_transform=dst_transform,
                  dst_crs=self.crs,
                  resampling=Resampling.cubic_spline)

        return data_new_proj
Exemple #8
0
def _requested_tile_aligned_with_internal_tile(
    src_dst: Union[DatasetReader, DatasetWriter, WarpedVRT],
    bounds: Tuple[float, float, float, float],
    height: int,
    width: int,
) -> bool:
    """Check if tile is aligned with internal tiles."""
    if not src_dst.is_tiled:
        return False

    if src_dst.crs != constants.WEB_MERCATOR_CRS:
        return False

    col_off, row_off, w, h = windows.from_bounds(
        *bounds, height=height, transform=src_dst.transform, width=width
    ).flatten()

    if round(w) % 64 and round(h) % 64:
        return False

    if (src_dst.width - round(col_off)) % 64:
        return False

    if (src_dst.height - round(row_off)) % 64:
        return False

    return True
Exemple #9
0
def _bounds_to_ranges(bounds, affine, shape):
    return map(int, itertools.chain(
            *from_bounds(
                *bounds, transform=affine, height=shape[-2], width=shape[-1]
            ).round_lengths().round_offsets().toranges()
        )
    )
Exemple #10
0
    def window(self, left, bottom, right, top, precision=6, **kwargs):
        """Get the window corresponding to the bounding coordinates.

        The resulting window is not cropped to the row and column
        limits of the dataset.

        Parameters
        ----------
        left: float
            Left (west) bounding coordinate
        bottom: float
            Bottom (south) bounding coordinate
        right: float
            Right (east) bounding coordinate
        top: float
            Top (north) bounding coordinate
        precision: int, optional
            Number of decimal points of precision when computing inverse
            transform.
        kwargs: mapping
            For backwards compatibility: absorbs deprecated keyword args.

        Returns
        -------
        window: Window
        """
        if 'boundless' in kwargs:  # pragma: no branch
            warnings.warn("boundless keyword arg should not be used",
                          RasterioDeprecationWarning)

        transform = guard_transform(self.transform)
        return windows.from_bounds(
            left, bottom, right, top, transform=transform,
            height=self.height, width=self.width, precision=precision)
Exemple #11
0
def load_data(stand_path, chip_size=None, offsets=None):
    """Loads NAIP, LANDSAT, and stand delineation data"""
    dirname, cell_id, state_name, year, agency = parse_stand_path(stand_path)
    naip_path = get_naip_path(dirname, cell_id, state_name, year)
    landsat_path = get_landsat_path(dirname, cell_id, state_name, year)

    with rasterio.open(naip_path) as src:
        profile = src.profile
        height, width = src.shape
        if chip_size is not None:
            if offsets is not None:
                row_off, col_off = offsets
            else:
                row_off = np.random.randint(0, height - chip_size)
                col_off = np.random.randint(0, width - chip_size)
            window = windows.Window(col_off, row_off, chip_size, chip_size)
        else:
            window = None

        naip = reshape_as_image(src.read(window=window))
        if window is not None:
            trf = src.window_transform(window)
            bbox = src.window_bounds(window)
        else:
            trf = src.transform
            bbox = src.bounds

    with rasterio.open(landsat_path) as src:
        if chip_size is not None:
            window = windows.from_bounds(*bbox,
                                         transform=src.transform,
                                         height=chip_size,
                                         width=chip_size)
        else:
            window = windows.from_bounds(*bbox,
                                         transform=src.transform,
                                         height=height,
                                         width=width)
        landsat = ((reshape_as_image(
            np.stack([src.read(band + 1, window=window)
                      for band in range(4)])) / 3000).clip(0, 1) * 255).astype(
                          np.uint8)

    stands = gpd.read_file(stand_path)
    stands = gpd.clip(stands, box(*bbox))

    return naip, landsat, profile, trf, stands
Exemple #12
0
def test_window_float(path_rgb_byte_tif):
    """Test window float values"""
    with rasterio.open(path_rgb_byte_tif) as src:
        left, bottom, right, top = src.bounds
        dx, dy = src.res
        height = src.height
        width = src.width

        assert_window_almost_equals(from_bounds(
            left, top - 400, left + 400, top, src.transform,
            height, width), Window.from_slices((0, 400 / src.res[1]), (0, 400 / src.res[0])))
 def get_pixel_tree_cover(xy):
     arr = src.read(1,
                    window=windows.from_bounds(xy[0] - x_inc,
                                               xy[1] - y_inc,
                                               xy[0] + x_inc,
                                               xy[1] + y_inc,
                                               transform=src.transform))
     # ACHTUNG: gdalmerge might have messed with `src.nodata`
     # TODO: avoid UGLY HARDCODED zero below (inspect gdalmerge or
     # accept extra click CLI arg for tree nodata value)
     # return np.sum(arr != src.nodata) / arr.size
     return np.sum(arr != 0) / arr.size
Exemple #14
0
    def rect(self, fin, fout, bounds, mode='asc'):
        """crops a rectangle of Bounds, from a file. Returns a asc (grid) or geotiff

        Arguments:
            fin {string} -- input file
            fout {string} -- output file path
            bounds {bound class} -- a class with top,left,bottom,right attrs

        Keyword Arguments:
            mode {string} -- output file mode. can be 'asc' or 'geotiff' (default: {'asc'})

        Returns:
            [bool] -- Nothing, for now. True
        """

        with rasterio.open(fin, mode='r') as dataset:
            print(dataset.crs)
            print(dataset.bounds)

            #big
            lon_a, lat_a = self.wgs84_to_utm(bounds.left,
                                             bounds.top)  # lon, lat # TOPLEFT
            lon_b, lat_b = self.wgs84_to_utm(
                bounds.right, bounds.bottom)  # lon, lat #BOTTOMRIGHT

            print("NW:", lon_a, lat_a)
            print("SE:", lon_b, lat_b)
            # this return in row, col (Y,X)
            # py_a,px_a = dataset.index( lon_a, lat_a )
            # py_b,px_b = dataset.index( lon_b, lat_b )
            # width = px_b - px_a
            # height = py_b - py_a
            # print("A:",lon_a, lat_a,":", px_a, py_a)
            # print("B:",lon_b, lat_b,":", px_b, py_b)
            # print("width, height: ", width, height)

            bbox = from_bounds(lon_a, lat_b, lon_b, lat_a,
                               dataset.transform)  #left, bottom, right, top
            window = dataset.read(window=bbox)  # 1 -> 1 channel, nothing, all
            # this is the point (A) scaled, so we can locate coords inside.
            # Affine.scale(res_x, res_x) should be Affine.scale(res_x, res_y) but this generates
            # non square pixels, and insert dx,dy values, that are not supported by noone.
            # tested with GlobalMapper, and it works fine.
            # res_x = (lon_b - lon_a) / width
            # res_y = (lat_b - lat_a) / height
            #transform = Affine.translation(lon_a + res_x, lat_a + res_y) * Affine.scale(res_x, res_x)
            transform = dataset.window_transform(bbox)

            self.outputs[mode](fout, width, height, window, transform,
                               dataset.crs)
            self.add_prj(fout, dataset.crs)

        return True
Exemple #15
0
def test_window_float():
    """Test window float values"""
    with rasterio.open('tests/data/RGB.byte.tif') as src:
        left, bottom, right, top = src.bounds
        dx, dy = src.res
        height = src.height
        width = src.width

        assert_window_almost_equals(
            from_bounds(left, top - 400, left + 400, top, src.transform,
                        height, width),
            Window.from_slices((0, 400 / src.res[1]), (0, 400 / src.res[0])))
Exemple #16
0
def test_window_from_bounds(path_rgb_byte_tif):
    # TODO: break this test up.
    with rasterio.open(path_rgb_byte_tif) as src:
        left, bottom, right, top = src.bounds
        dx, dy = src.res
        height = src.height
        width = src.width

        assert_window_almost_equals(from_bounds(
            left + EPS, bottom + EPS, right - EPS, top - EPS, src.transform,
            height, width), Window.from_slices((0, height), (0, width)))

        assert_window_almost_equals(from_bounds(
            left, top - 2 * dy - EPS, left + 2 * dx - EPS, top, src.transform,
            height, width), Window.from_slices((0, 2), (0, 2)))

        # boundless
        assert_window_almost_equals(
            from_bounds(left - 2 * dx, top - 2 * dy, left + 2 * dx,
                        top + 2 * dy, src.transform, height=height,
                        width=width),
            Window.from_slices((-2, 2), (-2, 2), boundless=True, height=height,
                               width=width))
Exemple #17
0
    def read(self,
             band_name,
             window=None,
             bbox=None,
             crs=None):  # pragma: no cover
        """Read an asset given a band name.

        Notes:
            You must install the extra `geo` containing the `rasterio` and `Shapely` library
            in order to use this method:

                pip install stac.py[geo]

        :param band_name: Band name used in the asset
        :type band_name: str
        :param window: window crop
        :type window: raster.windows.Window
        :param bbox: The bounding box
        :type bbox: Union[str,Tuple[float],List[float],BaseGeometry]
        :param crs: The Coordinate Reference System
        :return: the asset as a numpy array
        :rtype: numpy.ndarray
        """
        import rasterio
        from rasterio.crs import CRS
        from rasterio.warp import transform
        from rasterio.windows import from_bounds

        # Check Authorization
        _ = Utils.safe_request(self.assets[band_name]['href'], method='head')

        source_crs = CRS.from_string('EPSG:4326')
        if crs:
            source_crs = CRS.from_string(crs)

        with rasterio.open(self.assets[band_name]['href']) as dataset:
            if bbox:
                bbox = Utils.build_bbox(bbox)

                w, s, e, n = bbox.bounds

                t = transform(source_crs, dataset.crs, [w, e], [s, n])
                window = from_bounds(t[0][0], t[1][0], t[0][1], t[1][1],
                                     dataset.transform)

            asset = dataset.read(1, window=window)

        return asset
Exemple #18
0
    def _get_rasterio_window(self, selector, dst_crs, transform):
        left_edge = self.LeftEdge
        right_edge = self.RightEdge

        transform_x, transform_y = warp.transform(
            self.ds.parameters["crs"],
            dst_crs,
            [left_edge[0], right_edge[0]],
            [left_edge[1], right_edge[1]],
            zs=None,
        )

        window = from_bounds(transform_x[0], transform_y[0], transform_x[1],
                             transform_y[1], transform)

        return window
def crop(src, geom, extend_box):
    left, bottom, right, top = geom.bounds
    window = from_bounds(left - extend_box,
                         bottom - extend_box,
                         right + extend_box,
                         top + extend_box,
                         transform=src.transform)
    masked_image = src.read(window=window)

    #Roll depth to channel last
    masked_image = np.rollaxis(masked_image, 0, 3)

    #Skip empty frames
    if masked_image.size == 0:
        raise ValueError("Empty Frame")

    return masked_image
Exemple #20
0
def test_baselevels_output_buffer(mp_tmpdir, baselevels_output_buffer):
    # it should not contain masked values within bounds
    # (171.46155, -87.27184, 174.45159, -84.31281)
    with mapchete.open(baselevels_output_buffer.dict) as mp:
        # process all
        mp.batch_process()
        # read tile 6/62/125.tif
        with rasterio.open(
            os.path.join(mp.config.output.output_params["path"], "6/62/125.tif")
        ) as src:
            window = windows.from_bounds(
                171.46155, -87.27184, 174.45159, -84.31281, transform=src.transform
            )
            subset = src.read(window=window, masked=True)
            print(subset.shape)
            assert not subset.mask.any()
            pass
Exemple #21
0
    def _get_rasterio_window(self, selector, dst_crs, transform):
        """
        Calculate position, width, and height for a rasterio window read.
        """
        left_edge, right_edge = self._get_selection_window(selector)

        transform_x, transform_y = warp.transform(
            self.ds.parameters["crs"],
            dst_crs,
            [left_edge[0], right_edge[0]],
            [left_edge[1], right_edge[1]],
            zs=None,
        )

        window = from_bounds(transform_x[0], transform_y[0], transform_x[1],
                             transform_y[1], transform)

        return window
Exemple #22
0
def merge(datasets, bounds=None, res=None, nodata=None, precision=7, indexes=None):
    """Copy valid pixels from input files to an output file.

    All files must have the same number of bands, data type, and
    coordinate reference system.

    Input files are merged in their listed order using the reverse
    painter's algorithm. If the output file exists, its values will be
    overwritten by input values.

    Geospatial bounds and resolution of a new output file in the
    units of the input file coordinate reference system may be provided
    and are otherwise taken from the first input file.

    Parameters
    ----------
    datasets: list of dataset objects opened in 'r' mode
        source datasets to be merged.
    bounds: tuple, optional
        Bounds of the output image (left, bottom, right, top).
        If not set, bounds are determined from bounds of input rasters.
    res: tuple, optional
        Output resolution in units of coordinate reference system. If not set,
        the resolution of the first raster is used. If a single value is passed,
        output pixels will be square.
    nodata: float, optional
        nodata value to use in output file. If not set, uses the nodata value
        in the first input raster.
    precision: float, optional
        Number of decimal points of precision when computing inverse transform.
    indexes : list of ints or a single int, optional
        bands to read and merge

    Returns
    -------
    tuple

        Two elements:

            dest: numpy ndarray
                Contents of all input rasters in single array

            out_transform: affine.Affine()
                Information for mapping pixel coordinates in `dest` to another
                coordinate system
    """
    first = datasets[0]
    first_res = first.res
    nodataval = first.nodatavals[0]
    dtype = first.dtypes[0]

    # Determine output band count
    if indexes is None:
        output_count = first.count
    elif isinstance(indexes, int):
        output_count = 1
    else:
        output_count = len(indexes)

    # Extent from option or extent of all inputs
    if bounds:
        dst_w, dst_s, dst_e, dst_n = bounds
    else:
        # scan input files
        xs = []
        ys = []
        for src in datasets:
            left, bottom, right, top = src.bounds
            xs.extend([left, right])
            ys.extend([bottom, top])
        dst_w, dst_s, dst_e, dst_n = min(xs), min(ys), max(xs), max(ys)

    logger.debug("Output bounds: %r", (dst_w, dst_s, dst_e, dst_n))
    output_transform = Affine.translation(dst_w, dst_n)
    logger.debug("Output transform, before scaling: %r", output_transform)

    # Resolution/pixel size
    if not res:
        res = first_res
    elif not np.iterable(res):
        res = (res, res)
    elif len(res) == 1:
        res = (res[0], res[0])
    output_transform *= Affine.scale(res[0], -res[1])
    logger.debug("Output transform, after scaling: %r", output_transform)

    # Compute output array shape. We guarantee it will cover the output
    # bounds completely
    output_width = int(math.ceil((dst_e - dst_w) / res[0]))
    output_height = int(math.ceil((dst_n - dst_s) / res[1]))

    # Adjust bounds to fit
    dst_e, dst_s = output_transform * (output_width, output_height)
    logger.debug("Output width: %d, height: %d", output_width, output_height)
    logger.debug("Adjusted bounds: %r", (dst_w, dst_s, dst_e, dst_n))

    # create destination array
    dest = np.zeros((output_count, output_height, output_width), dtype=dtype)

    if nodata is not None:
        nodataval = nodata
        logger.debug("Set nodataval: %r", nodataval)

    if nodataval is not None:
        # Only fill if the nodataval is within dtype's range
        inrange = False
        if np.dtype(dtype).kind in ('i', 'u'):
            info = np.iinfo(dtype)
            inrange = (info.min <= nodataval <= info.max)
        elif np.dtype(dtype).kind == 'f':
            info = np.finfo(dtype)
            if np.isnan(nodataval):
                inrange = True
            else:
                inrange = (info.min <= nodataval <= info.max)
        if inrange:
            dest.fill(nodataval)
        else:
            warnings.warn(
                "Input file's nodata value, %s, is beyond the valid "
                "range of its data type, %s. Consider overriding it "
                "using the --nodata option for better results." % (
                    nodataval, dtype))
    else:
        nodataval = 0

    for src in datasets:
        # Real World (tm) use of boundless reads.
        # This approach uses the maximum amount of memory to solve the
        # problem. Making it more efficient is a TODO.

        # 1. Compute spatial intersection of destination and source
        src_w, src_s, src_e, src_n = src.bounds

        int_w = src_w if src_w > dst_w else dst_w
        int_s = src_s if src_s > dst_s else dst_s
        int_e = src_e if src_e < dst_e else dst_e
        int_n = src_n if src_n < dst_n else dst_n

        # 2. Compute the source window
        src_window = windows.from_bounds(
            int_w, int_s, int_e, int_n, src.transform, precision=precision)
        logger.debug("Src %s window: %r", src.name, src_window)

        src_window = src_window.round_shape()

        # 3. Compute the destination window
        dst_window = windows.from_bounds(
            int_w, int_s, int_e, int_n, output_transform, precision=precision)

        # 4. Read data in source window into temp
        trows, tcols = (
            int(round(dst_window.height)), int(round(dst_window.width)))
        temp_shape = (output_count, trows, tcols)
        temp = src.read(out_shape=temp_shape, window=src_window,
                        boundless=False, masked=True, indexes=indexes)

        # 5. Copy elements of temp into dest
        roff, coff = (
            int(round(dst_window.row_off)), int(round(dst_window.col_off)))

        region = dest[:, roff:roff + trows, coff:coff + tcols]
        if np.isnan(nodataval):
            region_nodata = np.isnan(region)
            temp_nodata = np.isnan(temp)
        else:
            region_nodata = region == nodataval
            temp_nodata = temp.mask
        mask = np.logical_and(region_nodata, ~temp_nodata)
        np.copyto(region, temp, where=mask)

    return dest, output_transform
Exemple #23
0
def test_window_bounds_north_up():
    transform = Affine.translation(0.0, 10.0) * Affine.scale(1.0, -1.0) * Affine.identity()
    assert_window_almost_equals(
        from_bounds(0, 0, 10, 10, transform, 10, 10),
        Window(0, 0, 10, 10))
Exemple #24
0
def test_window_bounds_south_up():
    identity = Affine.identity()
    assert_window_almost_equals(
        from_bounds(0, 10, 10, 0, identity, 10, 10),
        Window(0, 0, 10, 10))