Ejemplo n.º 1
0
def vector2raster(extent, inputPath, outputPath, pixelSize=0.2):
    """
	Converts a given input polygon vector layer to a raster image.


	:param extent: (minX, minY, maxX, maxY)
	:type extent: tuple
	:param inputPath: path to polygon vector layer
	:type inputPath: str
	:param outputPath: path where raster will be saved
	:type outputPath: str
	:param pixelSize: size of pixel in georeferenced units (ie. meter) of input data
	:type pixelSize: float
	"""
    subprocess.call([
        "gdal_rasterize", "-of", "GTiff", "-ot", "Byte", "-init", "0", "-burn",
        "255", "-te",
        str(extent[0]),
        str(extent[1]),
        str(extent[2]),
        str(extent[3]), "-tr",
        str(pixelSize),
        str(pixelSize), inputPath, outputPath
    ],
                    startupinfo=getSubprocessStartUpInfo())
Ejemplo n.º 2
0
def scaleImageToSize(inputPath,
                     outputPath,
                     resolutionX,
                     resolutionY,
                     interpolation=gdal.GRA_NearestNeighbour):
    """
	Scales input image to sizeX x sizeY.

	:param inputPath:
	:type inputPath: str
	:param outputPath:
	:type outputPath: str
	:param resolutionX: pixel resolution in X
	:type resolutionX: int
	:param resolutionY: pixel resolution in Y
	:type resolutionY: int
	:param interpolation: ie. gdal.GRA_NearestNeighbour or "near"
	:type interpolation: int | str
	"""
    if not isinstance(interpolation, str):
        interpolation = getGDALInterpolationName(interpolation)
    subprocess.call([
        "gdalwarp", "-of", "GTiff", "-ts",
        str(resolutionX),
        str(resolutionY), "-r", interpolation, inputPath, outputPath
    ],
                    startupinfo=getSubprocessStartUpInfo())
Ejemplo n.º 3
0
def convertToEPSG(inputPath, outputPath, outputFormat="GeoJSON", toEPSG=25832):
    """
	Converts the given input path to the given EPSG and saves it in outputPath.

	:param inputPath:
	:type inputPath: str
	:param outputPath:
	:type outputPath: str
	:param outputFormat: ogr2ogr output format http://www.gdal.org/ogr2ogr.html
	:type outputFormat: str
	:param toEPSG:
	:type toEPSG: int
	"""
    deleteFile(outputPath)
    subprocess.call([
        "ogr2ogr", "-f", outputFormat, "-t_srs",
        "EPSG:%d" % toEPSG, outputPath, inputPath
    ],
                    startupinfo=getSubprocessStartUpInfo())
Ejemplo n.º 4
0
def createBuffers(inputPath, outputPath, outputFormat="GeoJSON", buffer=1):
    """
	Buffers input data.

	:param inputPath: path to polygon vector layer
	:type inputPath: str
	:param outputPath: path where raster will be saved
	:type outputPath: str
	:param buffer: buffer amount in epsg units
	:type buffer: float
	"""

    inputDataSource = ogr.Open(inputPath)  # type: ogr.DataSource
    inputLayer = inputDataSource.GetLayerByIndex(0)  # type: ogr.Layer
    layerName = inputLayer.GetName()
    inputDataSource = None
    deleteFile(outputPath)
    subprocess.call([
        "ogr2ogr", "-dialect", "sqlite", "-f", outputFormat, "-sql",
        "SELECT ST_Buffer( geometry , " + str(buffer) + " ),* FROM '" +
        layerName + "' ", outputPath, inputPath
    ],
                    startupinfo=getSubprocessStartUpInfo())
