def test_statsFunction_valid(): """Should return a valid dict with array statistics.""" with rasterio.open(S3_ALPHA_PATH) as src: arr = src.read(indexes=[1], masked=True) stats = utils._stats(arr) assert stats["pc"] == [10, 200] assert stats["min"] == 0 assert stats["max"] == 254 assert int(stats["std"]) == 55 assert len(stats["histogram"]) == 2 assert len(stats["histogram"][0]) == 10 stats = utils._stats(arr, percentiles=(5, 95)) assert stats["pc"] == [31, 195]
def _sentinel_stats(src_path, percentiles=(2, 98)): """ src_path : str or PathLike object A dataset path or URL. Will be opened in "r" mode. """ with rasterio.open(src_path) as src: arr = src.read(indexes=[1], masked=True) arr[arr == 0] = np.ma.masked return {1: utils._stats(arr, percentiles=percentiles)}
def test_raster_get_stats_ovr(): """Validate that overview level return the same result than reeading the overview.""" resampling_method = "bilinear" rio_stats = utils.raster_get_stats( S3_PATH, overview_level=1, resampling_method=resampling_method ) with rasterio.open(S3_PATH, overview_level=1) as src_dst: indexes = src_dst.indexes arr = src_dst.read(resampling=Resampling[resampling_method], masked=True) stats = {indexes[b]: utils._stats(arr[b], bins=10) for b in range(arr.shape[0])} assert rio_stats["statistics"] == stats
def _sentinel_stats( src_path, percentiles=(2, 98), histogram_bins=10, histogram_range=None ): """ src_path : str or PathLike object A dataset path or URL. Will be opened in "r" mode. """ with rasterio.open(src_path) as src: arr = src.read(indexes=[1], masked=True) arr[arr == 0] = np.ma.masked params = {} if histogram_bins: params.update(dict(bins=histogram_bins)) if histogram_range: params.update(dict(range=histogram_range)) return {1: utils._stats(arr, percentiles=percentiles, **params)}
def _landsat_stats( band, address_prefix, metadata, overview_level=None, max_size=1024, percentiles=(2, 98), dst_crs=CRS({"init": "EPSG:4326"}), histogram_bins=10, histogram_range=None, ): """ Retrieve landsat dataset statistics. Attributes ---------- band : str Landsat band number address_prefix : str A Landsat AWS S3 dataset prefix. metadata : dict Landsat metadata overview_level : int, optional Overview (decimation) level to fetch. max_size: int, optional Maximum size of dataset to retrieve (will be used to calculate the overview level to fetch). percentiles : tulple, optional Percentile or sequence of percentiles to compute, which must be between 0 and 100 inclusive (default: (2, 98)). dst_crs: CRS or dict Target coordinate reference system (default: EPSG:4326). histogram_bins: int, optional Defines the number of equal-width histogram bins (default: 10). histogram_range: tuple or list, optional The lower and upper range of the bins. If not provided, range is simply the min and max of the array. Returns ------- out : dict (percentiles), min, max, stdev, histogram for each band, e.g. { "4": { 'pc': [15, 121], 'min': 1, 'max': 162, 'std': 27.22067722127997, 'histogram': [ [102934, 135489, 20981, 13548, 11406, 8799, 7351, 5622, 2985, 662] [1., 17.1, 33.2, 49.3, 65.4, 81.5, 97.6, 113.7, 129.8, 145.9, 162.] ] } } """ src_path = "{}_B{}.TIF".format(address_prefix, band) with rasterio.open(src_path) as src: levels = src.overviews(1) width = src.width height = src.height bounds = transform_bounds(src.crs, dst_crs, *src.bounds, densify_pts=21) if len(levels): if overview_level: decim = levels[overview_level] else: # determine which zoom level to read for ii, decim in enumerate(levels): if max(width // decim, height // decim) < max_size: break else: decim = 1 warnings.warn("Dataset has no overviews, reading the full dataset", NoOverviewWarning) out_shape = (height // decim, width // decim) if band == "QA": nodata = 1 else: nodata = 0 vrt_params = dict(nodata=nodata, add_alpha=False, src_nodata=nodata, init_dest_nodata=False) with WarpedVRT(src, **vrt_params) as vrt: arr = vrt.read(out_shape=out_shape, indexes=[1], masked=True) if band in ["1", "2", "3", "4", "5", "6", "7", "8", "9"]: # OLI multi_reflect = metadata["RADIOMETRIC_RESCALING"].get( "REFLECTANCE_MULT_BAND_{}".format(band)) add_reflect = metadata["RADIOMETRIC_RESCALING"].get( "REFLECTANCE_ADD_BAND_{}".format(band)) sun_elev = metadata["IMAGE_ATTRIBUTES"]["SUN_ELEVATION"] arr = 10000 * reflectance.reflectance( arr, multi_reflect, add_reflect, sun_elev, src_nodata=0) elif band in ["10", "11"]: # TIRS multi_rad = metadata["RADIOMETRIC_RESCALING"].get( "RADIANCE_MULT_BAND_{}".format(band)) add_rad = metadata["RADIOMETRIC_RESCALING"].get( "RADIANCE_ADD_BAND_{}".format(band)) k1 = metadata["TIRS_THERMAL_CONSTANTS"].get( "K1_CONSTANT_BAND_{}".format(band)) k2 = metadata["TIRS_THERMAL_CONSTANTS"].get( "K2_CONSTANT_BAND_{}".format(band)) arr = brightness_temp.brightness_temp(arr, multi_rad, add_rad, k1, k2) params = {} if histogram_bins: params.update(dict(bins=histogram_bins)) if histogram_range: params.update(dict(range=histogram_range)) stats = {band: utils._stats(arr, percentiles=percentiles, **params)} return { "bounds": { "value": bounds, "crs": dst_crs.to_string() if isinstance(dst_crs, CRS) else dst_crs, }, "statistics": stats, }
def get_area_stats( src, bounds, max_img_size=512, indexes=None, nodata=None, resampling_method="bilinear", bbox_crs="epsg:4326", histogram_bins=20, histogram_range=None, ): """ Read data and mask. Attributes ---------- srd_dst : rasterio.io.DatasetReader rasterio.io.DatasetReader object bounds : list bounds (left, bottom, right, top) tilesize : int Output image size indexes : list of ints or a single int, optional, (defaults: None) If `indexes` is a list, the result is a 3D array, but is a 2D array if it is a band index number. nodata: int or float, optional (defaults: None) resampling_method : str, optional (default: "bilinear") Resampling algorithm histogram_bins: int, optional Defines the number of equal-width histogram bins (default: 10). histogram_range: str, optional The lower and upper range of the bins. If not provided, range is simply the min and max of the array. Returns ------- out : array, int returns pixel value. """ if isinstance(indexes, int): indexes = [indexes] elif isinstance(indexes, tuple): indexes = list(indexes) with rasterio.open(src) as src_dst: bounds = transform_bounds(bbox_crs, src_dst.crs, *bounds, densify_pts=21) vrt_params = dict(add_alpha=True, resampling=Resampling[resampling_method]) indexes = indexes if indexes is not None else src_dst.indexes nodata = nodata if nodata is not None else src_dst.nodata def _get_descr(ix): """Return band description.""" name = src_dst.descriptions[ix - 1] if not name: name = "band{}".format(ix) return name band_descriptions = [(ix, _get_descr(ix)) for ix in indexes] vrt_transform, vrt_width, vrt_height = get_vrt_transform( src_dst, bounds, bounds_crs=src_dst.crs) vrt_params.update( dict(transform=vrt_transform, width=vrt_width, height=vrt_height)) width = round(vrt_width) if vrt_width < max_img_size else max_img_size height = round( vrt_height) if vrt_height < max_img_size else max_img_size out_shape = (len(indexes), width, height) if nodata is not None: vrt_params.update( dict(nodata=nodata, add_alpha=False, src_nodata=nodata)) if has_alpha_band(src_dst): vrt_params.update(dict(add_alpha=False)) with WarpedVRT(src_dst, **vrt_params) as vrt: arr = vrt.read(out_shape=out_shape, indexes=indexes, masked=True) if not arr.any(): return None, band_descriptions params = {} if histogram_bins: params.update(dict(bins=histogram_bins)) if histogram_range: params.update(dict(range=histogram_range)) stats = { indexes[b]: _stats(arr[b], **params) for b in range(arr.shape[0]) if vrt.colorinterp[b] != ColorInterp.alpha } return stats, band_descriptions