def from_slice_out_res(self, slice_=None): assert self.out_res in ["10", "30", "20", "60" ], "output resolution must be 10, 20, 30 or 60" if slice_ is None: slice_ = self.slice if slice_ is None: slice_ = (slice(None), slice(None)) shape = (self.dimsByRes[self.out_res][0], self.dimsByRes[self.out_res][1]) slice_norm = [] for i, s in enumerate(slice_): start = 0 if s.start is None else s.start end = shape[i] if s.stop is None else s.stop slice_norm.append(slice(start, end)) slice_ = tuple(slice_norm) # Assert slice fits the dims misc.assert_valid_slice( slice_, (self.dimsByRes[self.out_res][0], self.dimsByRes[self.out_res][1])) bbox = windows.bounds(windows.Window.from_slices(*slice_), self.transform_dict[self.out_res][0]) return bbox, slice_
def _resize_crs_probav(img, src_crs, transform_landsat, resolution_step): assert (len(img.shape) == 3 ), "Prepared to work with 3d arrays in HWC format {}".format( img.shape) assert not np.any( np.ma.getmask(img)), "masked array not supported. fill before calling!" window_landsat = (slice(0, img.shape[0]), slice(0, img.shape[1])) bbox = windows.bounds(window_landsat, transform_landsat) transform, width, height = warp.calculate_default_transform( src_crs, {"init": "epsg:4326"}, img.shape[1], img.shape[0], left=bbox[0], bottom=bbox[1], right=bbox[2], top=bbox[3], resolution=resolution_step) img = np.ma.filled(img, fill_value=-1) out_array = np.ndarray((img.shape[2], height, width), dtype=img.dtype) warp.reproject(np.transpose(img, axes=(2, 0, 1)), out_array, src_crs=src_crs, dst_crs={"init": "epsg:4326"}, src_transform=transform_landsat, dst_transform=transform, resampling=warp.Resampling.lanczos, dst_nodata=-1, src_nodata=-1) out_array = np.transpose(out_array, (1, 2, 0)) return out_array, transform
def _compute_image_stats_chunked(dataset: 'DatasetReader') -> Optional[Dict[str, Any]]: """Compute statistics for the given rasterio dataset by looping over chunks.""" from rasterio import features, warp, windows from shapely import geometry total_count = valid_data_count = 0 tdigest = TDigest() sstats = SummaryStats() convex_hull = geometry.Polygon() block_windows = [w for _, w in dataset.block_windows(1)] for w in block_windows: with warnings.catch_warnings(): warnings.filterwarnings('ignore', message='invalid value encountered.*') block_data = dataset.read(1, window=w, masked=True) # handle NaNs for float rasters block_data = np.ma.masked_invalid(block_data, copy=False) total_count += int(block_data.size) valid_data = block_data.compressed() if valid_data.size == 0: continue valid_data_count += int(valid_data.size) if np.any(block_data.mask): hull_candidates = RasterDriver._hull_candidate_mask(~block_data.mask) hull_shapes = [geometry.shape(s) for s, _ in features.shapes( np.ones(hull_candidates.shape, 'uint8'), mask=hull_candidates, transform=windows.transform(w, dataset.transform) )] else: w, s, e, n = windows.bounds(w, dataset.transform) hull_shapes = [geometry.Polygon([(w, s), (e, s), (e, n), (w, n)])] convex_hull = geometry.MultiPolygon([convex_hull, *hull_shapes]).convex_hull tdigest.update(valid_data) sstats.update(valid_data) if sstats.count() == 0: return None convex_hull_wgs = warp.transform_geom( dataset.crs, 'epsg:4326', geometry.mapping(convex_hull) ) return { 'valid_percentage': valid_data_count / total_count * 100, 'range': (sstats.min(), sstats.max()), 'mean': sstats.mean(), 'stdev': sstats.std(), 'percentiles': tdigest.quantile(np.arange(0.01, 1, 0.01)), 'convex_hull': convex_hull_wgs }
def _calc_transform(self): bbox = windows.bounds(self.window, self.transform_window) transform, width, height = warp.calculate_default_transform( self.src.crs, {"init": "epsg:4326"}, self.window.width, self.window.height, left=bbox[0], bottom=bbox[1], right=bbox[2], top=bbox[3], resolution=self.resolution) return transform, width, height
def crop(pixel_collection, data_format, offsets): data, (bounds, data_crs), _ = pixel_collection left, bottom, right, top = offsets if _isimage(data_format): width, height, _ = data.shape t = transform.from_bounds(*bounds, width=width, height=height) data = data[top:height - bottom, left:width - right, :] cropped_window = windows.Window(left, top, width, height) cropped_bounds = windows.bounds(cropped_window, t) return PixelCollection(data, Bounds(cropped_bounds, data_crs)) _, height, width = data.shape t = transform.from_bounds(*bounds, width=width, height=height) data = data[:, top:height - bottom, left:width - right] cropped_window = windows.Window(left, top, width, height) cropped_bounds = windows.bounds(cropped_window, t) return PixelCollection(data, Bounds(cropped_bounds, data_crs))
def window_bounds(self, window): """Get the bounds of a window Parameters ---------- window: tuple Dataset window tuple Returns ------- bounds : tuple x_min, y_min, x_max, y_max for the given window """ transform = guard_transform(self.transform) return windows.bounds(window, transform)
def build_window(in_src, in_xy_ul, in_chip_size, in_chip_stride): out_window = windows.Window(col_off=in_xy_ul[0], row_off=in_xy_ul[1], width=in_chip_size, height=in_chip_size) out_win_transform = windows.transform(out_window, in_src.transform) col_id = in_xy_ul[1] // in_chip_stride row_id = in_xy_ul[0] // in_chip_stride out_win_id = f'{col_id}_{row_id}' out_win_bounds = windows.bounds(out_window, out_win_transform) return out_window, out_win_transform, out_win_bounds, out_win_id
def _read_window(self, vrt: WarpedVRT, dst_window: Window) -> MaskedArray: """Read window of input raster.""" dst_bounds: Bounds = bounds(dst_window, self.dst[self.default_format].transform) window = vrt.window(*dst_bounds) src_bounds = transform_bounds( self.dst[self.default_format].crs, self.src.crs, *dst_bounds ) LOGGER.debug( f"Read {dst_window} for Tile {self.tile_id} - this corresponds to bounds {src_bounds} in source" ) shape = ( len(self.layer.input_bands), int(round(dst_window.height)), int(round(dst_window.width)), ) try: return vrt.read( window=window, out_shape=shape, masked=True, ) except rasterio.RasterioIOError as e: if "Access window out of range" in str(e) and ( shape[1] == 1 or shape[2] == 1 ): LOGGER.warning( f"Access window out of range while reading {dst_window} for Tile {self.tile_id}. " "This is most likely due to subpixel misalignment. " "Returning empty array instead." ) return np.ma.array( data=np.zeros(shape=shape), mask=np.ones(shape=shape) ) else: LOGGER.warning( f"RasterioIO error while reading {dst_window} for Tile {self.tile_id}. " "Will make attempt to retry." ) raise
def _reproject_dst_window(self, dst_window: Window) -> Window: """Reproject window into same projection as source raster.""" dst_bounds: Bounds = bounds( window=dst_window, transform=self.dst[self.default_format].transform, height=self.grid.blockysize, width=self.grid.blockxsize, ) src_bounds: Bounds = transform_bounds( self.dst[self.default_format].crs, self.src.crs, *dst_bounds ) src_window: Window = from_bounds(*src_bounds, transform=self.src.transform) LOGGER.debug( f"Source window for {dst_window} of tile {self.tile_id} is {src_window}" ) return src_window
def test_window_bounds_function(): with rasterio.open('tests/data/RGB.byte.tif') as src: rows = src.height cols = src.width assert bounds(((0, rows), (0, cols)), src.transform) == src.bounds
def pixel_to_geo(datafile: DataFile, window: PixelWindow) -> GeoWindow: """Return the geo BoundingBox corresponding to the pixel window on the datafile""" return rasterio.coords.BoundingBox( *windows.bounds(window, datafile.transform))
def _get_gpdf_from_window(self, window: Window, transform) -> GeoDataFrame: """Returns a GeoDataFrame of the bounds of the given window""" return self._get_gpdf_from_bounds(bounds(window, transform))
def test_window_bounds_function(path_rgb_byte_tif): with rasterio.open(path_rgb_byte_tif) as src: rows = src.height cols = src.width assert bounds(((0, rows), (0, cols)), src.transform) == src.bounds
def _get_raster_tile(self, path: str, *, upsampling_method: str, downsampling_method: str, bounds: Tuple[float, float, float, float] = None, tile_size: Tuple[int, int] = (256, 256), preserve_values: bool = False) -> np.ma.MaskedArray: """Load a raster dataset from a file through rasterio. Heavily inspired by mapbox/rio-tiler """ import rasterio from rasterio import transform, windows, warp from rasterio.vrt import WarpedVRT from affine import Affine dst_bounds: Tuple[float, float, float, float] if preserve_values: upsampling_enum = downsampling_enum = self._get_resampling_enum('nearest') else: upsampling_enum = self._get_resampling_enum(upsampling_method) downsampling_enum = self._get_resampling_enum(downsampling_method) with contextlib.ExitStack() as es: es.enter_context(rasterio.Env(**self._RIO_ENV_KEYS)) try: with trace('open_dataset'): src = es.enter_context(rasterio.open(path)) except OSError: raise IOError('error while reading file {}'.format(path)) # compute suggested resolution and bounds in target CRS dst_transform, _, _ = self._calculate_default_transform( src.crs, self._TARGET_CRS, src.width, src.height, *src.bounds ) dst_res = (abs(dst_transform.a), abs(dst_transform.e)) dst_bounds = warp.transform_bounds(src.crs, self._TARGET_CRS, *src.bounds) if bounds is None: bounds = dst_bounds # pad tile bounds to prevent interpolation artefacts num_pad_pixels = 2 # compute tile VRT shape and transform dst_width = max(1, round((bounds[2] - bounds[0]) / dst_res[0])) dst_height = max(1, round((bounds[3] - bounds[1]) / dst_res[1])) vrt_transform = ( transform.from_bounds(*bounds, width=dst_width, height=dst_height) * Affine.translation(-num_pad_pixels, -num_pad_pixels) ) vrt_height, vrt_width = dst_height + 2 * num_pad_pixels, dst_width + 2 * num_pad_pixels # remove padding in output out_window = windows.Window( col_off=num_pad_pixels, row_off=num_pad_pixels, width=dst_width, height=dst_height ) # construct VRT vrt = es.enter_context( WarpedVRT( src, crs=self._TARGET_CRS, resampling=upsampling_enum, add_alpha=True, transform=vrt_transform, width=vrt_width, height=vrt_height ) ) # prevent loads of very sparse data out_window_bounds = windows.bounds(out_window, vrt_transform) cover_ratio = ( (dst_bounds[2] - dst_bounds[0]) / (out_window_bounds[2] - out_window_bounds[0]) * (dst_bounds[3] - dst_bounds[1]) / (out_window_bounds[3] - out_window_bounds[1]) ) if cover_ratio < 0.01: raise exceptions.TileOutOfBoundsError('dataset covers less than 1% of tile') # determine whether we are upsampling or downsampling pixel_ratio = min(out_window.width / tile_size[1], out_window.height / tile_size[0]) if pixel_ratio < 1: resampling_enum = upsampling_enum else: resampling_enum = downsampling_enum # read data with warnings.catch_warnings(), trace('read_from_vrt'): warnings.filterwarnings('ignore', message='invalid value encountered.*') tile_data = vrt.read( 1, resampling=resampling_enum, window=out_window, out_shape=tile_size ) # read alpha mask mask_idx = src.count + 1 mask = vrt.read(mask_idx, window=out_window, out_shape=tile_size) == 0 if src.nodata is not None: mask |= tile_data == src.nodata return np.ma.masked_array(tile_data, mask=mask)