def test_resample_no_invert_proj(method): """Nearest and bilinear should produce valid results with CHECK_WITH_INVERT_PROJ = False """ if method in (Resampling.bilinear, Resampling.cubic, Resampling.cubic_spline, Resampling.lanczos): pytest.xfail( reason="Some resampling methods succeed but produce blank images. " "See https://github.com/mapbox/rasterio/issues/614") with rasterio.Env(CHECK_WITH_INVERT_PROJ=False): with rasterio.open('tests/data/world.rgb.tif') as src: source = src.read(1) profile = src.profile.copy() dst_crs = {'init': 'EPSG:32619'} # Calculate the ideal dimensions and transformation in the new crs dst_affine, dst_width, dst_height = calculate_default_transform( src.crs, dst_crs, src.width, src.height, *src.bounds) profile['height'] = dst_height profile['width'] = dst_width out = np.empty(shape=(dst_height, dst_width), dtype=np.uint8) # see #614, some resampling methods succeed but produce blank images out = np.empty(src.shape, dtype=np.uint8) reproject( source, out, src_transform=src.transform, src_crs=src.crs, dst_transform=dst_affine, dst_crs=dst_crs, resampling=method) assert out.mean() > 0
def read_write_bigtiff(out_path, pol): """ This method is a proper way to read big GeoTIFF raster data. """ with rasterio.Env(): with rasterio.open("%s%s.tif" % (out_path, pol[0])) as src0: kwargs = src0.profile kwargs.update( count=len(pol), bigtiff="YES", compress="lzw", # Output will be larger than 4GB ) with rasterio.open("%s%s.tif" % (out_path, "stack"), "w", **kwargs) as dst: for b_id, layer in enumerate(pol): src = rasterio.open("%s%s.tif" % (out_path, layer)) windows = src.block_windows(1) for _, window in windows: src_data = src.read(1, window=window) dst.write(src_data, window=window, indexes=b_id + 1) dst.set_band_description(b_id + 1, layer)
def test_reproject_nodata(options, expected): nodata = 215 with rasterio.Env(**options): params = uninvertable_reproject_params() source = np.ones((params.width, params.height), dtype=np.uint8) out = np.zeros((params.dst_width, params.dst_height), dtype=source.dtype) out.fill(120) # Fill with arbitrary value reproject(source, out, src_transform=params.src_transform, src_crs=params.src_crs, src_nodata=nodata, dst_transform=params.dst_transform, dst_crs=params.dst_crs, dst_nodata=nodata) assert (out == 1).sum() == expected assert (out == nodata).sum() == (params.dst_width * params.dst_height - expected)
def test_issue1982(capfd): """See a curl request for overview file""" # Note: the underlying GDAL issue has been fixed after 3.1.3. The # rasterio 1.1.6 wheels published to PyPI will include a patched # 2.4.4 that also fixes the issue. This test will XPASS in the # rasterio-wheels tests. with rasterio.Env(CPL_CURL_VERBOSE=True), rasterio.open( "https://raw.githubusercontent.com/mapbox/rasterio/master/tests/data/green.tif" ) as src: image = src.read( indexes=[1, 2, 3], window=Window(col_off=-32, row_off=-32, width=64, height=64), resampling=Resampling.cubic, boundless=True, out_shape=(3, 10, 10), fill_value=42, ) captured = capfd.readouterr() assert "green.tif" in captured.err assert "green.tif.ovr" in captured.err assert (42 == image[:, :3, :]).all() assert (42 == image[:, :, :3]).all()
def reproject(src, src_trans, dst_trans, dst_shape, _crs, src_nodata=0, dst_nodata=0, dtype=np.uint8): dst = np.empty(dst_shape, dtype=dtype) with rio.Env(): warp.reproject(source=np.ascontiguousarray(src), destination=dst, src_crs=_crs, dst_crs=_crs, dst_transform=dst_trans, src_transform=src_trans, src_nodata=src_nodata, dst_nodata=src_nodata, resampling=enums.Resampling.nearest, num_threads=4) return dst
def main(AHN_pc_file): AHN_pc = read_PC_Data("AHN/" + AHN_pc_file + ".las") interpolation_methods = ["IDW", "NN", "Laplace", "TINlinear"] file_name = "DSM_" + AHN_pc_file[4:] + "_" ff = open("MAE_report_" + AHN_pc_file[4:] + ".txt", "w") for method in interpolation_methods: raster = method + "/" + file_name + method + ".tif" raster_info = read_file(raster) differences_values = calculate_differences(AHN_pc, raster_info[0], raster_info[1], raster_info[2], raster_info[3], raster_info[4]) transform = (Affine.translation(raster_info[2][0], raster_info[2][3]) * Affine.scale(raster_info[1][0], raster_info[1][1])) with rasterio.Env(): with rasterio.open(method + "/" + file_name + 'verticle_differences.tif', 'w', driver='GTiff', height=raster_info[4], width=raster_info[3], count=1, dtype=differences_values.dtype, crs='EPSG:28992', transform=transform) as dst: dst.write(differences_values, 1) abs_sum = 0 for col in range(raster_info[3]): for row in range(raster_info[4]): abs_sum += abs(differences_values[row][col]) N = (raster_info[3] * raster_info[4]) - np.count_nonzero(differences_values == 0) MAE = abs_sum / N ff.write("MAE for " + method + "_" + file_name + " = " + str(MAE) + "\n") print("MAE for " + method + "_" + file_name + " = " + str(MAE))
def main(infile, outfile, num_workers=4): """Process infile block-by-block and write to a new file The output is the same as the input, but with band order reversed. """ with rasterio.Env(): with rasterio.open(infile) as src: # Create a destination dataset based on source params. The # destination will be tiled, and we'll process the tiles # concurrently. profile = src.profile profile.update(blockxsize=128, blockysize=128, tiled=True) with rasterio.open(outfile, "w", **profile) as dst: # Materialize a list of destination block windows # that we will use in several statements below. windows = [window for ij, window in dst.block_windows()] # This generator comprehension gives us raster data # arrays for each window. Later we will zip a mapping # of it with the windows list to get (window, result) # pairs. data_gen = (src.read(window=window) for window in windows) with concurrent.futures.ThreadPoolExecutor( max_workers=num_workers) as executor: # We map the compute() function over the raster # data generator, zip the resulting iterator with # the windows list, and as pairs come back we # write data to the destination dataset. for window, result in zip(windows, executor.map(compute, data_gen)): dst.write(result, window=window)
def raster_to_vector(value_of_interest = 0, raster_file_path = 'raster.asc', output_vector_file = 'buildings.gpkg'): """ Converts a .asc file (or any raster format) to a vector geopackage creating polygons for cells with the given value (default value set to 0) param: value_of_interest: raster value assigned to cells which are to be converted to polygons param: raster_file_path: file path and file name of raster file to convert to a vector layer/file param: output_vector_file: file path and file name of vector file to be saved (as a geopackage) """ # read in raster file mask = None with rasterio.Env(): with rasterio.open(raster_file_path) as src: image = src.read(1) # first band results = ( {'properties': {'raster_val': v}, 'geometry': s} for i, (s, v) in enumerate( shapes(image, mask=mask, transform=src.transform))) # save polygons to a geodataframe polygons = list(results) gpd_polygons = gp.GeoDataFrame.from_features(polygons) # remove any polygons which are not of interest gpd_polygons = gpd_polygons[gpd_polygons.raster_val == value_of_interest] if len(gpd_polygons) == 0: print('Could not export as no cells matched the expected cell value (%s)' %value_of_interest) exit(2) # export file gpd_polygons.to_file(output_vector_file, layer='buildings', driver="GPKG") return
def tiled(sources, equal_blocks=True): """ Tests if raster sources have the same tiling optionally assert that their block sizes are equal (default: True) """ blocksize = None with rasterio.Env(): for source in sources: with rasterio.open(source) as src: if not src.is_tiled: return (False, "Source(s) are not internally tiled") if equal_blocks: this_blocksize = (src.profile['blockxsize'], src.profile['blockysize']) if blocksize: if blocksize != this_blocksize: return (False, "Blocksizes are not equal") else: blocksize = this_blocksize return (True, "Tiling checks out")
def _wmts( url: str = None, tile_format: str = "png", tile_scale: int = 1, title: str = "Cloud Optimizied GeoTIFF", **kwargs: Any, ) -> Tuple[str, str, str]: """Handle /wmts requests.""" if tile_scale is not None and isinstance(tile_scale, str): tile_scale = int(tile_scale) # Remove QGIS arguments kwargs.pop("SERVICE", None) kwargs.pop("REQUEST", None) kwargs.update(dict(url=url)) query_string = urllib.parse.urlencode(list(kwargs.items())) # & is an invalid character in XML query_string = query_string.replace("&", "&") with rasterio.Env(aws_session): with COGReader(url) as cog: info = cog.spatial_info() return ( "OK", "application/xml", wmts_template( app.host, query_string, minzoom=info["minzoom"], maxzoom=info["maxzoom"], bounds=info["bounds"], tile_scale=tile_scale, tile_format=tile_format, title=title, ), )
def fix_mukey(mukey_tif): """The mukey tiff might come out with some odd values around the edges, which makes viewing it a bit tricky. This fixes that.""" mukey_tif = os.path.expanduser(mukey_tif) # For the profile profile = rasterio.open(mukey_tif).profile # For the data array mukey = xr.open_rasterio(mukey_tif, chunks=(1, 5000, 5000)) # Change everything under 0 to the nan value array = mukey.data array[array < 0] = profile["nodata"] with Client(): array = array.compute() # save with rasterio.Env(): with rasterio.open(mukey_tif, "w", **profile) as file: file.write(array[0].astype(rasterio.int32), 1)
def _save_raster(self): transform = rasterio.transform.from_origin( west=self._origin[0], north=self._origin[1], xsize=self._raster_cell_size, ysize=self._raster_cell_size) self._raster = self._raster.astype(np.float32) with rasterio.Env(): with rasterio.open(self._get_save_name(), "w", driver='GTiff', height=self._raster.shape[0], width=self._raster.shape[1], count=1, dtype=str(self._raster.dtype), crs='EPSG:28992', transform=transform, nodata=NO_DATA) as dest: dest.write(self._raster, 1)
def smoosh_rasters(inputRasters, outputRaster, gfs, development): import rasterio import rasterio.env import numpy as np # if isinstance(inputRasters, list): # pass # else: # inputRasters = [inputRasters] rasInfo = list(gribdoctor.loadRasterInfo(b) for b in inputRasters) if abs(rasInfo[0]['affine'].c) > 360 and development == True: gfs = False kwargs = rasInfo[0]['kwargs'] elif development == True: gfs = True snapShape = gribdoctor.getSnapDims(rasInfo) snapSrc = gribdoctor.getSnapAffine(rasInfo, snapShape) allBands = list( gribdoctor.loadBands(b, snapShape, gfs) for b in inputRasters) allBands = list(b for sub in allBands for b in sub) if gfs: zoomFactor = 2 kwargs = gribdoctor.makeKwargs(allBands, snapSrc, snapShape, zoomFactor) else: zoomFactor = 1 kwargs['count'] = len(allBands) kwargs['driver'] = 'GTiff' with rasterio.Env(): with rasterio.open(outputRaster, 'w', **kwargs) as dst: for i, b in enumerate(allBands): dst.write_band(i + 1, b)
def _process_file_stream(src_stream, on_file_cbk, gdal_opts=None, region_name=None, timer=None): session = _session(region_name) if timer is not None: def proc(url, userdata): t0 = timer() with rasterio.open(url, 'r') as f: on_file_cbk(f, userdata, t0=t0) else: def proc(url, userdata): with rasterio.open(url, 'r') as f: on_file_cbk(f, userdata) with rasterio.Env(session=session, **gdal_opts): for userdata, url in src_stream: proc(url, userdata)
def test_issue2202(dx, dy): import rasterio.merge from shapely import wkt from shapely.affinity import translate aoi = wkt.loads( r"POLYGON((11.09 47.94, 11.06 48.01, 11.12 48.11, 11.18 48.11, 11.18 47.94, 11.09 47.94))" ) aoi = translate(aoi, dx, dy) with rasterio.Env(AWS_NO_SIGN_REQUEST=True,): ds = [ rasterio.open(i) for i in [ "/vsis3/copernicus-dem-30m/Copernicus_DSM_COG_10_N47_00_E011_00_DEM/Copernicus_DSM_COG_10_N47_00_E011_00_DEM.tif", "/vsis3/copernicus-dem-30m/Copernicus_DSM_COG_10_N48_00_E011_00_DEM/Copernicus_DSM_COG_10_N48_00_E011_00_DEM.tif", ] ] aux_array, aux_transform = rasterio.merge.merge(datasets=ds, bounds=aoi.bounds) from rasterio.plot import show show(aux_array)
def make_raster_difference(scn_fn1, scn_fn2, dst_fn, nodata=-9999.0): ds = rasterio.open(scn_fn1) ds2 = rasterio.open(scn_fn2) with open(dst_fn + '.log', 'w') as fp: fp.write('scn_fn1 = ' + scn_fn1) fp.write('scn_fn2 = ' + scn_fn2) _data1 = np.ma.masked_values(ds.read(), nodata) _data1 = np.ma.masked_values(_data1, 0) _data1 = np.ma.masked_values(_data1, 1) _data2 = np.ma.masked_values(ds2.read(), nodata) _data2 = np.ma.masked_values(_data2, 0) _data2 = np.ma.masked_values(_data2, 1) if not _data1.shape == _data2.shape: transformed_scn_fn2 = scn_fn2[:-4] + '.x.tif' transform_to_template_ds(scn_fn1, scn_fn2, transformed_scn_fn2) return make_raster_difference(scn_fn1, transformed_scn_fn2, dst_fn, nodata) data = (_data2[0, :, :] - _data1[0, :, :]) / _data1[0, :, :] if isinstance(data, np.ma.core.MaskedArray): data.fill_value = nodata _data = data.filled() else: _data = data with rasterio.Env(): profile = ds.profile profile.update(dtype=rasterio.float32, count=1, nodata=nodata, compress='lzw') with rasterio.open(dst_fn, 'w', **profile) as dst: dst.write(_data.astype(rasterio.float32), 1)
def wrapped_f(*args, **kwargs): """Wrapped functions.""" rio_stream = StringIO() logger = logging.getLogger("rasterio") logger.setLevel(logging.DEBUG) handler = logging.StreamHandler(rio_stream) logger.addHandler(handler) gdal_config = config or {} gdal_config.update({"CPL_DEBUG": "ON", "CPL_CURL_VERBOSE": "TRUE"}) with pipes() as (_, curl_stream): with rasterio.Env(**gdal_config): with Timer() as t: retval = func(*args, **kwargs) logger.removeHandler(handler) handler.close() rio_lines = rio_stream.getvalue().splitlines() curl_lines = curl_stream.read().splitlines() results = analyse_logs(rio_lines, curl_lines) results["Timing"] = t.elapsed if not kernels: results.pop("WarpKernels") if raw: results["curl"] = curl_lines results["rasterio"] = rio_lines if not quiet: log.info(json.dumps(results)) if add_to_return: return retval, results return retval
def test_shapes(basic_image): """Test creation of shapes from pixel values.""" with rasterio.Env(): results = list(shapes(basic_image)) assert len(results) == 2 shape, value = results[0] assert shape == { 'coordinates': [[(2, 2), (2, 5), (5, 5), (5, 2), (2, 2)]], 'type': 'Polygon' } assert value == 1 shape, value = results[1] assert shape == { 'coordinates': [[(0, 0), (0, 10), (10, 10), (10, 0), (0, 0)], [(2, 2), (5, 2), (5, 5), (2, 5), (2, 2)]], 'type': 'Polygon' } assert value == 0
def test_reproject_nodata(): params = default_reproject_params() nodata = 215 with rasterio.Env(): source = np.ones((params.width, params.height), dtype=np.uint8) out = np.zeros((params.dst_width, params.dst_height), dtype=source.dtype) out.fill(120) # Fill with arbitrary value reproject(source, out, src_transform=params.src_transform, src_crs=params.src_crs, src_nodata=nodata, dst_transform=params.dst_transform, dst_crs=params.dst_crs, dst_nodata=nodata) assert (out == 1).sum() == 6215 assert (out == nodata).sum() == (params.dst_width * params.dst_height - 6215)
def pointArea(lat, lon, loc): mask = None with rasterio.Env(): with rasterio.open(loc) as src: #input the classified image image = src.read(1) # first band results = ({ 'properties': { 'raster_val': v }, 'geometry': s } for i, (s, v) in enumerate( shapes(image, mask=mask, transform=src.transform))) geoms = list(results) #input the coordinates of the point. must be utm coordinates point = Point(lat, lon) gpd = gp.GeoDataFrame.from_features(geoms) gpd.crs = {'init': 'epsg:32643'} water_pol = gpd.loc[gpd['raster_val'] == 1] water_pol.crs = {'init': 'epsg:32643'} water_pol["area"] = water_pol['geometry'].area #save the geojson to a location. water_pol.to_file( "C:/Users/risha/waterbudgeting/water_pol_konambe.geojson", driver="GeoJSON") #read geojson with open("C:/Users/risha/waterbudgeting/water_pol_konambe.geojson") as f: js = geojson.load(f) #find polygon which contains the point for feature in js['features']: polygon = shape(feature['geometry']) if polygon.contains(point): print('Water area:', feature['properties']['area']) return feature['properties']['area']
def test_reproject_dst_nodata_default(options, expected): """If nodata is not provided, destination will be filled with 0.""" with rasterio.Env(**options): params = uninvertable_reproject_params() source = np.ones((params.width, params.height), dtype=np.uint8) out = np.zeros((params.dst_width, params.dst_height), dtype=source.dtype) out.fill(120) # Fill with arbitrary value reproject( source, out, src_transform=params.src_transform, src_crs=params.src_crs, dst_transform=params.dst_transform, dst_crs=params.dst_crs ) assert (out == 1).sum() == expected assert (out == 0).sum() == (params.dst_width * params.dst_height - expected)
def tileserver_optimized_raster(src, dest): """ This method converts a raster to a tileserver optimized raster. The method will reproject the raster to align to the xyz system, in resolution and projection It will also create overviews And finally it will arragne the raster in a cog way. You could take the dest file upload it to a web server that supports ranges and user GeoRaster.get_tile on it, You are geranteed that you will get as minimal data as possible """ src_raster = tl.GeoRaster2.open(src) bounding_box = src_raster.footprint().get_shape(tl.constants.WGS84_CRS).bounds tile = mercantile.bounding_tile(*bounding_box) dest_resolution = mercator_upper_zoom_level(src_raster) bounds = tl.GeoVector.from_xyz(tile.x, tile.y, tile.z).get_bounds(tl.constants.WEB_MERCATOR_CRS) create_options = { "tiled": "YES", "blocksize": 256, "compress": "DEFLATE", "photometric": "MINISBLACK" } with TemporaryDirectory() as temp_dir: temp_file = os.path.join(temp_dir, 'temp.tif') warp(src, temp_file, dst_crs=tl.constants.WEB_MERCATOR_CRS, resolution=dest_resolution, dst_bounds=bounds, create_options=create_options) with rasterio.Env(GDAL_TIFF_INTERNAL_MASK=True, GDAL_TIFF_OVR_BLOCKSIZE=256): resampling = rasterio.enums.Resampling.gauss with rasterio.open(temp_file, 'r+') as tmp_raster: factors = _calc_overviews_factors(tmp_raster) tmp_raster.build_overviews(factors, resampling=resampling) tmp_raster.update_tags(ns='rio_overview', resampling=resampling.name) telluric_tags = _get_telluric_tags(src) if telluric_tags: tmp_raster.update_tags(**telluric_tags) rasterio_sh.copy(temp_file, dest, COPY_SRC_OVERVIEWS=True, tiled=True, compress='DEFLATE', photometric='MINISBLACK')
def get_subset(fkey, features): import numpy as np # import pandas as pd import rasterio from rasterio.mask import mask from rasterio.session import AWSSession s3host_ = S3HOST.replace('http://', '') s3host_ = s3host_.replace('https://', '') session = connection('session') with rasterio.Env(AWSSession(session), AWS_S3_ENDPOINT=s3host_, AWS_HTTPS='NO', AWS_VIRTUAL_HOSTING=False) as env: with rasterio.open('/vsis3/{}/{}'.format(BUCKET, fkey)) as src: out_image, out_transform = mask(src, features, crop=True, pad=False, all_touched=False) # print('--out_image.shape: ', out_image.shape) w_5 = np.percentile(out_image, 5.0) w_95 = np.percentile(out_image, 95.0) # print('--w_5, w_95: ', w_5, w_95) chip_set = np.clip(255 * (out_image - w_5) /(w_95 - w_5), 0, 255).astype(np.uint16) return chip_set, out_transform
def __init__(self, file): """Open the file. Parameters ---------- file: path to the file """ if rasterio is None: raise ImportError('This feature needs rasterio to be insalled') # brutally efficient with rasterio.Env(): with rasterio.open(file) as src: nxny = (src.width, src.height) ul_corner = (src.bounds.left, src.bounds.top) proj = pyproj.Proj(src.crs) dxdy = (src.res[0], -src.res[1]) grid = Grid(x0y0=ul_corner, nxny=nxny, dxdy=dxdy, pixel_ref='corner', proj=proj) # done self.file = file GeoDataset.__init__(self, grid)
def geotiff_writer(filename, trans, dst_crs, shape, n_bands, dtype=np.uint8, nodata=0): """writes the raster as a multiband geotiff returns an open geotiff writer """ with rio.Env(): with rio.open(filename, 'w', driver='GTiff', width=shape[1], height=shape[0], count=n_bands, dtype=dtype, nodata=nodata, transform=trans, crs=dst_crs) as f: yield f
def clip(self, tile: Tile): """ Clips this raster according to the size of original geometry of the tile provided :param tile: Tile element corresponding with this raster :return: None """ try: self.open() except Exception: return False clip_geom = tile.get_unbuffered_geometry() clip_height = clip_geom.bounds[3] - clip_geom.bounds[1] # maxy - miny clip_width = clip_geom.bounds[2] - clip_geom.bounds[0] # maxx - minx try: print(self._raster_name, clip_geom) out_image, out_transform = mask(dataset=self._raster, shapes=[clip_geom], crop=True) out_meta = self._raster.meta.copy() self.close() out_meta.update({ "driver": "GTiff", "height": clip_height / self._base_raster_cell_size, "width": clip_width / self._base_raster_cell_size, "transform": out_transform, }) with rasterio.Env(): with rasterio.open(self.filepath, "w", **out_meta) as dest: dest.write(out_image) except Exception as e: print(e) return False
def fetch_meta(self) -> Tuple[BoundingBox, Dict[str, Any]]: """Open file to fetch metadata.""" LOGGER.debug(f"Fetch metadata data for file {self.url} if exists") try: with rasterio.Env(**GDAL_ENV), rasterio.open(self.url) as src: LOGGER.info(f"File {self.url} exists") return src.bounds, src.profile except Exception as e: if _file_does_not_exist(e): LOGGER.info(f"File does not exist {self.url}") raise FileNotFoundError(f"File does not exist: {self.url}") elif isinstance(e, rasterio.RasterioIOError): LOGGER.warning( f"RasterioIO Error while opening {self.url}. Will make attempts to retry" ) raise else: LOGGER.exception(f"Cannot open file {self.url}") raise
def loadRaster(filePath, bands, bounds): """ """ # with rasterio.drivers(): import rasterio import rasterio.env with rasterio.Env(): with rasterio.open(filePath, 'r') as src: oaff = src.transform upperLeft = src.index(bounds.left, bounds.top) lowerRight = src.index(bounds.right, bounds.bottom) filler = np.zeros((lowerRight[0] - upperLeft[0], lowerRight[1] - upperLeft[1])) - 999 return np.dstack( list( src.read(i[1], boundless=True, out=filler, window=((upperLeft[0], lowerRight[0]), (upperLeft[1], lowerRight[1]))) for i in bands)), oaff
def _profile(data, nx, ny, bands=1, bounds=None): """ Profile for writing depth and gradient. Dtype and band count needs to be set depending on data. """ if bounds is not None: l, b, r, t = bounds else: l, b = np.min(data[:, 0]), np.min(data[:, 1]) r, t = np.max(data[:, 0]), np.max(data[:, 1]) with rasterio.Env(): profile = rasterio.profiles.DefaultGTiffProfile() transform = rasterio.transform.from_bounds(l, b, r, t, nx, ny) profile.update(crs=CRS, transform=transform, width=nx, height=ny, count=bands, dtype=data.dtype) return profile
def run(multi_band_file, swir_file, out_fn, green_fn, s3_fn, px_res, p_name): if (multi_band_file is not None) & (swir_file is not None): green_arr, prf, g_ndv = read_file(multi_band_file[:-4] + "_b3_" + p_name + "_refl.tif") swir3_arr, _, swir3_ndv = read_file(swir_file[:-4] + "_b3_" + p_name + "_refl.tif") elif (green_fn is not None) & (s3_fn is not None): green_arr, prf, g_ndv = read_file(green_fn) swir3_arr, _, swir3_ndv = read_file(s3_fn) else: sys.exit("Check input files, missing proper input") ndsi_3, ndsi_3_norm = calc_ndsi(green_arr, swir3_arr, g_ndv, swir3_ndv) # Write NDSI arrays to file with rio.Env(): prf.update( dtype=rio.float32, count=1, compress='lzw') with rio.open(out_fn, 'w', **prf) as dst: dst.write(np.squeeze(ndsi_3).astype(rio.float32), 1) with rio.open(out_fn[:-4]+"_minmax.tif", 'w', **prf) as dst: dst.write(np.squeeze(ndsi_3_norm).astype(rio.float32), 1)