def vectorize_prediction_map(prediction_map): image_1001 = prediction_map.read(1) image_1005 = prediction_map.read(2) results_1001 = ({ 'properties': { 'raster_val': v }, 'geometry': s } for i, (s, v) in enumerate( shapes(image_1001, mask=None, transform=prediction_map.transform))) results_1005 = ({ 'properties': { 'raster_val': v }, 'geometry': s } for i, (s, v) in enumerate( shapes(image_1005, mask=None, transform=prediction_map.transform))) geoms_1001 = list(results_1001) geoms_1005 = list(results_1005) gpd_polygonized_raster_1001 = gpd.GeoDataFrame.from_features(geoms_1001) gpd_polygonized_raster_1005 = gpd.GeoDataFrame.from_features(geoms_1005) gpd_polygonized_raster_1001['Species'] = 1001 gpd_polygonized_raster_1005['Species'] = 1005 df_prediction = pd.concat( [gpd_polygonized_raster_1001, gpd_polygonized_raster_1005]).drop(columns=['raster_val']) return df_prediction
def array_to_polygons(array, affine=None): """ Returns a geopandas dataframe of polygons as deduced from an array. :param array: The 2D numpy array to polygonize. :param affine: The affine transformation. :return: """ if affine == None: results = [{ 'properties': { 'raster_val': v }, 'geometry': s } for i, (s, v) in enumerate(shapes(array))] else: results = [{ 'properties': { 'raster_val': v }, 'geometry': s } for i, (s, v) in enumerate(shapes(array, transform=affine))] tops_df = geopandas.GeoDataFrame({ 'geometry': [shape(results[geom]['geometry']) for geom in range(len(results))], 'raster_val': [ results[geom]['properties']['raster_val'] for geom in range(len(results)) ] }) return (tops_df)
def test_shapes_blank_mask(basic_image): """Mask is blank so results should mask shapes without mask.""" assert np.array_equal( list( shapes(basic_image, mask=np.ones(basic_image.shape, dtype=rasterio.bool_))), list(shapes(basic_image)))
def test_shapes_blank_mask(basic_image): """Mask is blank so results should mask shapes without mask.""" assert np.array_equal( list(shapes( basic_image, mask=np.ones(basic_image.shape, dtype=rasterio.bool_)) ), list(shapes(basic_image)) )
def test_shapes_band(pixelated_image, pixelated_image_file): """Shapes from a band should match shapes from an array.""" truth = list(shapes(pixelated_image)) with rasterio.open(pixelated_image_file) as src: band = rasterio.band(src, 1) assert truth == list(shapes(band)) # Mask band should function, but will mask out some results assert truth[0] == list(shapes(band, mask=band))[0]
def test_shapes_blank_mask(basic_image): """ Mask is blank so results should mask shapes without mask """ with rasterio.drivers(): assert numpy.array_equal( list(shapes( basic_image, mask=numpy.ones(basic_image.shape, dtype=rasterio.bool_)) ), list(shapes(basic_image)) )
def get_shapes_from_raster(raster, mask_file, daymaps=False): shapes_with_properties = [] # crs, transform, area_shape = area2transform_baws300_sweref99tm() crs, transform, area_shape = area2transform_baws1000_sweref99tm() classes = {int(cls): {'class': int(cls)} for cls in np.unique(raster)} classes[0] = None if mask_file: with fiona.open(mask_file, "r") as shapefile: mask_features = [feature["geometry"] for feature in shapefile] mask = rasterize(mask_features, area_shape, transform=transform) else: mask = None if daymaps: covered = False for i, (s, v) in enumerate( shapes(raster, mask=mask, transform=transform)): if v != 4: covered = True if v in [0, 1, 4]: continue shapes_with_properties.append({ 'properties': classes[int(v)], 'geometry': s }) if not covered: return None # Clouds ontop! for i, (s, v) in enumerate(shapes(raster, transform=transform)): if v in [0, 2, 3]: continue shapes_with_properties.append({ 'properties': classes[int(v)], 'geometry': s }) else: covered = False for i, (s, v) in enumerate( shapes(raster, mask=mask, transform=transform)): if v == 0: continue shapes_with_properties.append({ 'properties': classes[int(v)], 'geometry': s }) return shapes_with_properties
def snap(dataurl, out_url, out_url2): wbt = whitebox.WhiteboxTools() wbt.set_verbose_mode(False) wbt.work_dir = out_url wbt.snap_pour_points("point.shp", "Flow_acc.tif", "snap_point.shp", snap_dist=0.01) wbt.watershed("Flow_dir.tif", "snap_point.shp", "Watershed.tif") # wbt.longest_flowpath("DEM_fill.tif","Watershed.tif",'LongestFlowpath.shp') # wbt.raster_to_vector_lines("Watershed.tif","Watershed.shp") # Convert basin raster file to polygon mask = None with rasterio.open(os.path.join(out_url, "Watershed.tif")) 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))) geoms = list(results) boundary = shapes(geoms[0]['geometry']) gpd_polygonized_raster = gpd.GeoDataFrame.from_features(geoms) # Filter nodata value gpd_polygonized_raster = gpd_polygonized_raster[ gpd_polygonized_raster['raster_val'] == 1] # Convert to geojson boundary = gpd_polygonized_raster.to_json() gpd_polygonized_raster.to_file(driver='ESRI Shapefile', filename=os.path.join( out_url, "basin_boundary.shp")) wbt.clip_raster_to_polygon("DEM_out.tif", "basin_boundary.shp", "DEM_watershed.tif") wbt.hypsometric_analysis("DEM_watershed.tif", "hypso.html") wbt.slope_vs_elevation_plot("DEM_watershed.tif", "Slope_elevation.html") wbt.extract_raster_statistics("DEM_out.tif", "Watershed.tif", output=None, stat="total", out_table="stat.html") wbt.raster_histogram("DEM_watershed.tif", "hist.html") X, Y = hyspoparser.hypso(os.path.join(out_url, "hypso.html")) stat = hyspoparser.stat(os.path.join(out_url, "stat.html")) return boundary, X, Y, stat
def test_shapes_dtype(): """Test image data type handling""" rows = cols = 10 with rasterio.drivers(): supported_types = (('int16', -32768), ('int32', -2147483648), ('uint8', 255), ('uint16', 65535), ('float32', 1.434532)) for dtype, test_value in supported_types: image = numpy.zeros((rows, cols), dtype=dtype) image[2:5, 2:5] = test_value shapes = ftrz.shapes(image) shape, value = next(shapes) if dtype == 'float32': assert round(value, 6) == round(test_value, 6) else: assert value == test_value # Unsupported types should all raise exceptions unsupported_types = (('int8', -127), ('uint32', 4294967295), ('int64', 20439845334323), ('float16', -9343.232), ('float64', -98332.133422114)) for dtype, test_value in unsupported_types: with pytest.raises(ValueError): image = numpy.zeros((rows, cols), dtype=dtype) image[2:5, 2:5] = test_value shapes = ftrz.shapes(image) next(shapes) # Test mask types image = numpy.zeros((rows, cols), dtype='uint8') image.fill(255) supported_mask_types = (('bool', 1), ('uint8', 255)) for dtype, mask_value in supported_mask_types: mask = numpy.zeros((rows, cols), dtype=dtype) mask[2:5, 2:5] = mask_value shapes = ftrz.shapes(image, mask=mask) shape, value = next(shapes) assert value == 255 unsupported_mask_types = (('int8', -127), ('int16', -32768)) for dtype, mask_value in unsupported_mask_types: with pytest.raises(ValueError): mask = numpy.zeros((rows, cols), dtype=dtype) mask[2:5, 2:5] = mask_value shapes = ftrz.shapes(image, mask=mask) next(shapes)
def test_shapes_connectivity_rook(diagonal_image): """ Diagonals are not connected, so there will be 1 feature per pixel plus background. """ with rasterio.Env(): assert len(list(shapes(diagonal_image, connectivity=4))) == 12
def test_shapes_internal_driver_manager(): """Access to shapes of labeled features""" image = numpy.zeros((20, 20), dtype=rasterio.ubyte) image[5:15,5:15] = 127 shapes = ftrz.shapes(image) shape, val = next(shapes) assert shape['type'] == 'Polygon'
def test_shapes_invalid_mask_dtype(basic_image): """A mask that is the wrong dtype should fail.""" for dtype in ('int8', 'int16', 'int32'): with pytest.raises(ValueError): next( shapes(basic_image, mask=np.ones(basic_image.shape, dtype=dtype)))
def test_shapes_connectivity_queen(diagonal_image): """ Diagonals are connected, so there will be 1 feature for all pixels plus background. """ with rasterio.Env(): assert len(list(shapes(diagonal_image, connectivity=8))) == 2
def polygonize(input_path): with rasterio.open(input_path, mode='r+') as src: print("Polygonizing GeoTIFF") # from https://stackoverflow.com/questions/17615963/standard-rgb-to-grayscale-conversion r = src.read(1) g = src.read(2) b = src.read(3) rgb = (r * 256 ** 2) + g * 256 + b rgb = rgb.astype('float32') # Make a mask # mask = grayscale != 1 # iterate over shapes. results = ( {'properties': {'raster_val': v}, 'geometry': s} for i, (s, v) in enumerate(features.shapes(rgb, transform=src.transform))) with fiona.open( 'GOES17_Poly' '.json', 'w', driver='GeoJSON', crs=src.crs.wkt, schema={'properties': [('raster_val', 'int')], 'geometry': 'Polygon'}) as dst: dst.writerecords(results) print("Successfully polygonized GeoTIFF to JSON") return
def test_shapes(basic_image): """ Test creation of shapes from pixel values """ with 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 raster_shape(raster_path): if not os.path.exists(raster_path): print "File does not exist: %s" % raster_path with rasterio.open(raster_path) as src: # read the first band and create a binary mask arr = src.read(1) ndv = src.nodata binarray = (arr == ndv).astype('uint8') # extract shapes from raster shapes = features.shapes(binarray, transform=src.transform) # create geojson feature collection fc = { 'type': 'FeatureCollection', 'features': []} for geom, val in shapes: if val == 0: # not nodata, i.e. valid data feature = { 'type': 'Feature', 'properties': {'name': raster_path}, 'geometry': geom} fc['features'].append(feature) # Write to file with NamedTemporaryFile(suffix=".geojson", delete=False) as temp: temp.file.write(json.dumps(fc)) return temp.name
def polygonize(self, crs_out="+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs"): """Transform the raster result of a segmentation to a feature collection Args: crs_out (proj4): The coordinate reference system of the feature collection produced. Defaults to longlat, can be None if no reprojection is needed """ if self.segments_array is None: raise ValueError("self.segments_array is None, you must run segment before this method") # Use rasterio.features.shapes to generate a geometries collection from the # segmented raster geom_collection = features.shapes(self.segments_array.astype(np.uint16), transform=self.affine) # Make it a valid featurecollection def to_feature(feature): """Tranforms the results of rasterio.feature.shape to a feature""" fc_out = { "type": "Feature", "geometry": { "type": feature[0]['type'], "coordinates": feature[0]['coordinates'] }, "properties": { "id": feature[1] } } return fc_out fc_out = (to_feature(x) for x in geom_collection) if crs_out is not None: fc_out = (feature_transform(x, crs_out=crs_out, crs_in=self.crs) for x in fc_out) self.fc = fc_out
def build_map(tiles_dir, preds_dir, map_dir, fn, truths): input_img_paths = sorted([ os.path.join(preds_dir, fname) for fname in os.listdir(preds_dir) if fname.endswith(".png") ]) print('\nConverting predictions to .GEOTIFF & extracting polygons as .SHP') for i in range(len(input_img_paths)): img = Image.open(input_img_paths[i]) img_arr = np.array(img) ### convert prediction tile to geotiff using original geotiff metadata tif_number = get_name(input_img_paths[i]) Gtif = tiles_dir + '/%s.tif' % tif_number raster = rasterio.open(Gtif) meta = raster.meta.copy() meta['nodata'] = 0 # meta['count'] = 1 saved_mask = preds_dir + '/%s.tif' % tif_number with rasterio.open(saved_mask, 'w+', **meta) as out: # out.write(img_arr.astype(rasterio.uint8), 1) # out.write(img_arr.astype(rasterio.uint8), 2) out.write(img_arr.astype(rasterio.uint8), 3) ### visulaize in blue with rasterio.open(saved_mask) as data: crs = data.crs M = data.dataset_mask() mask = M != 0 geo_list = [] for g, val in features.shapes(M, transform=data.transform, mask=mask): # Transform shapes from the dataset's own coordinate system geom = rasterio.warp.transform_geom(crs, crs, g, precision=6) geo_list.append(geom) l = [] for k in range(len(geo_list)): l.append(shape(geo_list[k])) if len(l) > 0: df = pd.DataFrame(l) polys = gpd.GeoDataFrame(geometry=df[0], crs=crs) polys.to_file(map_dir + '/%s.shp' % tif_number) print('\n.GEOTIFF & .SHP files saved in Predictions & Map directories.') print('\nBuilding Map...') if combine_shps(map_dir, fn, truths): return True else: return False
def raster_to_geodataframe(raster_data: np.ndarray, transform: affine.Affine) -> gpd.GeoDataFrame: ''' Given an array of raster data and the transform, creates the correponsding vector reprseentation of the data ''' geom_types = {'Polygon': Polygon} geom_type_multi = {'Polygon': MultiPolygon} if raster_data.dtype == np.float64: raster_data = raster_data.astype(np.float32) shape_gen = list(features.shapes(raster_data, transform=transform)) gdf_data = {'geometry': [], 'data': []} for geom_dict, val in shape_gen: geom_type = geom_types[geom_dict['type']] multi_type = geom_type_multi[geom_dict['type']] coords = geom_dict['coordinates'] if len(coords) <= 1: geom = geom_type(*coords) else: # This can be done better geom = multi_type( [geom_type(coords[i]) for i in range(len(coords))]) gdf_data['geometry'].append(geom) gdf_data['data'].append(val) return gpd.GeoDataFrame(gdf_data)
def polygonize(input_tif_dir, output_shp_dir, countries): rm_and_mkdir(output_shp_dir) for country in countries: shp_filename = country + '.shp' output_shp_path = os.path.join(output_shp_dir, shp_filename) tif_filename = country + '.tif' input_tif_path = os.path.join(input_tif_dir, tif_filename) with rasterio.open(input_tif_path) as src: band = src.read(1) mask = band != 255 shapes = features.shapes(band, mask=mask, transform=src.transform) geomvals = list(shapes) geom_val_trios = [] for idx, geom_val in enumerate(geomvals): shapely_geom = shape(geomvals[idx][0]) shapely_val = geomvals[idx][1] geom_val_trio = [shapely_geom, shapely_val, country] geom_val_trios.append(geom_val_trio) gdf = gpd.GeoDataFrame(geom_val_trios, columns={'geometry', 'val', 'country'}) gdf.crs = {'init': 'epsg:4326', 'no_defs': True} gdf.to_file(output_shp_path)
def __mask_to_polys(mask): """[summary] Args: mask ([type]): [description] Returns: [type]: [description] """ import numpy as np import pandas as pd from rasterio import features from shapely import ops, geometry shapes = features.shapes(mask.astype(np.int16), mask > 0) mp = ops.cascaded_union( geometry.MultiPolygon( [geometry.shape(shape) for shape, value in shapes])) if isinstance(mp, geometry.Polygon): polygon_gdf = pd.DataFrame({ 'geometry': [mp], }) else: polygon_gdf = pd.DataFrame({ 'geometry': [p for p in mp], }) return polygon_gdf
def raster_shape(raster_path): with rasterio.open(raster_path) as src: # read the first band and create a binary mask arr = src.read(1) ndv = src.nodata binarray = (arr == ndv).astype('uint8') # extract shapes from raster shapes = features.shapes(binarray, transform=src.transform) # create geojson feature collection fc = { 'type': 'FeatureCollection', 'features': []} for geom, val in shapes: if val == 0: # not nodata, i.e. valid data feature = { 'type': 'Feature', 'properties': {'name': raster_path}, 'geometry': geom} fc['features'].append(feature) # Write to file with NamedTemporaryFile(suffix=".geojson", delete=False) as temp: temp.file.write(json.dumps(fc)) return temp.name
def extract_polygon(mask_tif_path): """Extracts polygon to a geojson dict Args: mask_tif_path (str): path to tif to extract geojson from Returns: str: path to geojson file """ with rasterio.open(mask_tif_path, 'r') as src: raster = src.read(1) src_crs = Proj(init=src.crs.get('init')) src_affine = src.affine mask = np.ma.masked_equal(raster, 0) geoms = shapes(raster, mask=mask, transform=src_affine) footprint, value = geoms.next() assert value == 1.0, 'Geometry should be of value 1' target_crs = Proj(init='epsg:4326') feature = transform_polygon_coordinates(footprint, src_crs, target_crs) feature_collection = { 'type': 'FeatureCollection', 'features': [{ 'type': 'Feature', 'geometry': feature, 'properties': { 'value': value } }] } return feature_collection
def raster_to_shape(in_dir, out_dir, img_name): file_name = in_dir + img_name mask = None with rasterio.open(file_name) 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))) geoms = list(results) gpd_polygonized_raster = gp.GeoDataFrame.from_features(geoms) gpd_polygonized_raster["single_val"] = 1 gpd_polygonized_raster = gpd_polygonized_raster.dissolve(by="single_val") gpd_polygonized_raster.crs = src.crs shape_name = img_name.replace(".tif", ".shp") gpd_polygonized_raster.to_file(out_dir + shape_name)
def main(raster_file, vector_file, driver, mask_value): with rasterio.drivers(): with rasterio.open(raster_file) as src: image = src.read_band(1) if mask_value is not None: mask = image == mask_value else: mask = None results = ({ 'properties': { 'raster_val': v }, 'geometry': s } for i, ( s, v) in enumerate(shapes(image, mask=mask, transform=src.transform))) with fiona.open(vector_file, 'w', driver=driver, crs=src.crs, schema={ 'properties': [('raster_val', 'int')], 'geometry': 'Polygon' }) as dst: dst.writerecords(results) return dst.name
def clump(data): '''Contiguous groups of cells with the same value (‘clumps’)' Parameters ---------- data: Numpy array with no-data cells as nan (np.NaN). returns ---------- Numpy array with the data for which clumps are to be returned ''' if not np.isnan(np.sum(data)): logging.warning( "convert no-data cells to np.NaN before using clump. If not, no-data cells will be clumped too" ) #data = data * 0 + 1 mask = data.copy() mask = mask * 0 + 1 mask[np.isnan(mask)] = 0 mask = mask.astype(np.bool) geoms = [ (shape(s), idx) for idx, (s, v) in enumerate(shapes(data.astype(np.int32), mask=mask)) ] clumps = rasterio.features.rasterize(geoms, out_shape=data.shape, fill=-999) return np.where(clumps == -999, np.NaN, clumps)
def polygonize(self, band_number=1): """ Extract shapes from raster features. This is the inverse operation of rasterizing shapes. Uses the `Rasterio <https://mapbox.github.io/rasterio/_modules/rasterio/features.html>'_ library for this purpose. The data is loaded into a `geopandas <http://geopandas.org/user.html>`_ GeoDataFrame. GeoDataFrame data structures are pandas DataFrames with added functionality, containing a ``geometry`` column for the `Shapely <http://toblerity.org/shapely/shapely.geometry.html>`_ geometries. The raster data should be loaded in the layer before calling this method. :param int band_number: The index of the raster band which is to be used as input for extracting \ gemetrical shapes. :returns: geopandas.GeoDataFrame """ raster_data = self.read(band_number) mask = raster_data != self.raster_reader.nodata T0 = self.raster_reader.affine shapes = features.shapes(raster_data, mask=mask, transform=T0) df = GeoDataFrame.from_records(shapes, columns=['geometry', 'value']) # convert the geometry dictionary from a dictionary format like {'coordinates': [[(-73.5, 83.5), # (-73.5, 83.0), # (-68.0, 83.0), # (-68.0, 83.5), # (-73.5, 83.5)]], # 'type': 'Polygon'} # to a proper shapely polygon format df.geometry = df.geometry.apply(lambda row: Polygon(row['coordinates'][0])) df.crs = self.raster_reader.crs return df
def extract_polygon(mask_tif_path): """Extracts polygon to a geojson dict Args: mask_tif_path (str): path to tif to extract geojson from Returns: str: path to geojson file """ with rasterio.open(mask_tif_path, 'r') as src: raster = src.read(1) src_crs = Proj(init=src.crs.get('init')) src_affine = src.affine mask = np.ma.masked_equal(raster, 0) geoms = shapes(raster, mask=mask, transform=src_affine, connectivity=8) footprint, value = geoms.next() assert value == 1.0, 'Geometry should be of value 1' target_crs = Proj(init='epsg:4326') feature = transform_polygon_coordinates(footprint, src_crs, target_crs) return {'type': 'MultiPolygon', 'coordinates': [feature['coordinates']]}
def VectorizeTile(axis, row, col, params): """ DOCME """ rasterfile = params.watershed_raster.tilename(axis=axis, row=row, col=col) # config.tileset().tilename( # 'ax_watershed_raster', # axis=axis, # row=row, # col=col) if os.path.exists(rasterfile): with rio.open(rasterfile) as ds: watershed = ds.read(1) transform = ds.transform polygons = features.shapes(watershed, connectivity=4, transform=transform) return [polygon for polygon, value in polygons if value == axis], row, col else: return [], row, col
def __mask_to_polygons(mask): """[summary] Args: mask ([type]): [description] Returns: [type]: [description] """ # XXX: maybe this should be merged with __mask_to_polys() defined above import numpy as np from rasterio import features, Affine from shapely import geometry all_polygons = [] for shape, value in features.shapes(mask.astype(np.int16), mask=(mask > 0), transform=Affine(1.0, 0, 0, 0, 1.0, 0)): all_polygons.append(geometry.shape(shape)) all_polygons = geometry.MultiPolygon(all_polygons) if not all_polygons.is_valid: all_polygons = all_polygons.buffer(0) # Sometimes buffer() converts a simple Multipolygon to just a Polygon, # need to keep it a Multi throughout if all_polygons.type == 'Polygon': all_polygons = geometry.MultiPolygon([all_polygons]) return all_polygons
def test_shapes_internal_driver_manager(): """Access to shapes of labeled features""" image = numpy.zeros((20, 20), dtype=rasterio.ubyte) image[5:15, 5:15] = 127 shapes = ftrz.shapes(image) shape, val = next(shapes) assert shape['type'] == 'Polygon'
def get_data_polygon(rasterfile): import rasterio from rasterio.features import shapes from shapely.geometry import shape r = Raster(rasterfile) array = np.array(r.array.mask * 1, dtype=np.int16) # with rasterio.drivers(): with rasterio.open(rasterfile) as src: image = src.read(1) mask_array = image != src.nodata # https://github.com/mapbox/rasterio/issues/86 if isinstance(src.transform, Affine): transform = src.transform else: transform = src.affine # for compatibility with rasterio 0.36 results = ({ 'properties': { 'raster_val': v }, 'geometry': s } for i, (s, v) in enumerate( shapes(array, mask=mask_array, transform=transform))) geoms = list(results) polygons = [shape(geom['geometry']) for geom in geoms] return polygons
def polygonize_raster(infile, outfile, mask_value=1, driver='ESRI Shapefile'): with rasterio.open(infile) as src: image = src.read(1) if mask_value is not None: mask = image == mask_value else: mask = None results = ( {'properties': {'raster_val': v}, 'geometry': s} for i, (s, v) in enumerate( shapes(image, mask=mask, transform=src.transform))) with fiona.open( outfile, 'w', driver=driver, crs=src.crs, schema={'properties': [('raster_val', 'int')], 'geometry': 'Polygon'}) as dst: dst.writerecords(results)
def raster_bounds(path): ''' Gets boundary of raster at path, ignoring no data values ''' print('Getting raster bounds...') with rasterio.drivers(): with rasterio.open(path) as src: # Raster band rb = src.read(1) nodata = src.nodatavals[0] # Array of 1's and 0's binary = np.where(rb <= nodata, 0, 1) # Array True, False mask = np.where(binary == 1, True, False) ## Create a dictionary of raster values and geometries, where ## the geometries are based on grouping the values in the binary array ## and ignoring the False values in the mask geoms = list(({ 'properties': { 'raster_val': value }, 'geometry': shp } for i, (shp, value) in enumerate( shapes(binary, mask=mask, transform=src.affine)))) bb = shape(geoms[0]['geometry']) return bb
def union(inputtiles, parsenames): tiles = sutils.tile_parser(inputtiles, parsenames) xmin, xmax, ymin, ymax = sutils.get_range(tiles) zoom = sutils.get_zoom(tiles) # make an array of shape (xrange + 3, yrange + 3) burn = sutils.burnXYZs(tiles, xmin, xmax, ymin, ymax, 0) nw = mercantile.xy(*mercantile.ul(xmin, ymin, zoom)) se = mercantile.xy(*mercantile.ul(xmax + 1, ymax + 1, zoom)) aff = Affine(((se[0] - nw[0]) / float(xmax - xmin + 1)), 0.0, nw[0], 0.0, -((nw[1] - se[1]) / float(ymax - ymin + 1)), nw[1]) unprojecter = sutils.Unprojecter() unionedTiles = [ { 'geometry': unprojecter.unproject(feature), 'properties': {}, 'type': 'Feature' } for feature, shapes in features.shapes(np.asarray(np.flipud(np.rot90(burn)).astype(np.uint8), order='C'), transform=aff) if shapes == 1 ] return unionedTiles
def main(raster_file, vector_file, driver, mask_value): with rasterio.drivers(): with rasterio.open(raster_file) as src: image = src.read_band(1) if mask_value is not None: mask = image == mask_value else: mask = None results = ( {'properties': {'raster_val': v}, 'geometry': s} for i, (s, v) in enumerate( shapes(image, mask=mask, transform=src.affine))) with fiona.open( vector_file, 'w', driver=driver, crs=src.crs, schema={'properties': [('raster_val', 'int')], 'geometry': 'Polygon'}) as dst: dst.writerecords(results) return dst.name
def create_shapefile(in_files, out_shapefile, dest_crs): polygons = [] for idx, f in enumerate(in_files): src = rasterio.open(f) crs = src.crs transform = src.transform bnd = src.read(1) polys = list(shapes(bnd, transform=transform)) for geom, val in polys: if val == 0: continue polygons.append((Polygon(shape(geom)), val)) shp_schema = { 'geometry': 'Polygon', 'properties': {'dmg': 'int'} } # Write out all the multipolygons to the same file with fiona.open(out_shapefile, 'w', 'ESRI Shapefile', shp_schema, dest_crs) as shp: for polygon, px_val in polygons: shp.write({ 'geometry': mapping(polygon), 'properties': {'dmg': int(px_val)} })
def test_shapes_invalid_mask_dtype(basic_image): """A mask that is the wrong dtype should fail.""" for dtype in ('int8', 'int16', 'int32'): with pytest.raises(ValueError): next(shapes( basic_image, mask=np.ones(basic_image.shape, dtype=dtype) ))
def test_shapes_internal_driver_manager(): """Make sure this works if driver is managed outside this test""" image = numpy.zeros((20, 20), dtype=rasterio.ubyte) image[5:15, 5:15] = 127 shapes = ftrz.shapes(image) shape, val = next(shapes) assert shape['type'] == 'Polygon'
def test_rasterize_geometries_symmetric(): """Make sure that rasterize is symmetric with shapes.""" transform = (1.0, 0.0, 0.0, 0.0, -1.0, 0.0) truth = np.zeros(DEFAULT_SHAPE, dtype=rasterio.ubyte) truth[2:5, 2:5] = 1 s = shapes(truth, transform=transform) result = rasterize(s, out_shape=DEFAULT_SHAPE, transform=transform) assert np.array_equal(result, truth)
def test_shapes_band_shortcut(): """Access to shapes of labeled features""" with rasterio.drivers(): with rasterio.open('rasterio/tests/data/shade.tif') as src: shapes = ftrz.shapes(rasterio.band(src, 1)) shape, val = next(shapes) assert shape['type'] == 'Polygon' assert len(shape['coordinates']) == 1 assert val == 255
def test_shapes_connectivity(): """Test connectivity options""" image = numpy.zeros((20, 20), dtype=rasterio.ubyte) image[5:11,5:11] = 1 image[11,11] = 1 shapes = ftrz.shapes(image, connectivity=8) shape, val = next(shapes) assert len(shape['coordinates'][0]) == 9
def test_shapes_invalid_mask_shape(basic_image): """A mask that is the wrong shape should fail.""" with pytest.raises(ValueError): next(shapes( basic_image, mask=np.ones( (basic_image.shape[0] + 10, basic_image.shape[1] + 10), dtype=rasterio.bool_ ) ))
def test_shapes_band_shortcut(): """Test rasterio bands as input to shapes""" with rasterio.drivers(): with rasterio.open('tests/data/shade.tif') as src: shapes = ftrz.shapes(rasterio.band(src, 1)) shape, val = next(shapes) assert shape['type'] == 'Polygon' assert len(shape['coordinates']) == 1 assert val == 255
def test_rasterize_geometries_symmetric(): """Make sure that rasterize is symmetric with shapes""" rows = cols = 10 transform = (1.0, 0.0, 0.0, 0.0, -1.0, 0.0) truth = numpy.zeros((rows, cols), dtype=rasterio.ubyte) truth[2:5, 2:5] = 1 with rasterio.drivers(): s = shapes(truth, transform=transform) result = rasterize(s, out_shape=(rows, cols), transform=transform) assert numpy.array_equal(result, truth)
def test_rasterize_geometries_symmetric(): """Make sure that rasterize is symmetric with shapes""" rows = cols = 10 transform = [0, 1, 0, 0, 0, 1] truth = numpy.zeros((rows, cols), dtype=rasterio.ubyte) truth[2:5, 2:5] = 1 with rasterio.drivers(): s = shapes(truth, transform=transform) result = rasterize(s, out_shape=(rows, cols), transform=transform) assert (result == truth).min() == True
def makeVectors(inArr, affine_trans): for feature, shapes in features.shapes(np.asarray(inArr,order='C'),transform=affine_trans): if shapes != 0: featurelist = [Polygon(f) for f in feature['coordinates']] print json.dumps({ 'type': 'Feature', 'geometry': mapping(MultiPolygon(featurelist)), 'properties': { 'pred_delta': shapes } })
def test_shapes_connectivity(): """Test connectivity options""" image = numpy.zeros((20, 20), dtype=rasterio.ubyte) image[5:11, 5:11] = 1 image[11, 11] = 1 shapes = ftrz.shapes(image, connectivity=4) shape, val = next(shapes) assert len(shape['coordinates'][0]) == 5 shapes = ftrz.shapes(image, connectivity=8) shape, val = next(shapes) assert len(shape['coordinates'][0]) == 9 # Note: geometry is not technically valid at this point, it has a self # intersection at 11,11 # Test invalid connectivity with pytest.raises(ValueError): shapes = ftrz.shapes(image, connectivity=12) next(shapes)
def test_shapes_dtype(): """Test image data type handling""" rows = cols = 10 with rasterio.drivers(): supported_types = ( ('int16', -32768), ('int32', -2147483648), ('uint8', 255), ('uint16', 65535), ('float32', 1.434532) ) for dtype, test_value in supported_types: image = numpy.zeros((rows, cols), dtype=dtype) image[2:5, 2:5] = test_value shapes = ftrz.shapes(image) shape, value = next(shapes) if dtype == 'float32': assert round(value, 6) == round(test_value, 6) else: assert value == test_value # Unsupported types should all raise exceptions unsupported_types = ( ('int8', -127), ('uint32', 4294967295), ('int64', 20439845334323), ('float16', -9343.232), ('float64', -98332.133422114) ) for dtype, test_value in unsupported_types: with pytest.raises(ValueError): image = numpy.zeros((rows, cols), dtype=dtype) image[2:5, 2:5] = test_value shapes = ftrz.shapes(image) shape, value = next(shapes)
def test_shapes_supported_dtypes(basic_image): """Supported data types should return valid results.""" supported_types = ( ('int16', -32768), ('int32', -2147483648), ('uint8', 255), ('uint16', 65535), ('float32', 1.434532) ) for dtype, test_value in supported_types: shape, value = next(shapes(basic_image.astype(dtype) * test_value)) assert np.allclose(value, test_value)
def test_shapes_unsupported_dtypes(basic_image): """Unsupported data types should raise exceptions.""" unsupported_types = ( ('int8', -127), ('uint32', 4294967295), ('int64', 20439845334323), ('float16', -9343.232), ('float64', -98332.133422114) ) for dtype, test_value in unsupported_types: with pytest.raises(ValueError): next(shapes(basic_image.astype(dtype) * test_value))
def get_tile_geometry(path, origin_espg, tolerance=500): """ Calculate the data and tile geometry for sentinel-2 tiles """ with rasterio.open(path) as src: # Get tile geometry b = src.bounds tile_shape = Polygon([(b[0], b[1]), (b[2], b[1]), (b[2], b[3]), (b[0], b[3]), (b[0], b[1])]) tile_geojson = mapping(tile_shape) # read first band of the image image = src.read(1) # create a mask of zero values mask = image == 0. # generate shapes of the mask novalue_shape = shapes(image, mask=mask, transform=src.affine) # generate polygons using shapely novalue_shape = [Polygon(s['coordinates'][0]) for (s, v) in novalue_shape] if novalue_shape: # Make sure polygons are united # also simplify the resulting polygon union = cascaded_union(novalue_shape) # generates a geojson data_shape = tile_shape.difference(union) # If there are multipolygons, select the largest one if data_shape.geom_type == 'MultiPolygon': areas = {p.area: i for i, p in enumerate(data_shape)} largest = max(areas.keys()) data_shape = data_shape[areas[largest]] # if the polygon has interior rings, remove them if list(data_shape.interiors): data_shape = Polygon(data_shape.exterior.coords) data_shape = data_shape.simplify(tolerance, preserve_topology=False) data_geojson = mapping(data_shape) else: data_geojson = tile_geojson # convert cooridnates to degrees return (to_latlon(tile_geojson, origin_espg), to_latlon(data_geojson, origin_espg))
def test_shapes_mask(basic_image): """Only pixels not masked out should be converted to features.""" mask = np.ones(basic_image.shape, dtype=rasterio.bool_) mask[4:5, 4:5] = False results = list(shapes(basic_image, mask=mask)) assert len(results) == 2 shape, value = results[0] assert shape == { 'coordinates': [ [(2, 2), (2, 5), (4, 5), (4, 4), (5, 4), (5, 2), (2, 2)] ], 'type': 'Polygon' } assert value == 1
def test_geometry_mask(): rows = cols = 10 transform = (1.0, 0.0, 0.0, 0.0, -1.0, 0.0) truth = numpy.zeros((rows, cols), dtype=rasterio.bool_) truth[2:5, 2:5] = True with rasterio.drivers(): s = shapes((truth * 10).astype(rasterio.ubyte), transform=transform) # Strip out values returned from shapes, and only keep first shape geoms = [next(s)[0]] # Regular mask should be the inverse of truth raster mask = geometry_mask(geoms, out_shape=(rows, cols), transform=transform) assert numpy.array_equal(mask, numpy.invert(truth)) # Inverted mask should be the same as the truth raster mask = geometry_mask(geoms, out_shape=(rows, cols), transform=transform, invert=True) assert numpy.array_equal(mask, truth)
def test_shapes(): """Access to shapes of labeled features""" image = numpy.zeros((20, 20), dtype=rasterio.ubyte) image[5:15,5:15] = 127 with rasterio.drivers(): shapes = ftrz.shapes(image) shape, val = next(shapes) assert shape['type'] == 'Polygon' assert len(shape['coordinates']) == 2 # exterior and hole assert val == 0 shape, val = next(shapes) assert shape['type'] == 'Polygon' assert len(shape['coordinates']) == 1 # no hole assert val == 127 try: shape, val = next(shapes) except StopIteration: assert True else: assert False