def check_features_block_windows(features, src, bidx): """Compare GeoJSON features to a datasource's blocks + windows. Parameters ---------- features : iter GeoJSON features src : a dataset object opened in 'r' mode Open input datasource Returns ------- bool ``True`` if the two block/window streams match and ``False`` otherwise """ out = [] iterator = zip_longest(features, src.block_windows(bidx=bidx)) for feat, (block, window) in iterator: out.append(np.array_equal( json.loads(feat['properties']['block']), block)) f_win = feat['properties']['window'] assert f_win['col_off'] == window.col_off assert f_win['row_off'] == window.row_off return all(out)
def check_features_block_windows(features, src, bidx): """Compare GeoJSON features to a datasource's blocks + windows. Parameters ---------- features : iter GeoJSON features. src : RasterReader Open input datasource. Returns ------- bool ``True`` if the two block/window streams match and ``False`` otherwise. """ out = [] iterator = zip_longest(features, src.block_windows(bidx=bidx)) for feat, (block, window) in iterator: out.append(np.array_equal( json.loads(feat['properties']['block']), block)) out.append(np.array_equal( json.loads(feat['properties']['window']), window)) return all(out)
def check_features_block_windows(features, src, bidx): """Compare GeoJSON features to a datasource's blocks + windows. Parameters ---------- features : iter GeoJSON features src : a dataset object opened in 'r' mode Open input datasource Returns ------- bool ``True`` if the two block/window streams match and ``False`` otherwise """ out = [] iterator = zip_longest(features, src.block_windows(bidx=bidx)) for feat, (block, window) in iterator: out.append( np.array_equal(json.loads(feat['properties']['block']), block)) f_win = feat['properties']['window'] assert f_win['col_off'] == window.col_off assert f_win['row_off'] == window.row_off return all(out)
def stack(ctx, files, output, driver, bidx, photometric, force_overwrite, creation_options): """Stack a number of bands from one or more input files into a multiband dataset. Input datasets must be of a kind: same data type, dimensions, etc. The output is cloned from the first input. By default, rio-stack will take all bands from each input and write them in same order to the output. Optionally, bands for each input may be specified using a simple syntax: --bidx N takes the Nth band from the input (first band is 1). --bidx M,N,0 takes bands M, N, and O. --bidx M..O takes bands M-O, inclusive. --bidx ..N takes all bands up to and including N. --bidx N.. takes all bands from N to the end. Examples, using the Rasterio testing dataset, which produce a copy. rio stack RGB.byte.tif -o stacked.tif rio stack RGB.byte.tif --bidx 1,2,3 -o stacked.tif rio stack RGB.byte.tif --bidx 1..3 -o stacked.tif rio stack RGB.byte.tif --bidx ..2 RGB.byte.tif --bidx 3.. -o stacked.tif """ verbosity = (ctx.obj and ctx.obj.get('verbosity')) or 2 logger = logging.getLogger('rio') try: with rasterio.Env(CPL_DEBUG=verbosity > 2): output, files = resolve_inout(files=files, output=output, force_overwrite=force_overwrite) output_count = 0 indexes = [] for path, item in zip_longest(files, bidx, fillvalue=None): with rasterio.open(path) as src: src_indexes = src.indexes if item is None: indexes.append(src_indexes) output_count += len(src_indexes) elif '..' in item: start, stop = map(lambda x: int(x) if x else None, item.split('..')) if start is None: start = 1 indexes.append(src_indexes[slice(start - 1, stop)]) output_count += len(src_indexes[slice(start - 1, stop)]) else: parts = list(map(int, item.split(','))) if len(parts) == 1: indexes.append(parts[0]) output_count += 1 else: parts = list(parts) indexes.append(parts) output_count += len(parts) with rasterio.open(files[0]) as first: kwargs = first.meta kwargs.update(**creation_options) kwargs['transform'] = kwargs.pop('affine') kwargs.update(driver=driver, count=output_count) if photometric: kwargs['photometric'] = photometric with rasterio.open(output, 'w', **kwargs) as dst: dst_idx = 1 for path, index in zip(files, indexes): with rasterio.open(path) as src: if isinstance(index, int): data = src.read(index) dst.write(data, dst_idx) dst_idx += 1 elif isinstance(index, collections.Iterable): data = src.read(index) dst.write(data, range(dst_idx, dst_idx + len(index))) dst_idx += len(index) except Exception: logger.exception("Exception caught during processing") raise click.Abort()
def show_hist(source, bins=10, masked=True, title='Histogram'): """Easily display a histogram with matplotlib. Parameters ---------- bins : int, optional Compute histogram across N bins. data : np.array or rasterio.Band or tuple(dataset, bidx) Input data to display. The first three arrays in multi-dimensional arrays are plotted as red, green, and blue. masked : bool, optional When working with a `rasterio.Band()` object, specifies if the data should be masked on read. title : str, optional Title for the figure. """ if plt is None: # pragma: no cover raise ImportError("Could not import matplotlib") if isinstance(source, (tuple, rasterio.Band)): arr = source[0].read(source[1], masked=masked) else: arr = source # The histogram is computed individually for each 'band' in the array # so we need the overall min/max to constrain the plot rng = arr.min(), arr.max() if len(arr.shape) is 2: arr = [arr] colors = ['gold'] else: colors = ('red', 'green', 'blue', 'violet', 'gold', 'saddlebrown') # If a rasterio.Band() is given make sure the proper index is displayed # in the legend. if isinstance(source, (tuple, rasterio.Band)): labels = [str(source[1])] else: labels = (str(i + 1) for i in range(len(arr))) # This loop should add a single plot each band in the input array, # regardless of if the number of bands exceeds the number of colors. # The colors slicing ensures that the number of iterations always # matches the number of bands. # The goal is to provide a curated set of colors for working with # smaller datasets and let matplotlib define additional colors when # working with larger datasets. for bnd, color, label in zip_longest(arr, colors[:len(arr)], labels): plt.hist(bnd.flatten(), bins=bins, alpha=0.5, color=color, label=label, range=rng) plt.legend(loc="upper right") plt.title(title, fontweight='bold') plt.grid(True) plt.xlabel('DN') plt.ylabel('Frequency') fig = plt.gcf() fig.show()
def stack(ctx, files, output, driver, bidx, photometric, force_overwrite, creation_options): """Stack a number of bands from one or more input files into a multiband dataset. Input datasets must be of a kind: same data type, dimensions, etc. The output is cloned from the first input. By default, rio-stack will take all bands from each input and write them in same order to the output. Optionally, bands for each input may be specified using a simple syntax: --bidx N takes the Nth band from the input (first band is 1). --bidx M,N,0 takes bands M, N, and O. --bidx M..O takes bands M-O, inclusive. --bidx ..N takes all bands up to and including N. --bidx N.. takes all bands from N to the end. Examples, using the Rasterio testing dataset, which produce a copy. rio stack RGB.byte.tif -o stacked.tif rio stack RGB.byte.tif --bidx 1,2,3 -o stacked.tif rio stack RGB.byte.tif --bidx 1..3 -o stacked.tif rio stack RGB.byte.tif --bidx ..2 RGB.byte.tif --bidx 3.. -o stacked.tif """ logger = logging.getLogger('rio') try: with ctx.obj['env']: output, files = resolve_inout(files=files, output=output, force_overwrite=force_overwrite) output_count = 0 indexes = [] for path, item in zip_longest(files, bidx, fillvalue=None): with rasterio.open(path) as src: src_indexes = src.indexes if item is None: indexes.append(src_indexes) output_count += len(src_indexes) elif '..' in item: start, stop = map( lambda x: int(x) if x else None, item.split('..')) if start is None: start = 1 indexes.append(src_indexes[slice(start - 1, stop)]) output_count += len(src_indexes[slice(start - 1, stop)]) else: parts = list(map(int, item.split(','))) if len(parts) == 1: indexes.append(parts[0]) output_count += 1 else: parts = list(parts) indexes.append(parts) output_count += len(parts) with rasterio.open(files[0]) as first: kwargs = first.meta kwargs.update(**creation_options) kwargs.update( driver=driver, count=output_count) if photometric: kwargs['photometric'] = photometric with rasterio.open(output, 'w', **kwargs) as dst: dst_idx = 1 for path, index in zip(files, indexes): with rasterio.open(path) as src: if isinstance(index, int): data = src.read(index) dst.write(data, dst_idx) dst_idx += 1 elif isinstance(index, collections.Iterable): data = src.read(index) dst.write(data, range(dst_idx, dst_idx + len(index))) dst_idx += len(index) except Exception: logger.exception("Exception caught during processing") raise click.Abort()
def show_hist(source, bins=10, masked=True, title='Histogram'): """Easily display a histogram with matplotlib. Parameters ---------- bins : int, optional Compute histogram across N bins. data : np.array or rasterio.Band or tuple(dataset, bidx) Input data to display. The first three arrays in multi-dimensional arrays are plotted as red, green, and blue. masked : bool, optional When working with a `rasterio.Band()` object, specifies if the data should be masked on read. title : str, optional Title for the figure. """ if plt is None: # pragma: no cover raise ImportError("Could not import matplotlib") if isinstance(source, (tuple, rasterio.Band)): arr = source[0].read(source[1], masked=masked) else: arr = source # The histogram is computed individually for each 'band' in the array # so we need the overall min/max to constrain the plot rng = arr.min(), arr.max() if len(arr.shape) is 2: arr = [arr] colors = ['gold'] else: colors = ('red', 'green', 'blue', 'violet', 'gold', 'saddlebrown') # If a rasterio.Band() is given make sure the proper index is displayed # in the legend. if isinstance(source, (tuple, rasterio.Band)): labels = [str(source[1])] else: labels = (str(i + 1) for i in range(len(arr))) # This loop should add a single plot each band in the input array, # regardless of if the number of bands exceeds the number of colors. # The colors slicing ensures that the number of iterations always # matches the number of bands. # The goal is to provide a curated set of colors for working with # smaller datasets and let matplotlib define additional colors when # working with larger datasets. for bnd, color, label in zip_longest(arr, colors[:len(arr)], labels): plt.hist( bnd.flatten(), bins=bins, alpha=0.5, color=color, label=label, range=rng ) plt.legend(loc="upper right") plt.title(title, fontweight='bold') plt.grid(True) plt.xlabel('DN') plt.ylabel('Frequency') fig = plt.gcf() fig.show()