Пример #1
0
def test_window_intersection_disjunct():
    with pytest.raises(WindowError):
        windows.intersection(((0, 6), (3, 6)), ((100, 200), (0, 12)),
                             ((7, 12), (7, 12)))

        # touch, no overlap on edge of open interval
        assert windows.intersection(((0, 6), (3, 6)), ((6, 10), (1, 5)))
Пример #2
0
def test_iter_args_winfuncs():
    wins = [
        ((0, 6), (3, 6)),
        ((2, 4), (1, 5))]

    assert windows.intersect(*wins) == windows.intersect(wins)
    assert windows.intersection(*wins) == windows.intersection(wins)
    assert windows.union(*wins) == windows.union(wins)
Пример #3
0
def test_window_intersection():
    assert windows.intersection(
        ((0, 6), (3, 6)), ((2, 4), (1, 5))) == windows.Window.from_ranges(
            (2, 4), (3, 5))

    assert windows.intersection(
        ((0, 6), (3, 6)), ((2, 4), (1, 5)),
        ((3, 6), (0, 6))) == windows.Window.from_ranges((3, 4), (3, 5))
Пример #4
0
def test_iter_args_winfuncs():
    wins = [
        ((0, 6), (3, 6)),
        ((2, 4), (1, 5))]

    assert windows.intersect(*wins) == windows.intersect(wins)
    assert windows.intersection(*wins) == windows.intersection(wins)
    assert windows.union(*wins) == windows.union(wins)
Пример #5
0
def test_window_intersection():
    assert windows.intersection(
        ((0, 6), (3, 6)),
        ((2, 4), (1, 5))
    ) == ((2, 4), (3, 5))

    assert windows.intersection(
        ((0, 6), (3, 6)),
        ((2, 4), (1, 5)),
        ((3, 6), (0, 6))
    ) == ((3, 4), (3, 5))
Пример #6
0
def test_window_intersection():
    assert windows.intersection(
        ((0, 6), (3, 6)),
        ((2, 4), (1, 5))
    ) == windows.Window.from_slices((2, 4), (3, 5))

    assert windows.intersection(
        ((0, 6), (3, 6)),
        ((2, 4), (1, 5)),
        ((3, 6), (0, 6))
    ) == windows.Window.from_slices((3, 4), (3, 5))
Пример #7
0
def test_window_intersection():
    assert windows.intersection(
        ((0, 6), (3, 6)),
        ((2, 4), (1, 5))
    ) == ((2, 4), (3, 5))

    assert windows.intersection(
        ((0, 6), (3, 6)),
        ((2, 4), (1, 5)),
        ((3, 6), (0, 6))
    ) == ((3, 4), (3, 5))
Пример #8
0
def test_window_intersection_disjunct():
    with pytest.raises(WindowError):
        windows.intersection(
            ((0, 6), (3, 6)),
            ((100, 200), (0, 12)),
            ((7, 12), (7, 12)))

        # touch, no overlap on edge of open interval
        assert windows.intersection(
            ((0, 6), (3, 6)),
            ((6, 10), (1, 5)))
Пример #9
0
def test_window_intersection(recwarn):
    data = [((0, 6), (3, 6)), ((2, 4), (1, 5))]
    warnings.simplefilter('always')
    old = window_intersection(data)
    assert len(recwarn) == 1
    assert recwarn.pop(DeprecationWarning)
    new = windows.intersection(data)
    assert len(recwarn) == 0
    assert old == new
Пример #10
0
def test_3x3matrix():
    """For a 3x3 arrangement of 2x2 windows
      a | b | c
      ---------
      d | e | f
      ---------
      g | h | i

      i.e. window e is ((2, 4), (2, 4))

      None of them should intersect or have an intersection
    """
    from itertools import product, combinations

    pairs = ((0, 2), (2, 4), (4, 6))
    arrangement = product(pairs, pairs)
    for wins in combinations(arrangement, 2):
        assert not windows.intersect(*wins)
        with pytest.raises(WindowError):
            windows.intersection(*wins)
