def __call__(self, src_ds, footprint_wkt): logger.info("Applying AlphaBandOptimization") dt = src_ds.GetRasterBand(1).DataType if src_ds.RasterCount == 3: src_ds.AddBand(dt) elif src_ds.RasterCount == 4: pass # okay else: raise Exception("Cannot add alpha band, as the current number of " "bands '%d' does not match" % src_ds.RasterCount) # initialize the alpha band with zeroes (completely transparent) band = src_ds.GetRasterBand(4) band.Fill(0) # set up the layer with geometry ogr_ds = ogr.GetDriverByName('Memory').CreateDataSource('wkt') sr = osr.SpatialReference() sr.ImportFromEPSG(4326) layer = ogr_ds.CreateLayer('poly', srs=sr.sr) feat = ogr.Feature(layer.GetLayerDefn()) feat.SetGeometryDirectly(ogr.Geometry(wkt=footprint_wkt)) layer.CreateFeature(feat) # rasterize the polygon, burning the opaque value into the alpha band gdal.RasterizeLayer(src_ds, [4], layer, burn_values=[get_limits(dt)[1]])
def __init__(self, dataset, wkt, srid=None, temporary_directory=None): super(GDALGeometryMaskMergeSource, self).__init__(dataset) srs = None srid = 4326 if srid is not None: srs = osr.SpatialReference() srs.ImportFromEPSG(srid) # create a geometry from the given WKT #geom = ogr.CreateGeometryFromWkt(wkt) # create an in-memory datasource and add one single layer ogr_mem_driver = ogr.GetDriverByName("Memory") data_source = ogr_mem_driver.CreateDataSource("xxx") layer = data_source.CreateLayer("poly", srs) # create a single feature and add the given geometry feature = ogr.Feature(layer.GetLayerDefn()) feature.SetGeometryDirectly(ogr.Geometry(wkt=str(wkt))) layer.CreateFeature(feature) temporary_ds = temporary_dataset(self.dataset.RasterXSize, self.dataset.RasterYSize, 1, temp_root=temporary_directory) # create a temporary raster dataset with the exact same size as the # dataset to be masked with temporary_ds as mask_dataset: band = mask_dataset.GetRasterBand(1) band.Fill(1) mask_dataset.SetGeoTransform(self.dataset.GetGeoTransform()) mask_dataset.SetProjection(self.dataset.GetProjection()) # finally rasterize the vector layer to the mask dataset gdal.RasterizeLayer(mask_dataset, (1, ), layer, burn_values=(0, )) source_mask_band = mask_dataset.GetRasterBand(1) self.dataset.CreateMaskBand(gdal.GMF_PER_DATASET) band = self.dataset.GetRasterBand(1) mask_band = band.GetMaskBand() block_x_size, block_y_size = source_mask_band.GetBlockSize() num_x = source_mask_band.XSize / block_x_size num_y = source_mask_band.YSize / block_y_size for x, y in product(range(num_x), range(num_y)): mask_band.WriteArray( source_mask_band.ReadAsArray(x * block_x_size, y * block_y_size, block_x_size, block_y_size), x * block_x_size, y * block_y_size)
def connect(self, coverage, data_items, layer, options): mask_item = data_items[0] try: is_reversed = ( layer.metadata.get("eoxs_geometry_reversed") == "true") except ms.MapServerError: is_reversed = False # check if the geometry is "reversed" if is_reversed: # TODO: better use the coverages Extent? geom_types = (ogr.wkbPolygon, ogr.wkbMultiPolygon) output_polygon = ogr.Geometry(wkt=str(coverage.footprint.wkt)) for mask_item in data_items: ds = ogr.Open(get_vsi_path(mask_item)) for i in range(ds.GetLayerCount()): ogr_layer = ds.GetLayer(i) if not ogr_layer: continue feature = ogr_layer.GetNextFeature() while feature: # TODO: reproject if necessary geometry = feature.GetGeometryRef() if geometry.GetGeometryType() not in geom_types: continue if geometry: output_polygon = output_polygon.Difference( geometry) feature = ogr_layer.GetNextFeature() # since we have the geometry already in memory, add it to the layer # as WKT shape = ms.shapeObj.fromWKT(output_polygon.ExportToWkt()) shape.initValues(1) shape.setValue(0, coverage.identifier) layer.addFeature(shape) else: layer.connectiontype = ms.MS_OGR layer.connection = connect(data_items[0]) # TODO: more than one mask_item? layer.setProjection("EPSG:4326") layer.setMetaData("ows_srs", "EPSG:4326") layer.setMetaData("wms_srs", "EPSG:4326")
def generate_footprint_wkt(ds, simplification_factor=2): """ Generate a fooptrint from a raster, using black/no-data as exclusion """ # create an empty boolean array initialized as 'False' to store where # values exist as a mask array. nodata_map = np.zeros((ds.RasterYSize, ds.RasterXSize), dtype=np.bool) for idx in range(1, ds.RasterCount + 1): band = ds.GetRasterBand(idx) raster_data = band.ReadAsArray() nodata = band.GetNoDataValue() if nodata is None: nodata = 0 # apply the output to the map nodata_map |= (raster_data != nodata) # create a temporary in-memory dataset and write the nodata mask # into its single band with temporary_dataset(ds.RasterXSize + 2, ds.RasterYSize + 2, 1, gdal.GDT_Byte) as tmp_ds: copy_projection(ds, tmp_ds) tmp_band = tmp_ds.GetRasterBand(1) tmp_band.WriteArray(nodata_map.astype(np.uint8)) # create an OGR in memory layer to hold the created polygon sr = osr.SpatialReference() sr.ImportFromWkt(ds.GetProjectionRef()) ogr_ds = ogr.GetDriverByName('Memory').CreateDataSource('out') layer = ogr_ds.CreateLayer('poly', sr.sr, ogr.wkbPolygon) fd = ogr.FieldDefn('DN', ogr.OFTInteger) layer.CreateField(fd) # polygonize the mask band and store the result in the OGR layer gdal.Polygonize(tmp_band, tmp_band, layer, 0) if layer.GetFeatureCount() != 1: # if there is more than one polygon, compute the minimum bounding polygon geometry = ogr.Geometry(ogr.wkbPolygon) while True: feature = layer.GetNextFeature() if not feature: break geometry = geometry.Union(feature.GetGeometryRef()) # TODO: improve this for a better minimum bounding polygon geometry = geometry.ConvexHull() else: # obtain geometry from the first (and only) layer feature = layer.GetNextFeature() geometry = feature.GetGeometryRef() if geometry.GetGeometryType() not in (ogr.wkbPolygon, ogr.wkbMultiPolygon): raise RuntimeError("Error during poligonization. Wrong geometry " "type.") # check if reprojection to latlon is necessary if not sr.IsGeographic(): dst_sr = osr.SpatialReference() dst_sr.ImportFromEPSG(4326) try: geometry.TransformTo(dst_sr.sr) except RuntimeError: geometry.Transform(osr.CoordinateTransformation(sr.sr, dst_sr.sr)) gt = ds.GetGeoTransform() resolution = min(abs(gt[1]), abs(gt[5])) simplification_value = simplification_factor * resolution # simplify the polygon. the tolerance value is *really* vague try: # SimplifyPreserveTopology() available since OGR 1.9.0 geometry = geometry.SimplifyPreserveTopology(simplification_value) except AttributeError: # use GeoDjango bindings if OGR is too old geometry = ogr.CreateGeometryFromWkt( GEOSGeometry(geometry.ExportToWkt()).simplify( simplification_value, True).wkt) return geometry.ExportToWkt()
def _generate_footprint_wkt(self, ds): """ Generate a footprint from a raster, using black/no-data as exclusion """ # create an empty boolean array initialized as 'False' to store where # values exist as a mask array. nodata_map = numpy.zeros((ds.RasterYSize, ds.RasterXSize), dtype=numpy.bool) for idx in range(1, ds.RasterCount + 1): band = ds.GetRasterBand(idx) raster_data = band.ReadAsArray() nodata = band.GetNoDataValue() if nodata is None: nodata = 0 # apply the output to the map nodata_map |= (raster_data != nodata) # create a temporary in-memory dataset and write the nodata mask # into its single band tmp_ds = create_mem(ds.RasterXSize + 2, ds.RasterYSize + 2, 1, gdal.GDT_Byte) copy_projection(ds, tmp_ds) tmp_band = tmp_ds.GetRasterBand(1) tmp_band.WriteArray(nodata_map.astype(numpy.uint8)) # Remove unwanted small areas of nodata # www.gdal.org/gdal__alg_8h.html#a33309c0a316b223bd33ae5753cc7f616 no_pixels = tmp_ds.RasterXSize * tmp_ds.RasterYSize threshold = 4 max_threshold = (no_pixels / 16) if self.sieve_max_threshold > 0: max_threshold = self.sieve_max_threshold while threshold <= max_threshold and threshold < 2147483647: gdal.SieveFilter(tmp_band, None, tmp_band, threshold, 4) threshold *= 4 #for debugging: #gdal.GetDriverByName('GTiff').CreateCopy('/tmp/test.tif', tmp_ds) # create an OGR in memory layer to hold the created polygon sr = osr.SpatialReference() sr.ImportFromWkt(ds.GetProjectionRef()) ogr_ds = ogr.GetDriverByName('Memory').CreateDataSource('out') layer = ogr_ds.CreateLayer('poly', sr, ogr.wkbPolygon) fd = ogr.FieldDefn('DN', ogr.OFTInteger) layer.CreateField(fd) # polygonize the mask band and store the result in the OGR layer gdal.Polygonize(tmp_band, tmp_band, layer, 0) tmp_ds = None if layer.GetFeatureCount() > 1: # if there is more than one polygon, compute the minimum # bounding polygon logger.debug("Merging %s features in footprint." % layer.GetFeatureCount()) # union all features in one multi-polygon geometry = ogr.Geometry(ogr.wkbMultiPolygon) while True: feature = layer.GetNextFeature() if not feature: break geometry.AddGeometry(feature.GetGeometryRef()) geometry = geometry.UnionCascaded() # TODO: improve this for a better minimum bounding polygon geometry = geometry.ConvexHull() elif layer.GetFeatureCount() < 1: # there was an error during polygonization raise RuntimeError("Error during polygonization. No feature " "obtained.") else: # obtain geometry from the first (and only) layer feature = layer.GetNextFeature() geometry = feature.GetGeometryRef() if geometry.GetGeometryType() != ogr.wkbPolygon: raise RuntimeError( "Error during polygonization. Wrong geometry " "type: %s" % ogr.GeometryTypeToName(geometry.GetGeometryType())) # check if reprojection to latlon is necessary if not sr.IsGeographic(): dst_sr = osr.SpatialReference() dst_sr.ImportFromEPSG(4326) try: geometry.TransformTo(dst_sr) except RuntimeError: geometry.Transform(osr.CoordinateTransformation(sr, dst_sr)) gt = ds.GetGeoTransform() resolution = min(abs(gt[1]), abs(gt[5])) simplification_value = self.simplification_factor * resolution #for debugging: #geometry.GetGeometryRef(0).GetPointCount() # simplify the polygon. the tolerance value is *really* vague try: # SimplifyPreserveTopology() available since OGR 1.9.0 geometry = geometry.SimplifyPreserveTopology(simplification_value) except AttributeError: # use GeoDjango bindings if OGR is too old geometry = ogr.CreateGeometryFromWkt( GEOSGeometry(geometry.ExportToWkt()).simplify( simplification_value, True).wkt) return geometry.ExportToWkt()