Ejemplo n.º 5
0
def getVectorDataFromWFS(url,
                         layerName,
                         extent,
                         outputPath,
                         outputFormat="GeoJSON",
                         epsg=25832,
                         append=False,
                         attributeFilter=""):
    """
	Creates vector file from given WFS.
	If too many features (>10000) are requested, then the extent will be split up, so the features per extent decreases.
	This is done recursively. Because features can overlap at extent borders, the file will be searched for duplicates.
	These will be removed.

	:param url: url to WFS
	:type url: str
	:param layerName: name of the layer in the WFS which should be downloaded
	:type layerName: str
	:param extent: (minX, minY, maxX, maxY)
	:type extent: tuple[float, float, float, float]
	:param outputPath: save path
	:type outputPath: str
	:param outputFormat: ogr output format string like "GeoJSON" or "ESRI Shapefile", NOTE: the output format should
						allow appending data!
	:type outputFormat: str
	:param epsg: target epsg (in which extent is)
	:type epsg: int
	:param append: if True, the data will append to the output file
	:type append: bool
	:param attributeFilter: filtering of attributes with SQL WHERE like "Amtlicheflaeche > '300' AND Amtlicheflaeche < '2000'"
	:type attributeFilter: str
	"""
    MAX_FEATURE_COUNT = 9999999  # splitting not working anymore, don't know why, maybe its the server:
    # ERROR 1: Layer tlvermgeo:ALKIS_GESAMT_FKZ not found, and CreateLayer not supported by driver.
    # so data will now be caped at 10000

    if not append:
        deleteFile(outputPath)

    # check how many features we want (we can only get 10000)
    wfsDriver = ogr.GetDriverByName('WFS')
    wfs = wfsDriver.Open("WFS:" + url)  # type: ogr.DataSource
    wfsLayer = wfs.GetLayerByName(layerName)  # type: ogr.Layer
    minX = extent[0]
    minY = extent[1]
    maxX = extent[2]
    maxY = extent[3]
    extentWkt = "POLYGON ((" + str(minX) + " " + str(minY) + "," \
                   "" + str(minX) + " " + str(maxY) + ", " \
                           "" + str(
     maxX) + " " + str(maxY) + ", " \
             "" + str(maxX) + " " + str(minY) + "," \
                     "" + str(minX) + " " + str(minY) + "))"
    wfsLayer.SetSpatialFilter(ogr.CreateGeometryFromWkt(extentWkt))
    wfsLayer.SetAttributeFilter(attributeFilter)
    featureCount = wfsLayer.GetFeatureCount()
    if featureCount > MAX_FEATURE_COUNT:  # is maximal number of features exceeded, than split extent in 4 parts
        print "Too many features in WFS request %d, splitting up extent" % featureCount
        filePathWithoutExtension, fileExtension = os.path.splitext(outputPath)
        tempPath = filePathWithoutExtension + "_temp" + fileExtension

        wfs = None
        halfWidth = (maxX - minX) / 2
        halfHeight = (maxY - minY) / 2
        # lower left
        getVectorDataFromWFS(url,
                             layerName=layerName,
                             extent=(minX, minY, minX + halfWidth,
                                     minY + halfHeight),
                             outputPath=tempPath,
                             outputFormat=outputFormat,
                             append=True,
                             attributeFilter=attributeFilter)
        # lower right
        getVectorDataFromWFS(url,
                             layerName=layerName,
                             extent=(minX + halfWidth, minY, maxX,
                                     minY + halfHeight),
                             outputPath=tempPath,
                             outputFormat=outputFormat,
                             append=True,
                             attributeFilter=attributeFilter)
        # upper left
        getVectorDataFromWFS(url,
                             layerName=layerName,
                             extent=(minX, minY + halfHeight, minX + halfWidth,
                                     maxY),
                             outputPath=tempPath,
                             outputFormat=outputFormat,
                             append=True,
                             attributeFilter=attributeFilter)
        # upper right
        getVectorDataFromWFS(url,
                             layerName=layerName,
                             extent=(minX + halfWidth, minY + halfHeight, maxX,
                                     maxY),
                             outputPath=tempPath,
                             outputFormat=outputFormat,
                             append=True,
                             attributeFilter=attributeFilter)
        # remove duplicate entries from overlapping bounds
        tempDataSource = ogr.Open(tempPath)  # type: ogr.DataSource
        tempLayer = tempDataSource.GetLayer()  # type: ogr.Layer
        geometries = []
        for feature in tempLayer:  # type: ogr.Feature
            geometries.append(feature.geometry().ExportToWkt())

        uniqueGeometriesWkt = [
            attribute for attribute, count in Counter(geometries).items()
            if count > 1
        ]

        # create final output file and add unique features
        outputDriver = ogr.GetDriverByName(outputFormat)
        outputDataSource = outputDriver.CreateDataSource(
            outputPath)  # type: ogr.DataSource
        outputLayer = outputDataSource.CreateLayer(
            "cadastre",
            srs=tempLayer.GetSpatialRef(),
            geom_type=tempLayer.GetGeomType())  # type: ogr.Layer
        tempLayer.ResetReading()
        for feature in tempLayer:  # type: ogr.Feature
            geomWkt = feature.geometry().ExportToWkt()
            if geomWkt in uniqueGeometriesWkt:
                uniqueGeometriesWkt.remove(geomWkt)
                outputLayer.CreateFeature(feature.Clone())
        outputDataSource = None
        tempDataSource = None
        deleteFile(tempPath)
        return
    wfs = None
    subprocess.call([
        "ogr2ogr", "-f", outputFormat, "-t_srs",
        "EPSG:%d" % epsg, "-spat",
        str(extent[0]),
        str(extent[1]),
        str(extent[2]),
        str(extent[3]), outputPath, "WFS:" + url, "-append", "-where",
        attributeFilter, layerName
    ],
                    startupinfo=getSubprocessStartUpInfo())