Пример #11
0
def test_3x3matrix():
    """For a 3x3 arrangement of 2x2 windows
      a | b | c
      ---------
      d | e | f
      ---------
      g | h | i

      i.e. window e is ((2, 4), (2, 4))

      None of them should intersect or have an intersection
    """
    from itertools import product, combinations

    pairs = ((0, 2), (2, 4), (4, 6))
    arrangement = product(pairs, pairs)
    for wins in combinations(arrangement, 2):
        assert not windows.intersect(*wins)
        with pytest.raises(WindowError):
            windows.intersection(*wins)
Пример #12
0
def test_window_intersection(recwarn):
    data = [
        ((0, 6), (3, 6)),
        ((2, 4), (1, 5))]
    warnings.simplefilter('always')
    old = window_intersection(data)
    assert len(recwarn) == 1
    assert recwarn.pop(DeprecationWarning)
    new = windows.intersection(data)
    assert len(recwarn) == 0
    assert old == new
Пример #13
0
def test_intersection():
    """Window intersection works."""
    window = intersection(Window(0, 0, 10, 10), Window(8, 8, 12, 12))
    assert window == Window.from_slices((8, 10), (8, 10))
Пример #14
0
def test_no_intersection():
    """Non intersecting windows raises error."""
    with pytest.raises(WindowError):
        intersection(Window(0, 0, 1, 1), Window(1, 1, 2, 2))
Пример #15
0
def window_intersection(data):
    warnings.warn("Deprecated; Use rasterio.windows instead", DeprecationWarning)
    return windows.intersection(data)
Пример #16
0
def window_intersection(data):
    warnings.warn("Deprecated; Use rasterio.windows instead",
                  DeprecationWarning)
    return windows.intersection(data)
Пример #17
0
def read_data_rasterio(rio_dataset, src_rect=None, dst_width=None, dst_height=None,
                       nodata_value=np.uint8(0), dtype=None, select_bands=None,
                       resampling=Resampling.nearest):
    """
    Method to read data from rasterio dataset

    Args:
      rio_dataset: instance of rasterio.io.DatasetReader
      src_rect: is source extent in pixels : [x,y,w,h] where (x,y) is top-left corner. Can be None and whole image
        extent is used. (Default value = None)
      dst_width: is the output array width. Can be None and src_rect[2] (width) is used. (Default value = None)
      dst_height: is the output array heigth. Can be None and src_rect[3] (height) is used. (Default value = None)
      nodata_value: value to fill out of bounds pixels with. (Default value = np.uint8(0)
      dtype: force type of returned numpy array
      select_bands: tuple of band indices (zero-based) to select from dataset, e.g. [0, 3, 4].
      resampling: rasterio resampling method (see rasterio.enums.Resampling)

    Returns:
      numpy.ndarray
    """
    assert isinstance(rio_dataset, rio.io.DatasetReader), \
        "Argument rio_dataset should be instance of rasterio.io.DatasetReader"
    assert rio_dataset.count > 0, "Dataset has no bands"

    if select_bands is not None:
        assert isinstance(select_bands, list) or isinstance(select_bands, tuple), \
            "Argument select_bands should be a tuple or list"
        available_bands = list(range(rio_dataset.count))
        for index in select_bands:
            assert index in available_bands, \
                "Index {} from select_bands is outside of available bands: {}".format(index, available_bands)

    if src_rect is None:
        src_req_extent = Window(0, 0, rio_dataset.width, rio_dataset.height)
        src_extent = [src_req_extent.col_off, src_req_extent.row_off, src_req_extent.width, src_req_extent.height]
    else:
        src_req_extent = intersection(Window(*src_rect), Window(0, 0, rio_dataset.width, rio_dataset.height))
        src_extent = src_rect

    if src_req_extent is None:
        print('Source request extent is None')
        return None

    if dst_width is None and dst_height is None:
        dst_extent = [src_extent[2], src_extent[3]]
    elif dst_height is None:
        h = int(dst_width * src_extent[3] * 1.0 / src_extent[2])
        dst_extent = [dst_width, h]
    elif dst_width is None:
        w = int(dst_height * src_extent[2] * 1.0 / src_extent[3])
        dst_extent = [w, dst_height]
    else:
        dst_extent = [dst_width, dst_height]

    scale_x = dst_extent[0] * 1.0 / src_extent[2]
    scale_y = dst_extent[1] * 1.0 / src_extent[3]
    req_scaled_w = int(min(np.ceil(scale_x * src_req_extent.width), dst_extent[0]))
    req_scaled_h = int(min(np.ceil(scale_y * src_req_extent.height), dst_extent[1]))

    r = [int(np.floor(scale_x * (src_req_extent.col_off - src_extent[0]))),
         int(np.floor(scale_y * (src_req_extent.row_off - src_extent[1]))),
         req_scaled_w,
         req_scaled_h]

    band_indices = range(rio_dataset.count) if select_bands is None else select_bands
    nb_bands = len(band_indices)

    if dtype is None:
        dtypes = rio_dataset.dtypes + (type(nodata_value),)
        dtype_sizes = [np.dtype(d).itemsize for d in dtypes]
        datatype = np.dtype(dtypes[np.argmax(dtype_sizes)])
    else:
        datatype = dtype

    out = np.empty((dst_extent[1], dst_extent[0], nb_bands), dtype=datatype)
    out.fill(nodata_value)

    band_indices = [b + 1 for b in band_indices]
    data = rio_dataset.read(indexes=band_indices,
                            out_shape=(len(band_indices), r[3], r[2]),
                            window=src_req_extent,
                            resampling=resampling)
    out[r[1]:r[1] + r[3], r[0]:r[0] + r[2], :] = np.transpose(data, [1, 2, 0])
    return out
