Пример #1
0
def absolute_window(base_window, rel_window, strict=True):
    window = Window(
        col_off=rel_window.col_off - base_window.col_off,
        row_off=rel_window.row_off - base_window.row_off,
        width=rel_window.width,
        height=rel_window.height,
        )

    return window.intersection(base_window) if strict else window
Пример #2
0
def relative_window(base_window, abs_window, strict=True):
    window = Window(
        col_off=base_window.col_off + abs_window.col_off,
        row_off=base_window.row_off + abs_window.row_off,
        width=abs_window.width,
        height=abs_window.height,
        )

    return window.intersection(base_window) if strict else window
Пример #3
0
def get_chip_windows(
    meta_raster,
    chip_width: int = 256,
    chip_height: int = 256,
    skip_partial_chips: bool = False,
) -> Generator[Tuple[Window, Polygon, affine.Affine], any, None]:
    """Generator for rasterio windows of specified pixel size to iterate over an image in chips.

    Chips are created row wise, from top to bottom of the raster.

    Args:
        meta_raster: rasterio src.meta or src.profile
        chip_width: Desired pixel width.
        chip_height: Desired pixel height.
        skip_partial_chips: Skip image chips at the edge of the raster that do not result in a full size chip.

    Returns : Yields tuple of rasterio window, Polygon and transform.

    """

    raster_width, raster_height = meta_raster["width"], meta_raster["height"]
    big_window = Window(col_off=0,
                        row_off=0,
                        width=raster_width,
                        height=raster_height)

    col_row_offsets = itertools.product(range(0, raster_width, chip_width),
                                        range(0, raster_height, chip_height))

    for col_off, row_off in col_row_offsets:

        chip_window = Window(col_off=col_off,
                             row_off=row_off,
                             width=chip_width,
                             height=chip_height)

        if skip_partial_chips:
            if (row_off + chip_height > raster_height
                    or col_off + chip_width > raster_width):
                continue

        chip_window = chip_window.intersection(big_window)
        chip_transform = rasterio.windows.transform(chip_window,
                                                    meta_raster["transform"])
        chip_bounds = rasterio.windows.bounds(
            chip_window,
            meta_raster["transform"])  # Use the transform of the full
        #  raster here!
        chip_poly = shapely.geometry.box(*chip_bounds, ccw=False)

        yield (chip_window, chip_poly, chip_transform)
Пример #4
0
def get_chip_windows(
    raster_width: int,
    raster_height: int,
    raster_transform,
    chip_width: int = 256,
    chip_height: int = 256,
    skip_partial_chips: bool = False,
) -> Generator[Tuple[Window, affine.Affine, Polygon], any, None]:
    """Generator for rasterio windows of specified pixel size to iterate over an image in chips.

    Chips are created row wise, from top to bottom of the raster.

    Args:
        raster_width: rasterio meta['width']
        raster_height: rasterio meta['height']
        raster_transform: rasterio meta['transform']
        chip_width: Desired pixel width.
        chip_height: Desired pixel height.
        skip_partial_chips: Skip image chips at the edge of the raster that do not result in a full size chip.

    Returns :
        Yields tuple of rasterio chip window, chip transform and chip polygon.
    """
    col_row_offsets = itertools.product(range(0, raster_width, chip_width),
                                        range(0, raster_height, chip_height))
    raster_window = Window(col_off=0,
                           row_off=0,
                           width=raster_width,
                           height=raster_height)

    for col_off, row_off in col_row_offsets:
        chip_window = Window(col_off=col_off,
                             row_off=row_off,
                             width=chip_width,
                             height=chip_height)

        if skip_partial_chips:
            if row_off + chip_height > raster_height or col_off + chip_width > raster_width:
                continue

        chip_window = chip_window.intersection(raster_window)
        chip_transform = rasterio.windows.transform(chip_window,
                                                    raster_transform)
        chip_bounds = rasterio.windows.bounds(
            chip_window, raster_transform)  # Uses transform of full raster.
        chip_poly = shapely.geometry.box(*chip_bounds, ccw=False)

        yield (chip_window, chip_transform, chip_poly)