Ejemplo n.º 6
0
def createImageFromWMS(savePath,
                       serverUrl,
                       layers,
                       boundingBox,
                       pixelPerMeter=5,
                       imageFormat="png",
                       transparent=False,
                       blockSize=(500, 500),
                       removeLogos=True):
    """
	Creates a geo tiff image at given savePath from given parameters.
	The crs of the WMS image is currently fixed at EPSG:25832.
	It also removes copyright logos if removeLogos is True.

	:param savePath:
	:type savePath str
	:param serverUrl:
	:type savePath str
	:param layers: comma separated layer names
	:type layers str
	:param boundingBox: (left, bottom, right, top) of bounding box in EPSG:25832 units.
	:type boundingBox tuple
	:param pixelPerMeter:
	:type pixelPerMeter int | float
	:param imageFormat: "jpeg", "png", etc
	:type imageFormat: str
	:param transparent:
	:type transparent: bool
	:param blockSize: (500,500) size of sub images in pixels, use multiple of pixelPerMeter
	:type blockSize: tuple
	:param removeLogos: if True, GeoProxies copyright logos will be removed
	:type removeLogos: bool
	"""
    pixelPerMeter = float(pixelPerMeter)

    createFoldersForPath(savePath)
    gdalWmsXmlPath = getPathToTempFile("gdal_wms_config.xml")

    xMin = boundingBox[0]
    xMax = boundingBox[2]
    yMin = boundingBox[1]
    yMax = boundingBox[3]
    widthInMeter = xMax - xMin
    heightInMeter = yMax - yMin
    imageWidth = int(round(widthInMeter * pixelPerMeter))
    imageHeight = int(round(heightInMeter * pixelPerMeter))

    # if blockSize is None:
    # 	# max block size given by server is 5000x5000, we use min block Size 500x500
    # 	blockWidth = int(round(min(max(imageWidth / 4, 500), 5000)))
    # 	blockHeight = int(round(min(max(imageWidth / 4, 500), 5000)))
    # 	blockSize = (blockHeight, blockWidth)

    name, extension = os.path.splitext(savePath)
    if extension.lower() == ".jpeg" or extension.lower() == ".jpg":
        gdalImageFormat = "JPEG"
    elif extension.lower() == ".png":
        gdalImageFormat = "PNG"
    else:
        gdalImageFormat = "GTiff"

    createGdalWmsXml(gdalWmsXmlPath,
                     serverUrl=serverUrl,
                     layers=layers,
                     bb=boundingBox,
                     size=(imageWidth, imageHeight),
                     blockSize=blockSize,
                     imageFormat=("image/" + imageFormat),
                     transparent=transparent)
    subprocess.call([
        "gdal_translate", "-of", gdalImageFormat, "-outsize",
        str(imageWidth),
        str(imageHeight), gdalWmsXmlPath, savePath
    ],
                    # startupinfo=getSubprocessStartUpInfo()
                    )

    if removeLogos is True and "geoproxy.geoportal-th.de" in serverUrl:
        # At each position of a logo, a new image will be loaded from the WMS (logoWidth, 2 * logoHeight).
        imageDataSet = gdal.Open(savePath,
                                 gdal.GA_Update)  # type: gdal.Dataset
        imageData = np.array(imageDataSet.ReadAsArray(),
                             dtype='uint8')  # [R,G,B,(A)][y][x]
        blockWidth = blockSize[0]
        blockHeight = blockSize[1]
        blockCountX = int(np.ceil(float(imageWidth) / blockWidth))
        blockCountY = int(np.ceil(float(imageHeight) / blockHeight))
        blockWidthInMeter = blockWidth / pixelPerMeter
        blockHeightInMeter = blockHeight / pixelPerMeter
        logoWidth = 65
        logoHeight = 25
        logoWidthInMeter = logoWidth / pixelPerMeter
        logoHeightInMeter = logoHeight / pixelPerMeter

        for y in range(0, blockCountY):
            for x in range(0, blockCountX):
                if y < blockCountY - 1:
                    bb = (
                        xMin + x * blockWidthInMeter,  # left
                        yMax - blockHeightInMeter + logoHeightInMeter -
                        y * blockHeightInMeter,  # top
                        xMin + logoWidthInMeter +
                        x * blockWidthInMeter,  # right
                        yMax - blockHeightInMeter - logoHeightInMeter -
                        y * blockHeightInMeter  # bottom
                    )
                else:  # the last blocks in y direction maybe not complete blocks, so use yMin
                    bb = (
                        xMin + x * blockWidthInMeter,  # left
                        yMin + logoHeightInMeter,  # top
                        xMin + logoWidthInMeter +
                        x * blockWidthInMeter,  # right
                        yMin - logoHeightInMeter  # bottom
                    )
                blockTempPath = getPathToTempFile("temp_block.tiff")
                createGdalWmsXml(gdalWmsXmlPath,
                                 serverUrl=serverUrl,
                                 layers=layers,
                                 bb=bb,
                                 size=(logoWidth, logoHeight * 2),
                                 blockSize=(logoWidth, logoHeight * 2),
                                 imageFormat=("image/" + imageFormat),
                                 transparent=transparent)
                # suppress showing up console window
                subprocess.call([
                    "gdal_translate", "-of", gdalImageFormat, "-outsize",
                    str(logoWidth),
                    str(logoHeight * 2), gdalWmsXmlPath, blockTempPath
                ],
                                startupinfo=getSubprocessStartUpInfo())

                # remove the logo in overlay image
                overlayDataSet = gdal.Open(
                    blockTempPath, gdal.GA_ReadOnly)  # type: gdal.Dataset
                overlayData = np.array(overlayDataSet.ReadAsArray(),
                                       dtype='uint8')  # [R,G,B][y][x]
                overlayData = removeLogo(overlayData)

                # set the overlay data at position where logos are in original image
                if y < blockCountY - 1:
                    logoData = imageData[:, blockHeight - logoHeight +
                                         y * blockHeight:blockHeight +
                                         y * blockHeight, x *
                                         blockWidth:x * blockWidth + logoWidth]
                else:  # the last blocks in y direction maybe not complete blocks, so use imageHeight
                    logoData = imageData[:,
                                         imageHeight - logoHeight:imageHeight,
                                         x * blockWidth:x * blockWidth +
                                         logoWidth]
                # check if image is big enough
                clippedOverlayData = overlayData[:, 0:logoData.shape[1],
                                                 0:logoData.shape[2]]

                if y < blockCountY - 1:
                    imageData[:, blockHeight - logoHeight +
                              y * blockHeight:blockHeight + y * blockHeight,
                              x * blockWidth:x * blockWidth +
                              logoWidth] = clippedOverlayData
                else:  # the last blocks in y direction maybe not complete blocks, so use imageHeight
                    imageData[:, imageHeight - logoHeight:imageHeight,
                              x * blockWidth:x * blockWidth +
                              logoWidth] = clippedOverlayData

                # cleanup
                overlayDataSet = None
                deleteFilesContainingName(os.path.basename(blockTempPath))

        for i in range(1, imageDataSet.RasterCount + 1):
            imageDataSet.GetRasterBand(i).WriteArray(
                imageData[i - 1])  # causes error when closing app window
        imageDataSet = None