Example #1
0
    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]])
Example #2
0
    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)
Example #3
0
    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")
Example #4
0
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()
Example #5
0
    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()