A common way to catalog raster datasets that consist of a large number of files is by creating a vector dataset with polygon footprints of the extent of each raster file. The vector footprint files can be easily loaded in QGIS or served over the Web. This recipe demonstrates a method to create a footprint vector from a directory full of raster files. We will build this program as a Processing Toolbox script, which is easier to build than a QGIS plugin and provides both a GUI and a clean programming API.
Download the sample raster image scenes from https://geospatialpython.googlecode.com/svn/scenes.zip. Unzip the scenes
directory into a directory named rasters
in your qgis_data
directory.
For this recipe, we will create a new Processing Toolbox script using the following steps:
First, we will use the Processing Toolbox header naming conventions ,which will simultaneously define our GUI and the input and output variables. Then, we'll create the logic, which processes a raster directory and calculates the image extents, and finally we'll create the vector file. To do this, we need to perform the following steps:
##Vector=group ##Input_Raster_Directory=folder ##Output_Footprints_Vector=output vector
import os from qgis.core import *
files = os.listdir(Input_Raster_Directory)
footprints = [] crs = ""
for f in files: try: fn = os.path.join(Input_Raster_Directory, f) lyr = QgsRasterLayer(fn, "Input Raster") crs = lyr.crs() e = lyr.extent() ulx = e.xMinimum() uly = e.yMaximum() lrx = e.xMaximum() lry = e.yMinimum() ul = (ulx, uly) ur = (lrx, uly) lr = (lrx, lry) ll = (ulx, lry) fp = {} points = [] points.append(QgsPoint(*ul)) points.append(QgsPoint(*ur)) points.append(QgsPoint(*lr)) points.append(QgsPoint(*ll)) points.append(QgsPoint(*ul)) fp["points"] = points fp["raster"] = fn footprints.append(fp) except: progress.setInfo("Warning: The file %s does not appear to be a valid raster file." % f)
vectorLyr = QgsVectorLayer("Polygon?crs=%s&field=raster:string(100)" % crs, "Footprints" , "memory") vpr = vectorLyr.dataProvider()
features = [] for fp in footprints: poly = QgsGeometry.fromPolygon([fp["points"]]) f = QgsFeature() f.setGeometry(poly) f.setAttributes([fp["raster"]]) features.append(f) vpr.addFeatures(features) vectorLyr.updateExtents()
driver = "Esri Shapefile" epsg = crs.postgisSrid() srs = "EPSG:%s" % epsg
error = QgsVectorFileWriter.writeAsVectorFormat (vectorLyr, Output_Footprints_Vector, "utf-8", srs, driver) if error == QgsVectorFileWriter.NoError: pass else: progress.setInfo("Unable to output footprints.")
It is important to remember that a Processing Toolbox script can be run in several different contexts: as a GUI process such as a plugin, as a programmatic script from the Python console, a Python plugin, or the Graphical Modeler framework. Therefore, it is important to follow the documented Processing Toolbox API so that it can work as expected in all of these contexts. This includes defining clear inputs and outputs and using the progress object. The progress object is the proper way to provide feedback to the user for both progress bars and messages. Although the API allows you to define outputs that let the user select different OGR and GDAL outputs, only shapefiles and GeoTiffs seem to be supported currently.
The Graphical Modeler tool within the Processing Toolbox lets you visually chain different processing algorithms together to create complex workflows. Another interesting plugin is the Processing Workflows plugin, which not only allows you to chain algorithms together but also provides a nice tabbed interface with instructions for the end user to help beginners through complicated geospatial workflows.
The following screenshot shows the raster footprints over an OpenStreetMap basemap: