Sampling a raster dataset using a regular grid

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.

Getting ready

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.

How to do it...

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:

  1. Start QGIS.
  2. From the Plugins menu, select Python Console.
  3. We will need to import the numpy module, which is included with QGIS, as well as the Qt core module:
    import numpy
    from PyQt4.QtCore import *
    
  4. Now, we will create a spacing variable to control how far apart the points are in map units:
    spacing = .1
    
  5. Next, we will create an inset variable to determine how close to the edge of the image the points start, in map units:
    inset = .04
    
  6. Now, we load and validate the raster layer:
    rasterLyr = QgsRasterLayer("/qgis_data/rasters/satimage.tif", "Sat Image")
    rasterLyr.isValid()
    
  7. Next, we collect the coordinate reference system and extent from the raster layer in order to transfer it to the point layer:
    rpr = rasterLyr.dataProvider()
    epsg = rasterLyr.crs().postgisSrid()
    ext = rasterLyr.extent()
    
  8. Now, we create an in-memory vector point layer, which won't be written to disk:
    vectorLyr = QgsVectorLayer('Point?crs=epsg:%s' % epsg, 'Grid' , "memory")
    
  9. In order to add points to the vector layer, we must access its data provider:
    vpr = vectorLyr.dataProvider()
    qd = QVariant.Double
    
  10. Next, we create the attributes' fields to store the raster data samples:
    vpr.addAttributes([QgsField("Red", qd), QgsField("Green", qd), QgsField("Blue", qd)])
    vectorLyr.updateFields()
    
  11. We use the 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
    
  12. Now, we use the 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))]
    
  13. Then, we create a list to store the point features we will create:
    feats = []
    
  14. In one loop, we create the point features, query the raster, and then update the attribute table. We store the points in a list for now:
    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)
    
  15. Next, we pass the list of points to the data provider of the points layer:
    vpr.addFeatures(feats)
    
  16. Now, we update the layer's extents:
    vectorLyr.updateExtents()
    
  17. Then, we add both the raster and vector layers to the map in the list. The last item in the list is on top:
    QgsMapLayerRegistry.instance().addMapLayers([rasterLyr,vectoryr])
    
  18. Finally, we refresh the map to see the result:
    canvas = iface.mapCanvas()
    canvas.setExtent(rasterLyr.extent())
    canvas.refresh()
    

How it works...

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:

How it works...

When you use the QGIS Identification Tool to click on one of the points, the results dialog shows the extracted Red, Green, and Blue values from the image.

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.

There's more...

In this example, we used a regular grid, but we could have just as easily modified the numpy-based algorithm to create a random points grid, which in some cases is more useful. However, the Processing Toolbox also has a simple algorithm for random points called grass:v.random.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset