Пример #1
0
def from_bounds(left,
                bottom,
                right,
                top,
                transform,
                height=None,
                width=None,
                boundless=False,
                precision=6):
    """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
    transform : Affine
        Affine transform matrix
    height : int
        Number of rows
    width : int
        Number of columns
    boundless : boolean, optional
        If boundless is False, window is limited
        to extent of this dataset.
    precision : int, optional
        float precision

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

    window_start = rowcol(transform,
                          left,
                          top,
                          op=math.floor,
                          precision=precision)

    window_stop = rowcol(transform,
                         right,
                         bottom,
                         op=math.ceil,
                         precision=precision)

    window = tuple(zip(window_start, window_stop))

    if boundless:
        return window
    else:
        if None in (height, width):
            raise ValueError("Must supply height and width unless boundless")
        return crop(window, height, width)
Пример #2
0
def from_bounds(left, bottom, right, top, transform=None,
                height=None, width=None, precision=None):
    """Get the window corresponding to the bounding coordinates.

    Parameters
    ----------
    left, bottom, right, top: float
        Left (west), bottom (south), right (east), and top (north)
        bounding coordinates.
    transform: Affine
        Affine transform matrix.
    height, width: int
        Number of rows and columns of the window.
    precision: int, optional
        Number of decimal points of precision when computing inverse
        transform.

    Returns
    -------
    Window
        A new Window
    """
    row_start, col_start = rowcol(
        transform, left, top, op=float, precision=precision)

    row_stop, col_stop = rowcol(
        transform, right, bottom, op=float, precision=precision)

    return Window.from_slices(
        (row_start, row_stop), (col_start, col_stop), height=height,
        width=width, boundless=True)
Пример #3
0
def from_bounds(left, bottom, right, top, transform=None,
                height=None, width=None, precision=None):
    """Get the window corresponding to the bounding coordinates.

    Parameters
    ----------
    left, bottom, right, top: float
        Left (west), bottom (south), right (east), and top (north)
        bounding coordinates.
    transform: Affine
        Affine transform matrix.
    height, width: int
        Number of rows and columns of the window.
    precision: int, optional
        Number of decimal points of precision when computing inverse
        transform.

    Returns
    -------
    Window
        A new Window
    """
    row_start, col_start = rowcol(
        transform, left, top, op=float, precision=precision)

    row_stop, col_stop = rowcol(
        transform, right, bottom, op=float, precision=precision)

    return Window.from_slices(
        (row_start, row_stop), (col_start, col_stop), height=height,
        width=width, boundless=True)
Пример #4
0
def test_rowcol():
    with rasterio.open("tests/data/RGB.byte.tif", 'r') as src:
        aff = src.transform
        left, bottom, right, top = src.bounds
        assert rowcol(aff, left, top) == (0, 0)
        assert rowcol(aff, right, top) == (0, src.width)
        assert rowcol(aff, right, bottom) == (src.height, src.width)
        assert rowcol(aff, left, bottom) == (src.height, 0)
        assert rowcol(aff, 101985.0, 2826915.0) == (0, 0)
Пример #5
0
def from_bounds(left,
                bottom,
                right,
                top,
                transform=None,
                height=None,
                width=None,
                precision=None):
    """Get the window corresponding to the bounding coordinates.

    Parameters
    ----------
    left, bottom, right, top: float
        Left (west), bottom (south), right (east), and top (north)
        bounding coordinates.
    transform: Affine, required
        Affine transform matrix.
    height, width: int, required
        Number of rows and columns of the window.
    precision: int, optional
        Number of decimal points of precision when computing inverse
        transform.

    Returns
    -------
    Window
        A new Window.

    Raises
    ------
    WindowError
        If a window can't be calculated.

    """
    if not isinstance(transform, Affine):  # TODO: RPCs?
        raise WindowError(
            "A transform object is required to calculate the window")

    row_start, col_start = rowcol(transform,
                                  left,
                                  top,
                                  op=float,
                                  precision=precision)

    row_stop, col_stop = rowcol(transform,
                                right,
                                bottom,
                                op=float,
                                precision=precision)

    return Window.from_slices((row_start, row_stop), (col_start, col_stop),
                              height=height,
                              width=width,
                              boundless=True)
Пример #6
0
def discretize(p, t):
    if type(p) is Polygon:
        x, y = p.exterior.xy
        rc = rowcol(t, x, y)
        return Polygon(list(zip(rc[0], rc[1])))
    if type(p) is MultiPolygon:
        polygons = []
        for pp in p:
            x, y = pp.exterior.xy
            rc = rowcol(t, x, y)
            polygons.append(Polygon(list(zip(rc[0], rc[1]))))
        return MultiPolygon(polygons)
Пример #7
0
def from_bounds(left,
                bottom,
                right,
                top,
                transform,
                height=None,
                width=None,
                boundless=False,
                precision=6):
    """Get the window corresponding to the bounding coordinates.

    Parameters
    ----------
    left, bottom, right, top : float
        Left (west), bottom (south), right (east), and top (north)
        bounding coordinates.
    transform : Affine
        Affine transform matrix.
    height, width : int
        Number of rows and columns of the window.
    boundless : boolean, optional
        If True, the output window's size may exceed the given height
        and width.
    precision : int, optional
        Number of decimal points of precision when computing inverse
        transform.

    Returns
    -------
    Window
        A new Window
    """
    window_start = rowcol(transform,
                          left,
                          top,
                          op=math.floor,
                          precision=precision)

    window_stop = rowcol(transform,
                         right,
                         bottom,
                         op=math.ceil,
                         precision=precision)

    window = Window.from_ranges(*tuple(zip(window_start, window_stop)))

    if boundless:
        return window
    else:
        if None in (height, width):
            raise ValueError("Must supply height and width unless boundless")
        return crop(window, height, width)
Пример #8
0
def from_bounds(left,
                bottom,
                right,
                top,
                transform=None,
                height=None,
                width=None,
                precision=6,
                **kwargs):
    """Get the window corresponding to the bounding coordinates.

    Parameters
    ----------
    left, bottom, right, top: float
        Left (west), bottom (south), right (east), and top (north)
        bounding coordinates.
    transform: Affine
        Affine transform matrix.
    height, width: int
        Number of rows and columns of the window.
    precision: int, optional
        Number of decimal points of precision when computing inverse
        transform.
    kwargs: mapping
        Absorbs deprecated keyword args

    Returns
    -------
    Window
        A new Window
    """
    if 'boundless' in kwargs:
        warnings.warn("boundless keyword should not be used",
                      RasterioDeprecationWarning)

    row_start, col_start = rowcol(transform,
                                  left,
                                  top,
                                  op=float,
                                  precision=precision)

    row_stop, col_stop = rowcol(transform,
                                right,
                                bottom,
                                op=float,
                                precision=precision)

    return Window.from_slices((row_start, row_stop), (col_start, col_stop),
                              height=height,
                              width=width,
                              boundless=True)
Пример #9
0
def test_rowcol_gcps_rpcs(dataset, transform_attr, coords, expected):
    with rasterio.open(dataset, 'r') as src:
        transform = getattr(src, transform_attr)
        if transform_attr == 'gcps':
            transform = transform[0]
        for coord, truth in zip(coords, expected):
            assert rowcol(transform, *coord) == truth
Пример #10
0
def extract_training_data_over_centroids(centroid_shapefiles,
                                         image_stack,
                                         class_labels,
                                         image_meta,
                                         label_meta,
                                         save_directory,
                                         tile_size=224):
    assert (image_stack.shape[1] == class_labels.shape[0])
    assert (image_stack.shape[2] == class_labels.shape[1])

    x = []
    y = []
    for shapefile in centroid_shapefiles:
        shp = gpd.read_file(shapefile)
        shp = shp[shp.geometry.notnull()]
        crs = CRS(image_meta['crs'])
        shp = shp.to_crs(crs)
        features = get_features(shp)

        xs = [f['coordinates'][0] for f in features]
        ys = [f['coordinates'][1] for f in features]
        x.extend(xs)
        y.extend(ys)

    rows, cols = rowcol(image_meta['transform'], x, y)
    ts = tile_size // 2
    for x, y in zip(rows, cols):
        image_tile = image_stack[:, x - ts:x + ts, y - ts:y + ts]
        class_label_tile = class_labels[x - ts:x + ts, y - ts:y + ts]
        save_image_tile_and_mask(save_directory, image_tile, class_label_tile,
                                 image_meta, label_meta)
Пример #11
0
    def index(self, x, y, op=math.floor, precision=6):
        """
        Returns the (row, col) index of the pixel containing (x, y) given a
        coordinate reference system.

        Use an epsilon, magnitude determined by the precision parameter
        and sign determined by the op function:
            positive for floor, negative for ceil.

        Parameters
        ----------
        x : float
            x value in coordinate reference system
        y : float
            y value in coordinate reference system
        op : function, optional (default: math.floor)
            Function to convert fractional pixels to whole numbers (floor,
            ceiling, round)
        precision : int, optional (default: 6)
            Decimal places of precision in indexing, as in `round()`.

        Returns
        -------
        tuple
            (row index, col index)
        """
        return rowcol(self.transform, x, y, op=op, precision=precision)
Пример #12
0
    def load_image_data(self):
        all_files = os.listdir(self.base_dir)
        all_files = [fn for fn in all_files if fn.endswith(self.file_suffix)]
        gdf = gps.read_file(self.annotation_file)

        frame_infos = []
        total_annotations = 0
        for i, fn in enumerate(all_files):
            annotations = []
            image = rasterio.open(os.path.join(self.base_dir, fn))
            for _, row in gdf[gdf.image_idx == fn].iterrows():
                p = row['geometry']
                coord = list(p.coords[0])
                ann = rowcol(image.transform, coord[0], coord[1])
                if not np.isnan(row['KRONE_DM']):
                    tree_size = int(row['KRONE_DM'])
                else:
                    tree_size = 4
                # Convert from metres to pixels and convert to radius from diameter
                tree_size *= 2.5
                tree_size = min(tree_size, 60)
                # Is the annotation correctly initialized???
                annotations.append((ann[0], ann[1], int(tree_size)))
                #print((ann[0], ann[1], tree_size))
            frame_info = FrameInfo(self.base_dir, fn,
                                   (0, 0, image.shape[0], image.shape[1]),
                                   annotations)
            frame_infos.append(frame_info)
            total_annotations += len(annotations)
        return frame_infos
def coords2Array(a, x, y):
	"""
	* convert between coords and array position
	*  returns row,col (y,x) as expected by rasterio
	"""
	r, c = rowcol(a, x, y)
	return int(r), int(c)
Пример #14
0
    def index(self, x, y, op=math.floor, precision=6):
        """
        Returns the (row, col) index of the pixel containing (x, y) given a
        coordinate reference system.

        Use an epsilon, magnitude determined by the precision parameter
        and sign determined by the op function:
            positive for floor, negative for ceil.

        Parameters
        ----------
        x : float
            x value in coordinate reference system
        y : float
            y value in coordinate reference system
        op : function, optional (default: math.floor)
            Function to convert fractional pixels to whole numbers (floor,
            ceiling, round)
        precision : int, optional (default: 6)
            Decimal places of precision in indexing, as in `round()`.

        Returns
        -------
        tuple
            (row index, col index)
        """
        return rowcol(self.transform, x, y, op=op, precision=precision)
Пример #15
0
    def load_image_data(self):
        all_files = os.listdir(self.base_dir)
        all_files = [fn for fn in all_files if fn.endswith(self.file_suffix)]
        gdf = gps.read_file(self.annotation_file)

        frame_infos = []
        total_annotations = 0
        for i, fn in enumerate(all_files):
            annotations = []
            image = rasterio.open(os.path.join(self.base_dir, fn))
            for _, row in gdf[gdf.image_idx == fn].iterrows():
                p = row['geometry']
                coord = list(p.coords[0])
                ann = rowcol(image.transform, coord[0], coord[1])
                if not np.isnan(row['KRONE_DM']):
                    tree_size = int(row['KRONE_DM'])
                else:
                    tree_size = 10
                tree_size = min(20, max(tree_size, 60))
                annotations.append((ann[1], ann[0], tree_size))

            frame_info = FrameInfo(self.base_dir, fn,
                                   (0, 0, image.shape[0], image.shape[1]),
                                   annotations)
            frame_infos.append(frame_info)
            total_annotations += len(annotations)
        return frame_infos
Пример #16
0
def test_xy_rowcol_inverse():
    # TODO this is an ideal candiate for
    # property-based testing with hypothesis
    aff = Affine.identity()
    rows_cols = ([0, 0, 10, 10],
                 [0, 10, 0, 10])
    assert rows_cols == rowcol(aff, *xy(aff, *rows_cols))
Пример #17
0
def pixel_position(x: float, y: float, transform: Affine) -> list:
    """
    CONVERT SPATIAL COORDINATES TO PIXEL X AND Y

    :param transform:
    :param x:
    :param y:
    :return:
    """
    return rowcol(transform, x, y)
Пример #18
0
    def _get_window(self, idx: int, transform: Affine = None) -> Window:
        """Returns a Window in the given transformation with sides of
        self.feature_chip_size and with an upper left corner self.chip_xs[idx],
        self.chip_ys[idx]"""
        if transform is None:
            transform = self.input_transform

        row_off, col_off = rowcol(transform, self.chip_xs[idx],
                                  self.chip_ys[idx])

        return Window(col_off, row_off, self.feature_chip_size,
                      self.feature_chip_size)
Пример #19
0
def sample_gen(dataset, xy, indexes=None, masked=False):
    """Sample pixels from a dataset

    Parameters
    ----------
    dataset : rasterio Dataset
        Opened in "r" mode.
    xy : iterable
        Pairs of x, y coordinates in the dataset's reference system.
    indexes : int or list of int
        Indexes of dataset bands to sample.
    masked : bool, default: False
        Whether to mask samples that fall outside the extent of the
        dataset.

    Yields
    ------
    array
        A array of length equal to the number of specified indexes
        containing the dataset values for the bands corresponding to
        those indexes.

    """
    dt = dataset.transform
    read = dataset.read
    height = dataset.height
    width = dataset.width

    if indexes is None:
        indexes = dataset.indexes
    elif isinstance(indexes, int):
        indexes = [indexes]

    nodata = np.full(len(indexes), (dataset.nodata or 0),
                     dtype=dataset.dtypes[0])
    if masked:
        # Masks for masked arrays are inverted (False means valid)
        mask = [
            MaskFlags.all_valid not in dataset.mask_flag_enums[i - 1]
            for i in indexes
        ]
        nodata = np.ma.array(nodata, mask=mask)

    for pts in _grouper(xy, 256):
        pts = zip(*filter(None, pts))

        for row_off, col_off in zip(*rowcol(dt, *pts)):
            if row_off < 0 or col_off < 0 or row_off >= height or col_off >= width:
                yield nodata
            else:
                window = Window(col_off, row_off, 1, 1)
                data = read(indexes, window=window, masked=masked)
                yield data[:, 0, 0]
Пример #20
0
def create_cutline(
    src_dst: Union[DatasetReader, DatasetWriter, WarpedVRT],
    geometry: Dict,
    geometry_crs: CRS = None,
) -> str:
    """
    Create WKT Polygon Cutline for GDALWarpOptions.

    Ref: https://gdal.org/api/gdalwarp_cpp.html?highlight=vrt#_CPPv415GDALWarpOptions

    Args:
        src_dst (rasterio.io.DatasetReader or rasterio.io.DatasetWriter or rasterio.vrt.WarpedVRT): Rasterio dataset.
        geometry (dict): GeoJSON feature or GeoJSON geometry. By default the cordinates are considered to be in the dataset CRS. Use `geometry_crs` to set a specific CRS.
        geometry_crs (rasterio.crs.CRS, optional): Input geometry Coordinate Reference System
    Returns:
        str: WKT geometry in form of `POLYGON ((x y, x y, ...)))

    """
    if "geometry" in geometry:
        geometry = geometry["geometry"]

    if not is_valid_geom(geometry):
        raise RioTilerError("Invalid geometry")

    geom_type = geometry["type"]
    if geom_type not in ["Polygon", "MultiPolygon"]:
        raise RioTilerError(
            "Invalid geometry type: {geom_type}. Should be Polygon or MultiPolygon"
        )

    if geometry_crs:
        geometry = transform_geom(geometry_crs, src_dst.crs, geometry)

    polys = []
    geom = (
        [geometry["coordinates"]] if geom_type == "Polygon" else geometry["coordinates"]
    )
    for p in geom:
        xs, ys = zip(*coords(p))
        src_y, src_x = rowcol(src_dst.transform, xs, ys)
        src_x = [max(0, min(src_dst.width, x)) for x in src_x]
        src_y = [max(0, min(src_dst.height, y)) for y in src_y]
        poly = ", ".join([f"{x} {y}" for x, y in list(zip(src_x, src_y))])
        polys.append(f"(({poly}))")

    str_poly = ",".join(polys)

    return (
        f"POLYGON {str_poly}"
        if geom_type == "Polygon"
        else f"MULTIPOLYGON ({str_poly})"
    )
    def map_to_pixel(self, map_point):
        """Transform point from map to pixel-based coordinates.

        Args:
            map_point: (x, y) tuple in map coordinates

        Returns:
            (x, y) tuple in pixel coordinates
        """
        image_point = self.map2image.transform(*map_point)
        pixel_point = rowcol(self.transform, image_point[0], image_point[1])
        pixel_point = (pixel_point[1], pixel_point[0])
        return pixel_point
Пример #22
0
def from_bounds(left, bottom, right, top, transform,
                height=None, width=None, boundless=False, precision=6):
    """Get the window corresponding to the bounding coordinates.

    Parameters
    ----------
    left, bottom, right, top : float
        Left (west), bottom (south), right (east), and top (north)
        bounding coordinates.
    transform : Affine
        Affine transform matrix.
    height, width : int
        Number of rows and columns of the window.
    boundless : boolean, optional
        If True, the output window's size may exceed the given height
        and width.
    precision : int, optional
        Number of decimal points of precision when computing inverse
        transform.

    Returns
    -------
    Window
        A new Window
    """
    window_start = rowcol(
        transform, left, top, op=math.floor, precision=precision)

    window_stop = rowcol(
        transform, right, bottom, op=math.ceil, precision=precision)

    window = Window.from_ranges(*tuple(zip(window_start, window_stop)))

    if boundless:
        return window
    else:
        if None in (height, width):
            raise ValueError("Must supply height and width unless boundless")
        return crop(window, height, width)
Пример #23
0
def elevation_adjustment(coords, elevation_array, transformation_matrix):
    ''''
    Function to return adjustment time
    coords - Must be the coordinates in [x, y]
    elevation_array - Must be a numpy array containing the elevation data
    transformation_matrix - The transformation matrix output.
    Code adapted from a function by Mahmoud Abdelrazek, 2019 - https://github.com/razekmh
    ''''
    rise = 0  # Initialise rise to zero
    try:
        for i, point in enumerate(coords):  # Extract coordinates
            x_coord, y_coord = point
            if i == 0:  # First value
                back_height = elevation_array[rowcol(transformation_matrix, x_coord, y_coord)]  # Get elevation
            else:
                fore_height = elevation_array[rowcol(transformation_matrix, x_coord, y_coord)]  # Get elevation
                if fore_height > back_height:  # Ignore negative elevation changes
                    rise += fore_height - back_height  # Add each posotive changes to the rise
                back_height = fore_height
        elevation_adjustment = rise * 0.1  # To get the adjustment value in minutes.
        return elevation_adjustment
    except IOError:
        print("Unable to perform this operation")
Пример #24
0
 def get_window_from_xy(self, xy):
     """Get the window index given a coordinate (raster CRS)."""
     a_transform = self._get_template_for_given_resolution(res=self.dst_res, return_="meta")["transform"]
     row, col = transform.rowcol(a_transform, xy[0], xy[1])
     ij_containing_xy = None
     for ji, win in enumerate(self.windows):
         (row_start, row_end), (col_start, col_end) = rasterio.windows.toranges(win)
         # print(row, col, row_start, row_end, col_start, col_end)
         if ((col >= col_start) & (col < col_end)) & ((row >= row_start) & (row < row_end)):
             ij_containing_xy = ji
             break
     if ij_containing_xy is None:
         raise ValueError("The given 'xy' value is not contained in any window.")
     return ij_containing_xy
Пример #25
0
def from_bounds(left, bottom, right, top, transform=None,
                height=None, width=None, precision=6, **kwargs):
    """Get the window corresponding to the bounding coordinates.

    Parameters
    ----------
    left, bottom, right, top: float
        Left (west), bottom (south), right (east), and top (north)
        bounding coordinates.
    transform: Affine
        Affine transform matrix.
    height, width: int
        Number of rows and columns of the window.
    precision: int, optional
        Number of decimal points of precision when computing inverse
        transform.
    kwargs: mapping
        Absorbs deprecated keyword args

    Returns
    -------
    Window
        A new Window
    """
    if 'boundless' in kwargs:
        warnings.warn("boundless keyword should not be used",
                      RasterioDeprecationWarning)

    row_start, col_start = rowcol(
        transform, left, top, op=float, precision=precision)

    row_stop, col_stop = rowcol(
        transform, right, bottom, op=float, precision=precision)

    return Window.from_slices(
        (row_start, row_stop), (col_start, col_stop), height=height,
        width=width, boundless=True)
Пример #26
0
def test_rowcol():
    with rasterio.open("tests/data/RGB.byte.tif", 'r') as src:
        aff = src.transform
        left, bottom, right, top = src.bounds
        assert rowcol(aff, left, top) == (0, 0)
        assert rowcol(aff, right, top) == (0, src.width)
        assert rowcol(aff, right, bottom) == (src.height, src.width)
        assert rowcol(aff, left, bottom) == (src.height, 0)
        assert rowcol(aff, 101985.0, 2826915.0) == (0, 0)
        assert rowcol(aff, 101985.0 + 400.0, 2826915.0) == (0, 1)
Пример #27
0
def create_cutline(src_dst: DataSet,
                   geometry: Dict,
                   geometry_crs: CRS = None) -> str:
    """
    Create WKT Polygon Cutline for GDALWarpOptions.

    Ref: https://gdal.org/api/gdalwarp_cpp.html?highlight=vrt#_CPPv415GDALWarpOptions

    Attributes
    ----------
    src_dst: rasterio.io.DatasetReader
        rasterio.io.DatasetReader object
    geometry: dict
        GeoJSON feature or GeoJSON geometry
    geometry_crs: CRS or str, optional
            Specify bounds coordinate reference system, default is same as input dataset.

    Returns
    -------
    wkt: str
        Cutline WKT geometry in form of `POLYGON ((x y, x y, ...)))

    """
    if "geometry" in geometry:
        geometry = geometry["geometry"]

    geom_type = geometry["type"]
    if not geom_type == "Polygon":
        raise RioTilerError(
            "Invalid geometry type: {geom_type}. Should be Polygon")

    if geometry_crs:
        geometry = transform_geom(geometry_crs, src_dst.crs, geometry)

    xs, ys = zip(*coords(geometry))
    src_y, src_x = rowcol(src_dst.transform, xs, ys)

    src_x = [max(0, min(src_dst.width, x)) for x in src_x]
    src_y = [max(0, min(src_dst.height, y)) for y in src_y]

    poly = ", ".join([f"{x} {y}" for x, y in list(zip(src_x, src_y))])
    return f"POLYGON (({poly}))"
Пример #28
0
def cell_series(rast_dir, lon, lat):
    """
        get the values of a particular latitude longitude in a time series of rasters
    """

    cell_series = []

    with rasterio.open(rast_dir + '/' + os.listdir(rast_dir)[0]) as data:

        aff = data.transform

        row, col = rowcol(aff, lon, lat)

        for fname in os.listdir(rast_dir):
            with rasterio.open(rast_dir + '/' + fname) as rast:
                vals = rast.read()
                val_at_coord = vals[0, row, col]
                date_str = fname[9:-4]
                date = dt.datetime.strptime(date_str, '%Y%m%d_%H%M%S')
                cell_series.append((date, val_at_coord))

    return (cell_series)
Пример #29
0
def geometry_window(
    dataset,
    shapes,
    pad_x=0,
    pad_y=0,
    north_up=None,
    rotated=None,
    pixel_precision=None,
    boundless=False,
):
    """Calculate the window within the raster that fits the bounds of
    the geometry plus optional padding.  The window is the outermost
    pixel indices that contain the geometry (floor of offsets, ceiling
    of width and height).

    If shapes do not overlap raster, a WindowError is raised.

    Parameters
    ----------
    dataset : dataset object opened in 'r' mode
        Raster for which the mask will be created.
    shapes : iterable over geometries.
        A geometry is a GeoJSON-like object or implements the geo
        interface.  Must be in same coordinate system as dataset.
    pad_x : float
        Amount of padding (as fraction of raster's x pixel size) to add
        to left and right side of bounds.
    pad_y : float
        Amount of padding (as fraction of raster's y pixel size) to add
        to top and bottom of bounds.
    north_up : optional
        This parameter is ignored since version 1.2.1. A deprecation
        warning will be emitted in 1.3.0.
    rotated : optional
        This parameter is ignored since version 1.2.1. A deprecation
        warning will be emitted in 1.3.0.
    pixel_precision : int or float, optional
        Number of places of rounding precision or absolute precision for
        evaluating bounds of shapes.
    boundless : bool, optional
        Whether to allow a boundless window or not.

    Returns
    -------
    rasterio.windows.Window

    """

    if pad_x:
        pad_x = abs(pad_x * dataset.res[0])

    if pad_y:
        pad_y = abs(pad_y * dataset.res[1])

    all_bounds = [bounds(shape) for shape in shapes]

    xs = [
        x for (left, bottom, right, top) in all_bounds
        for x in (left - pad_x, right + pad_x, right + pad_x, left - pad_x)
    ]
    ys = [
        y for (left, bottom, right, top) in all_bounds
        for y in (top + pad_y, top + pad_y, bottom - pad_x, bottom - pad_x)
    ]

    rows1, cols1 = rowcol(dataset.transform,
                          xs,
                          ys,
                          op=math.floor,
                          precision=pixel_precision)

    if isinstance(rows1, (int, float)):
        rows1 = [rows1]
    if isinstance(cols1, (int, float)):
        cols1 = [cols1]

    rows2, cols2 = rowcol(dataset.transform,
                          xs,
                          ys,
                          op=math.ceil,
                          precision=pixel_precision)

    if isinstance(rows2, (int, float)):
        rows2 = [rows2]
    if isinstance(cols2, (int, float)):
        cols2 = [cols2]

    rows = rows1 + rows2
    cols = cols1 + cols2

    row_start, row_stop = min(rows), max(rows)
    col_start, col_stop = min(cols), max(cols)

    window = Window(
        col_off=col_start,
        row_off=row_start,
        width=max(col_stop - col_start, 0.0),
        height=max(row_stop - row_start, 0.0),
    )

    # Make sure that window overlaps raster
    raster_window = Window(0, 0, dataset.width, dataset.height)
    if not boundless:
        window = window.intersection(raster_window)

    return window
Пример #30
0
def test_xy_rowcol_inverse():
    # TODO this is an ideal candiate for
    # property-based testing with hypothesis
    aff = Affine.identity()
    rows_cols = ([0, 0, 10, 10], [0, 10, 0, 10])
    assert rows_cols == rowcol(aff, *xy(aff, *rows_cols))
Пример #31
0
def from_bounds(left,
                bottom,
                right,
                top,
                transform=None,
                height=None,
                width=None,
                precision=None):
    """Get the window corresponding to the bounding coordinates.

    Parameters
    ----------
    left: float, required
        Left (west) bounding coordinates
    bottom: float, required
        Bottom (south) bounding coordinates
    right: float, required
        Right (east) bounding coordinates
    top: float, required
        Top (north) bounding coordinates
    transform: Affine, required
        Affine transform matrix.
    precision, height, width: int, optional
        These parameters are unused, deprecated in rasterio 1.3.0, and
        will be removed in version 2.0.0.

    Returns
    -------
    Window
        A new Window.

    Raises
    ------
    WindowError
        If a window can't be calculated.

    """
    if height is not None or width is not None or precision is not None:
        warnings.warn(
            "The height, width, and precision parameters are unused, deprecated, and will be removed in 2.0.0.",
            RasterioDeprecationWarning,
        )

    if not isinstance(transform, Affine):  # TODO: RPCs?
        raise WindowError(
            "A transform object is required to calculate the window")
    if (right - left) / transform.a < 0:
        raise WindowError("Bounds and transform are inconsistent")
    if (bottom - top) / transform.e < 0:
        raise WindowError("Bounds and transform are inconsistent")

    rows, cols = rowcol(
        transform,
        [left, right, right, left],
        [top, top, bottom, bottom],
        op=float,
    )
    row_start, row_stop = min(rows), max(rows)
    col_start, col_stop = min(cols), max(cols)

    return Window(
        col_off=col_start,
        row_off=row_start,
        width=max(col_stop - col_start, 0.0),
        height=max(row_stop - row_start, 0.0),
    )
Пример #32
0
def merge_rgba_tool(sources, outtif, bounds=None, res=None, precision=7,
                    creation_options={}):
    """A windowed, top-down approach to merging.
    For each block window, it loops through the sources,
    reads the corresponding source window until the block
    is filled with data or we run out of sources.

    Uses more disk IO but is faster* and
    consumes significantly less memory

    * The read efficiencies comes from using
    RGBA tifs where we can assume band 4 is the sole
    determinant of nodata. This avoids the use of
    expensive masked reads but, of course, limits
    what data can used. Hence merge_rgba.
    """
    first = sources[0]
    first_res = first.res
    dtype = first.dtypes[0]
    profile = first.profile

    # Extent from option or extent of all inputs.
    if bounds:
        dst_w, dst_s, dst_e, dst_n = bounds
    else:
        # scan input files.
        # while we're at it, validate assumptions about inputs
        xs = []
        ys = []
        for src in sources:
            left, bottom, right, top = src.bounds
            xs.extend([left, right])
            ys.extend([bottom, top])
            if src.profile['count'] != 4:  # TODO, how to test for alpha?
                raise ValueError("Inputs must be 4-band RGBA rasters")
        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))

    profile['transform'] = output_transform
    profile['height'] = output_height
    profile['width'] = output_width

    profile['nodata'] = None  # rely on alpha mask

    # Creation opts
    profile.update(creation_options)

    # create destination file
    with rasterio.open(outtif, 'w', **profile) as dstrast:

        for idx, dst_window in dstrast.block_windows():

            left, bottom, right, top = dstrast.window_bounds(dst_window)
            blocksize = ((dst_window[0][1] - dst_window[0][0]) *
                         (dst_window[1][1] - dst_window[1][0]))

            # initialize array destined for the block
            dst_count = first.count
            dst_rows, dst_cols = tuple(b - a for a, b in dst_window)
            dst_shape = (dst_count, dst_rows, dst_cols)
            logger.debug("Temp shape: %r", dst_shape)
            dstarr = np.zeros(dst_shape, dtype=dtype)

            # Read up srcs until
            # a. everything is data; i.e. no nodata
            # b. no sources left
            for src in sources:
                # The full_cover behavior is problematic here as it includes
                # extra pixels along the bottom right when the sources are
                # slightly misaligned
                #
                # src_window = get_window(left, bottom, right, top,
                #                         src.transform, precision=precision)
                #
                # With rio merge this just adds an extra row, but when the
                # imprecision occurs at each block, you get artifacts

                # Alternative, custom get_window using rounding
                window_start = rowcol(
                    src.transform, left, top, op=round, precision=precision)
                window_stop = rowcol(
                    src.transform, right, bottom, op=round, precision=precision)
                src_window = tuple(zip(window_start, window_stop))

                temp = np.zeros(dst_shape, dtype=dtype)
                temp = src.read(out=temp, window=src_window,
                                boundless=True, masked=False)

                # pixels without data yet are available to write
                write_region = np.logical_and(
                    (dstarr[3] == 0),  # 0 is nodata
                    (temp[3] != 0))
                np.copyto(dstarr, temp, where=write_region)

                # check if dest has any nodata pixels available
                if np.count_nonzero(dstarr[3]) == blocksize:
                    break

            dstrast.write(dstarr, window=dst_window)

    return output_transform
Пример #33
0
def merge(input_ortho_and_ortho_cuts, output_orthophoto, orthophoto_vars={}):
    """
    Based on https://github.com/mapbox/rio-merge-rgba/
    Merge orthophotos around cutlines using a blend buffer.
    """
    inputs = []
    bounds = None
    precision = 7

    for o, c in input_ortho_and_ortho_cuts:
        if not io.file_exists(o):
            log.ODM_WARNING(
                "%s does not exist. Will skip from merged orthophoto." % o)
            continue
        if not io.file_exists(c):
            log.ODM_WARNING(
                "%s does not exist. Will skip from merged orthophoto." % c)
            continue
        inputs.append((o, c))

    if len(inputs) == 0:
        log.ODM_WARNING("No input orthophotos, skipping merge.")
        return

    with rasterio.open(inputs[0][0]) as first:
        res = first.res
        dtype = first.dtypes[0]
        profile = first.profile
        num_bands = first.meta['count'] - 1  # minus alpha
        colorinterp = first.colorinterp

    log.ODM_INFO("%s valid orthophoto rasters to merge" % len(inputs))
    sources = [(rasterio.open(o), rasterio.open(c)) for o, c in inputs]

    # scan input files.
    # while we're at it, validate assumptions about inputs
    xs = []
    ys = []
    for src, _ in sources:
        left, bottom, right, top = src.bounds
        xs.extend([left, right])
        ys.extend([bottom, top])
        if src.profile["count"] < 4:
            raise ValueError("Inputs must be at least 4-band rasters")
    dst_w, dst_s, dst_e, dst_n = min(xs), min(ys), max(xs), max(ys)
    log.ODM_INFO("Output bounds: %r %r %r %r" % (dst_w, dst_s, dst_e, dst_n))

    output_transform = Affine.translation(dst_w, dst_n)
    output_transform *= Affine.scale(res[0], -res[1])

    # 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)
    log.ODM_INFO("Output width: %d, height: %d" %
                 (output_width, output_height))
    log.ODM_INFO("Adjusted bounds: %r %r %r %r" % (dst_w, dst_s, dst_e, dst_n))

    profile["transform"] = output_transform
    profile["height"] = output_height
    profile["width"] = output_width
    profile["tiled"] = orthophoto_vars.get('TILED', 'YES') == 'YES'
    profile["blockxsize"] = orthophoto_vars.get('BLOCKXSIZE', 512)
    profile["blockysize"] = orthophoto_vars.get('BLOCKYSIZE', 512)
    profile["compress"] = orthophoto_vars.get('COMPRESS', 'LZW')
    profile["predictor"] = orthophoto_vars.get('PREDICTOR', '2')
    profile["bigtiff"] = orthophoto_vars.get('BIGTIFF', 'IF_SAFER')
    profile.update()

    # create destination file
    with rasterio.open(output_orthophoto, "w", **profile) as dstrast:
        dstrast.colorinterp = colorinterp
        for idx, dst_window in dstrast.block_windows():
            left, bottom, right, top = dstrast.window_bounds(dst_window)

            blocksize = dst_window.width
            dst_rows, dst_cols = (dst_window.height, dst_window.width)

            # initialize array destined for the block
            dst_count = first.count
            dst_shape = (dst_count, dst_rows, dst_cols)

            dstarr = np.zeros(dst_shape, dtype=dtype)

            # First pass, write all rasters naively without blending
            for src, _ in sources:
                src_window = tuple(
                    zip(
                        rowcol(src.transform,
                               left,
                               top,
                               op=round,
                               precision=precision),
                        rowcol(src.transform,
                               right,
                               bottom,
                               op=round,
                               precision=precision)))

                temp = np.zeros(dst_shape, dtype=dtype)
                temp = src.read(out=temp,
                                window=src_window,
                                boundless=True,
                                masked=False)

                # pixels without data yet are available to write
                write_region = np.logical_and(
                    (dstarr[-1] == 0),
                    (temp[-1] != 0)  # 0 is nodata
                )
                np.copyto(dstarr, temp, where=write_region)

                # check if dest has any nodata pixels available
                if np.count_nonzero(dstarr[-1]) == blocksize:
                    break

            # Second pass, write all feathered rasters
            # blending the edges
            for src, _ in sources:
                src_window = tuple(
                    zip(
                        rowcol(src.transform,
                               left,
                               top,
                               op=round,
                               precision=precision),
                        rowcol(src.transform,
                               right,
                               bottom,
                               op=round,
                               precision=precision)))

                temp = np.zeros(dst_shape, dtype=dtype)
                temp = src.read(out=temp,
                                window=src_window,
                                boundless=True,
                                masked=False)

                where = temp[-1] != 0
                for b in range(0, num_bands):
                    blended = temp[-1] / 255.0 * temp[b] + (
                        1 - temp[-1] / 255.0) * dstarr[b]
                    np.copyto(dstarr[b],
                              blended,
                              casting='unsafe',
                              where=where)
                dstarr[-1][where] = 255.0

                # check if dest has any nodata pixels available
                if np.count_nonzero(dstarr[-1]) == blocksize:
                    break

            # Third pass, write cut rasters
            # blending the cutlines
            for _, cut in sources:
                src_window = tuple(
                    zip(
                        rowcol(cut.transform,
                               left,
                               top,
                               op=round,
                               precision=precision),
                        rowcol(cut.transform,
                               right,
                               bottom,
                               op=round,
                               precision=precision)))

                temp = np.zeros(dst_shape, dtype=dtype)
                temp = cut.read(out=temp,
                                window=src_window,
                                boundless=True,
                                masked=False)

                # For each band, average alpha values between
                # destination raster and cut raster
                for b in range(0, num_bands):
                    blended = temp[-1] / 255.0 * temp[b] + (
                        1 - temp[-1] / 255.0) * dstarr[b]
                    np.copyto(dstarr[b],
                              blended,
                              casting='unsafe',
                              where=temp[-1] != 0)

            dstrast.write(dstarr, window=dst_window)

    return output_orthophoto
Пример #34
0
 def extent_to_windows(self, extent, actual_transform):
     window_min = transform.rowcol(actual_transform, extent['xmin'],
                                   extent['ymin'])
     window_max = transform.rowcol(actual_transform, extent['xmax'],
                                   extent['ymax'])
     return self.window_transform(window_min, window_max)
Пример #35
0
def from_bounds(
    left, bottom, right, top, transform=None, height=None, width=None, precision=None
):
    """Get the window corresponding to the bounding coordinates.

    Parameters
    ----------
    left: float, required
        Left (west) bounding coordinates
    bottom: float, required
        Bottom (south) bounding coordinates
    right: float, required
        Right (east) bounding coordinates
    top: float, required
        Top (north) bounding coordinates
    transform: Affine, required
        Affine transform matrix.
    height: int, required
        Number of rows of the window.
    width: int, required
        Number of columns of the window.
    precision: int or float, optional
        An integer number of decimal points of precision when computing
        inverse transform, or an absolute float precision.

    Returns
    -------
    Window
        A new Window.

    Raises
    ------
    WindowError
        If a window can't be calculated.

    """
    if not isinstance(transform, Affine):  # TODO: RPCs?
        raise WindowError("A transform object is required to calculate the window")

    if (right - left) / transform.a < 0:
        raise WindowError("Bounds and transform are inconsistent")

    if (bottom - top) / transform.e < 0:
        raise WindowError("Bounds and transform are inconsistent")

    rows, cols = rowcol(
        transform,
        [left, right, right, left],
        [top, top, bottom, bottom],
        op=float,
        precision=precision,
    )
    row_start, row_stop = min(rows), max(rows)
    col_start, col_stop = min(cols), max(cols)

    return Window(
        col_off=col_start,
        row_off=row_start,
        width=max(col_stop - col_start, 0.0),
        height=max(row_stop - row_start, 0.0),
    )
Пример #36
0
def cmip(
    store='az',
    df=None,
    tlim=None,
    model=None,
    scenario=None,
    coarsen=None,
    variables=['ppt', 'tmean'],
    mask=None,
    member=None,
    method='bias-corrected',
    sampling='annual',
    historical=False,
    remove_nans=False,
):

    with warnings.catch_warnings():
        warnings.simplefilter('ignore', category=ResourceWarning)
        warnings.simplefilter('ignore', category=FutureWarning)
        warnings.simplefilter('ignore', category=RuntimeWarning)

        if scenario is None:
            raise ValueError('must specify scenario')
        if model is None:
            raise ValueError('must specify model')

        path = setup.loading(store)

        prefix = f'cmip6/{method}/conus/4000m/{sampling}/{model}.{scenario}.{member}.zarr'

        if store == 'az':
            mapper = zarr.storage.ABSStore('carbonplan-downscaling',
                                           prefix=prefix,
                                           account_name='carbonplan')
        else:
            mapper = fsspec.get_mapper(
                (path / 'carbonplan-downscaling' / prefix).as_uri())

        ds = xr.open_zarr(mapper, consolidated=True)

        if historical:
            prefix = f'cmip6/{method}/conus/4000m/{sampling}/{model}.historical.{member}.zarr'

            if store == 'az':
                mapper = zarr.storage.ABSStore('carbonplan-downscaling',
                                               prefix=prefix,
                                               account_name='carbonplan')
            else:
                mapper = fsspec.get_mapper(
                    (path / 'carbonplan-downscaling' / prefix).as_uri())

            ds_historical = xr.open_zarr(mapper, consolidated=True)

            ds = xr.concat([ds_historical, ds], 'time')

        ds['cwd'] = ds['def']
        ds['pdsi'] = ds['pdsi'].clip(-16, 16)

        X = xr.Dataset()
        keys = variables

        for key in keys:
            X[key] = ds[key]

        if tlim is not None:
            tlim = list(map(str, tlim))
            X = X.sel(time=slice(*tlim))

        if mask is not None:
            vals = mask.values
            vals[vals == 0] = np.NaN
            X = X * vals

        if coarsen:
            X_coarse = xr.Dataset()
            for key in keys:
                X_coarse[key] = X[key].coarsen(x=coarsen,
                                               y=coarsen,
                                               boundary='trim').mean()
            X = X_coarse

        if df is not None:
            t = Affine(*utils.albers_conus_transform(4000))
            p1 = Proj(utils.albers_conus_crs())
            p2 = Proj(proj='latlong', datum='WGS84')
            x, y = transform(p2, p1, df['lon'].values, df['lat'].values)
            rc = rowcol(t, x, y)
            ind_r = xr.DataArray(rc[0], dims=['c'])
            ind_c = xr.DataArray(rc[1], dims=['c'])

            base = X[keys].isel(y=ind_r, x=ind_c).load()
            for key in keys:
                df[key + '_mean'] = base[key].mean('time').values
                df[key + '_min'] = base[key].min('time').values
                df[key + '_max'] = base[key].max('time').values
            if remove_nans:
                for key in keys:
                    df = df[~np.isnan(df[key + '_mean'])]
            df = df.reset_index(drop=True)
            return df

        X = X.drop(['x', 'y'])
        X.load(retries=10)
        return X
Пример #37
0
def get_window(extent: tuple, transform: Affine) -> (tuple, tuple):
    row_start, col_start = rowcol(transform, extent[0], extent[-1], op=int)

    row_stop, col_stop = rowcol(transform, extent[2], extent[1], op=int)

    return (row_start, row_stop), (col_start, col_stop)