Пример #5
0
def make_windows_iterator(image_size, window_size, valid_pixels,
                          validity_threshold):
    """Iterates of patch windows corresponding to valid pixel positions

    Args:
        image_size (tuple[int]): (height, width) in pixels
        window_size (tuple[int]): (window_height, window_width) in pixels
        valid_pixels (np.ndarray): (height, width) boolean array
        validity_threshold (float): percentage of valid pixels in a window to be considered valid

    Yields:
        type: rasterio.windows.Window

    """
    # Make full raster window object
    height, width = image_size
    full_image_window = Window(col_off=0,
                               row_off=0,
                               width=width,
                               height=height)

    # Create offsets range to iterate on
    window_height, window_width = window_size
    col_row_offsets = product(range(0, width, window_width),
                              range(0, height, window_height))

    for window_idx, (col_offset, row_offset) in enumerate(col_row_offsets):
        # Create window instance
        window = Window(col_off=col_offset,
                        row_off=row_offset,
                        width=window_width,
                        height=window_height)

        # Verify the window is valid
        window_valid_pixels = valid_pixels[window.toslices()]
        is_valid = window_valid_pixels.sum(
        ) / window_valid_pixels.size > validity_threshold
        if not is_valid:
            continue

        # Intersect and return window
        window = window.intersection(full_image_window)
        yield window_idx, window
Пример #6
0
def get_input_area_mask(input_area):
    """Get input area mask, window, and transform for a given input area.

    Parameters
    ----------
    input_area : str
        one of the major input area codes, e.g., "gh", "sa", etc

    Returns
    -------
    mask, transform, window
        mask is 1 INSIDE input area, 0 outside
    """

    values = [
        e["value"] for e in INPUT_AREA_VALUES
        if input_area in set(e["id"].split(","))
    ]

    bnd = get_input_area_boundary(input_area)

    ### Get window into raster for bounds of input area
    with rasterio.open(data_dir / "input_areas.tif") as src:
        window = src.window(*pg.total_bounds(bnd))
        window_floored = window.round_offsets(op="floor", pixel_precision=3)
        w = math.ceil(window.width + window.col_off - window_floored.col_off)
        h = math.ceil(window.height + window.row_off - window_floored.row_off)
        window = Window(window_floored.col_off, window_floored.row_off, w, h)
        window = window.intersection(Window(0, 0, src.width, src.height))
        transform = src.window_transform(window)

        data = src.read(1, window=window)

    mask = np.zeros(shape=data.shape, dtype="uint8")
    for value in values:
        mask[data == value] = 1

    return mask, transform, window
Пример #7
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
Пример #8
0
def geometry_window(dataset,
                    shapes,
                    pad_x=0,
                    pad_y=0,
                    north_up=True,
                    rotated=False,
                    pixel_precision=3):
    """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: bool
        If True (default), the origin point of the raster's transform is the
        northernmost point and y pixel values are negative.
    rotated: bool
        If true, some rotation terms exist in the dataset transform (this
        requires special attention.)
    pixel_precision: int
        Number of places of rounding precision for evaluating bounds of shapes.

    Returns
    -------
    window: rasterio.windows.Window instance
    """

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

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

    if not rotated:
        all_bounds = [bounds(shape, north_up=north_up) for shape in shapes]
        lefts, bottoms, rights, tops = zip(*all_bounds)

        left = min(lefts) - pad_x
        right = max(rights) + pad_x

        if north_up:
            bottom = min(bottoms) - pad_y
            top = max(tops) + pad_y
        else:
            bottom = max(bottoms) + pad_y
            top = min(tops) - pad_y
    else:
        # get the bounds in the pixel domain by specifying a transform to the bounds function
        all_bounds_px = [
            bounds(shape, transform=~dataset.transform) for shape in shapes
        ]
        # get left, right, top, and bottom as above
        lefts, bottoms, rights, tops = zip(*all_bounds_px)
        left = min(lefts) - pad_x
        right = max(rights) + pad_x
        top = min(tops) - pad_y
        bottom = max(bottoms) + pad_y
        # do some clamping if there are any values less than zero or greater than dataset shape
        left = max(0, left)
        top = max(0, top)
        right = min(dataset.shape[1], right)
        bottom = min(dataset.shape[0], bottom)
        # convert the bounds back to the CRS domain
        left, top = (left, top) * dataset.transform
        right, bottom = (right, bottom) * dataset.transform

    window = dataset.window(left, bottom, right, top)
    window_floored = window.round_offsets(op='floor',
                                          pixel_precision=pixel_precision)
    w = math.ceil(window.width + window.col_off - window_floored.col_off)
    h = math.ceil(window.height + window.row_off - window_floored.row_off)
    window = Window(window_floored.col_off, window_floored.row_off, w, h)

    # Make sure that window overlaps raster
    raster_window = Window(0, 0, dataset.width, dataset.height)

    # This will raise a WindowError if windows do not overlap
    window = window.intersection(raster_window)

    return window
