Sometimes, you need to sample a raster dataset at regular intervals in order to provide summary statistics or for quality assurance purposes on the raster data. A common way to accomplish this regular sampling is to create a point grid over the dataset, query the grid at each point, and assign the results as attributes to those points. In this recipe, we will perform this type of sampling over a satellite image. QGIS has a tool to perform this operation called regular points, which is in the Vector menu under Research Tools. However, there is no tool in the QGIS API to perform this operation programmatically. However, we can implement this algorithm directly using Python's numpy
module.
In this recipe, we will use the previously used SatImage raster, available at https://geospatialpython.googlecode.com/files/SatImage.zip.
Place this raster in your /qgis_data/rasters
directory.
The order of operation for this recipe is to load the raster layer, create a vector layer in memory, add points at regular intervals, sample the raster layer at these points, and then add the sampling data as attributes for each point. To do this, we need to perform the following steps:
numpy
module, which is included with QGIS, as well as the Qt core module:import numpy from PyQt4.QtCore import *
spacing
variable to control how far apart the points are in map units:spacing = .1
inset
variable to determine how close to the edge of the image the points start, in map units:inset = .04
rasterLyr = QgsRasterLayer("/qgis_data/rasters/satimage.tif", "Sat Image") rasterLyr.isValid()
rpr = rasterLyr.dataProvider() epsg = rasterLyr.crs().postgisSrid() ext = rasterLyr.extent()
vectorLyr = QgsVectorLayer('Point?crs=epsg:%s' % epsg, 'Grid' , "memory")
vpr = vectorLyr.dataProvider() qd = QVariant.Double
vpr.addAttributes([QgsField("Red", qd), QgsField("Green", qd), QgsField("Blue", qd)]) vectorLyr.updateFields()
inset
variable to set up the layer's extents inside the raster layer:xmin = ext.xMinimum() + inset xmax = ext.xMaximum() ymin = ext.yMinimum() + inset ymax = ext.yMaximum() – inset
numpy
module to efficiently create the coordinates of the points in our regular grid:pts = [(x,y) for x in (i for i in numpy.arange(xmin, xmax, spacing)) for y in (j for j in numpy.arange(ymin, ymax, spacing))]
feats = []
for x,y in pts: f = QgsFeature() f.initAttributes(3) p = QgsPoint(x,y) qry = rasterLyr.dataProvider().identify(p, QgsRaster.IdentifyFormatValue) r = qry.results() f.setAttribute(0, r[1]) f.setAttribute(1, r[2]) f.setAttribute(2, r[3]) f.setGeometry(QgsGeometry.fromPoint(p)) feats.append(f)
vpr.addFeatures(feats)
vectorLyr.updateExtents()
QgsMapLayerRegistry.instance().addMapLayers([rasterLyr,vectoryr])
canvas = iface.mapCanvas() canvas.setExtent(rasterLyr.extent()) canvas.refresh()
The following screenshot shows the end result, with one of the points in the grid identified using the Identify Features map tool. The results dialog shows the raster values of the selected point:
Using memory layers in QGIS is an easy way to perform quick, one-off operations without the overhead of creating files on disk. Memory layers also tend to be fast if your machine has the resources to spare.