Пример #18
0
def stack_and_clip_rasters(raster_files, use_common=True, output_tif=None):
    """Combine multiple single band files into a single multi band raster where one band represents
    one file. The filename will be saved in the bands tag. Optionally a minimum common area mask
    can be applied.

    All input rasters MUST be of the same coordinate system and pixel size.

    Args:
        raster_files (List[str]): list of raster files to process
        use_common (bool):  if true input rasters will be masked to the minimum common data area
        output_tif (str):  output tif name. if omitted will be created in TEMPDIR

    Returns:
        str(): The output tif file
        list(): A list of the band tags. (ie order of allocation to bands)
    """
    # if output_tif doesn't include a path then add tempdir as well as overwriting it
    if output_tif is not None and not os.path.isabs(output_tif):
        output_tif = os.path.join(TEMPDIR, output_tif)

    if output_tif is None or config.get_debug_mode():
        # get a unique name, it will create, open the file and delete after saving the variable
        with NamedTemporaryFile(prefix='{}_'.format(
                inspect.getframeinfo(inspect.currentframe())[2]),
                                suffix='.tif',
                                dir=TEMPDIR) as new_file:
            output_tif = new_file.name
        del new_file

    if not isinstance(raster_files, list):
        raise TypeError('Invalid Type: raster_files should be a list')

    if len(raster_files) == 0:
        raise TypeError('Invalid Type: Empty list of raster files')

    not_exists = [
        my_file for my_file in raster_files if not os.path.exists(my_file)
    ]
    if len(not_exists) > 0:
        raise IOError('raster_files: {} raster file(s) do '
                      'not exist\n\t({})'.format(len(not_exists),
                                                 '\n\t'.join(not_exists)))

    check_pixelsize = []
    check_crs = []

    for ea_raster in raster_files:
        with rasterio.open(ea_raster) as src:
            if src.crs is None:
                check_crs.append(ea_raster)
            if src.res not in check_pixelsize:
                check_pixelsize.append(src.res)

    if len(check_pixelsize) == 1:
        resolution = check_pixelsize[0]
    else:
        raise TypeError(
            "raster_files are of different pixel sizes - {}".format(
                list(set(check_pixelsize))))

    if len(check_crs) > 0:
        raise TypeError("{} raster(s) don't have coordinates "
                        "systems assigned \n\t{}".format(
                            len(check_crs), '\n\t'.join(check_crs)))

    start_time = time.time()
    step_time = time.time()

    # Make sure ALL masks are saved inside the TIFF file not as a sidecar.
    gdal.SetConfigOption('GDAL_TIFF_INTERNAL_MASK', 'YES')

    try:
        # Find minimum overlapping extent of all rasters ------------------------------------
        for i, ea_raster in enumerate(raster_files, start=1):
            with rasterio.open(ea_raster) as src:

                band1 = src.read(1, masked=True)

                # get minimum data extent
                data_window = get_data_window(band1)

                # find the intersection of all the windows
                if i == 1:
                    min_window = data_window
                else:
                    # create a new window using the last coordinates based on this image in case
                    # extents/pixel origins are different
                    min_img_window = from_bounds(*min_bbox,
                                                 transform=src.transform)

                    # find the intersection of the windows.
                    min_window = intersection(
                        min_img_window, data_window).round_lengths('ceil')

                # convert the window co coordinates
                min_bbox = src.window_bounds(min_window)

                del min_window
        if config.get_debug_mode():
            LOGGER.info('{:<30} {:<15} {dur} {}'.format(
                'Found Common Extent',
                '',
                min_bbox,
                dur=timedelta(seconds=time.time() - step_time)))

    except rasterio.errors.WindowError as e:
        # reword 'windows do not intersect' error message
        if not e.args:
            e.args = ('', )
        e.args = ("Rasters (Images) do not overlap", )

        raise  # re-raise current exception

    # Create the metadata for the overlapping extent image. ---------------------------------------
    transform, width, height, bbox = create_raster_transform(
        min_bbox, resolution[0], buffer_by_pixels=5)

    # update the new image metadata ---------------------------------------------------------------
    kwargs = rasterio.open(raster_files[0]).meta.copy()
    kwargs.update({
        'count': len(raster_files),
        'nodata': -9999,
        'height': height,
        'width': width,
        'transform': transform
    })
    ''' combine individual rasters into one multi-band tiff using reproject will 
           fit each raster to the same pixel origin
           will crop to the min bbox
           standardise the nodata values
           apply nodata values to entire image including internal blocks'''

    with rasterio.open(output_tif, 'w', **kwargs) as dst:
        band_list = []
        for i, ea_raster in enumerate(raster_files, start=1):
            image = os.path.basename(os.path.splitext(ea_raster)[0])
            band_list.append(image)

            with rasterio.open(ea_raster) as src:
                reproject(source=rasterio.band(src, 1),
                          destination=rasterio.band(dst, i),
                          src_transform=src.transform,
                          dst_transform=transform,
                          resampling=Resampling.nearest)

            dst.update_tags(i, **{'name': image})

        dst.descriptions = band_list
    if config.get_debug_mode():
        LOGGER.info('{:<30} {:<15} {dur}'.format(
            'Rasters Combined',
            '',
            dur=timedelta(seconds=time.time() - step_time)))

    # find the common data area -------------------------------------------------------
    if use_common:
        with rasterio.open(output_tif, 'r+') as src:
            # find common area across all bands as there maybe internal nodata values in some bands.
            mask = []

            # loop through all all the masks
            for ea_mask in src.read_masks():
                if len(mask) == 0:
                    mask = ea_mask
                else:
                    mask = mask & ea_mask

            # change mask values to  0 = nodata, 1 = valid data
            mask[mask == 255] = 1

            # apply mask to all bands of file
            src.write_mask(mask)

        if config.get_debug_mode():
            # write mask to new file
            tmp_file = os.path.join(
                TEMPDIR, output_tif.replace('.tif', '_commonarea.tif'))

            kwargs_tmp = kwargs.copy()
            kwargs_tmp.update({
                'count': 1,
                'nodata': 0,
                'dtype': rasterio.dtypes.get_minimum_dtype(mask)
            })

            with rasterio.open(tmp_file, 'w', **kwargs_tmp) as tmp_dst:
                tmp_dst.write(mask, 1)

        LOGGER.info('{:<30} {:<15} {dur}'.format(
            'Rasters Combined and clipped',
            '',
            dur=timedelta(seconds=time.time() - start_time)))

    gdal.SetConfigOption('GDAL_TIFF_INTERNAL_MASK', None)

    return output_tif, band_list
Пример #19
0
def test_intersection():
    """Window intersection works."""
    window = intersection(Window(0, 0, 10, 10), Window(8, 8, 12, 12))
    assert window == Window.from_slices((8, 10), (8, 10))
Пример #20
0
def test_no_intersection():
    """Non intersecting windows raises error."""
    with pytest.raises(WindowError):
        intersection(Window(0, 0, 1, 1), Window(1, 1, 2, 2))