Пример #9
0
def geometry_window(dataset, shapes, pad_x=0, pad_y=0, north_up=True,
                    rotated=False, pixel_precision=3):
    """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: bool
        If True (default), the origin point of the raster's transform is the
        northernmost point and y pixel values are negative.
    rotated: bool
        If true, some rotation terms exist in the dataset transform (this
        requires special attention.)
    pixel_precision: int
        Number of places of rounding precision for evaluating bounds of shapes.

    Returns
    -------
    window: rasterio.windows.Window instance
    """

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

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

    if not rotated:
        all_bounds = [bounds(shape, north_up=north_up) for shape in shapes]
        lefts, bottoms, rights, tops = zip(*all_bounds)

        left = min(lefts) - pad_x
        right = max(rights) + pad_x

        if north_up:
            bottom = min(bottoms) - pad_y
            top = max(tops) + pad_y
        else:
            bottom = max(bottoms) + pad_y
            top = min(tops) - pad_y
    else:
        # get the bounds in the pixel domain by specifying a transform to the bounds function
        all_bounds_px = [bounds(shape, transform=~dataset.transform) for shape in shapes]
        # get left, right, top, and bottom as above
        lefts, bottoms, rights, tops = zip(*all_bounds_px)
        left = min(lefts) - pad_x
        right = max(rights) + pad_x
        top = min(tops) - pad_y
        bottom = max(bottoms) + pad_y
        # do some clamping if there are any values less than zero or greater than dataset shape
        left = max(0, left)
        top = max(0, top)
        right = min(dataset.shape[1], right)
        bottom = min(dataset.shape[0], bottom)
        # convert the bounds back to the CRS domain
        left, top = (left, top) * dataset.transform
        right, bottom = (right, bottom) * dataset.transform

    window = dataset.window(left, bottom, right, top)
    window_floored = window.round_offsets(op='floor', pixel_precision=pixel_precision)
    w = math.ceil(window.width + window.col_off - window_floored.col_off)
    h = math.ceil(window.height + window.row_off - window_floored.row_off)
    window = Window(window_floored.col_off, window_floored.row_off, w, h)

    # Make sure that window overlaps raster
    raster_window = Window(0, 0, dataset.width, dataset.height)

    # This will raise a WindowError if windows do not overlap
    window = window.intersection(raster_window)

    return window
Пример #10
0
    def predict(self, path, predpath):
        with rasterio.open(path, "r") as src:
            meta = src.meta
        self.model.eval()

        # for prediction
        predimage = os.path.join(predpath, os.path.basename(path))
        os.makedirs(predpath, exist_ok=True)
        meta["count"] = 1
        meta["dtype"] = "uint8" # storing as uint8 saves a lot of storage space

        #Window(col_off, row_off, width, height)
        H, W = self.image_size

        rows = np.arange(0, meta["height"], H)
        cols = np.arange(0, meta["width"], W)

        image_window = Window(0, 0, meta["width"], meta["height"])

        with rasterio.open(predimage, "w+", **meta) as dst:

            for r, c in tqdm(product(rows, cols), total=len(rows) * len(cols), leave=False):

                window = image_window.intersection(
                    Window(c-self.offset, r-self.offset, W+self.offset, H+self.offset))

                with rasterio.open(path) as src:
                    image = src.read(window=window)

                # if L1C image (13 bands). read only the 12 bands compatible with L2A data
                if (image.shape[0] == 13):
                    image = image[[l1cbands.index(b) for b in l2abands]]

                # to torch + normalize
                image = self.transform(torch.from_numpy(image.astype(np.float32)), [])[0].to(self.device)

                # predict
                with torch.no_grad():
                    x = image.unsqueeze(0)
                    #import pdb; pdb.set_trace()
                    y_logits = torch.sigmoid(self.model(x).squeeze(0))
                    if self.use_test_aug > 0:
                        y_logits += torch.sigmoid(torch.fliplr(self.model(torch.fliplr(x)))).squeeze(0) # fliplr)
                        y_logits += torch.sigmoid(torch.flipud(self.model(torch.flipud(x)))).squeeze(0) # flipud
                        if self.use_test_aug > 1:
                            for rot in [1, 2, 3]: # 90, 180, 270 degrees
                                y_logits += torch.sigmoid(torch.rot90(self.model(torch.rot90(x, rot, [2, 3])),-rot,[2,3]).squeeze(0))
                            y_logits /= 6
                        else:
                            y_logits /= 3

                    y_score = y_logits.cpu().detach().numpy()[0]
                    #y_score = y_score[:,self.offset:-self.offset, self.offset:-self.offset]

                data = dst.read(window=window)[0] / 255
                overlap = data > 0

                if overlap.any():
                    # smooth transition in overlapping regions
                    dx, dy = np.gradient(overlap.astype(float)) # get border
                    g = np.abs(dx) + np.abs(dy)
                    transition = gaussian_filter(g, sigma=self.offset / 2)
                    transition /= transition.max()
                    transition[~overlap] = 1.# normalize to 1

                    y_score = transition * y_score + (1-transition) * data

                # write
                writedata = (np.expand_dims(y_score, 0).astype(np.float32) * 255).astype(np.uint8)
                dst.write(writedata, window=window)