Change detection allows you to automatically highlight the differences between two images in the same area if they are properly orthorectified. In this recipe, we'll do a simple difference change detection on two images, which are several years apart, to see the differences in urban development and the natural environment.
You can download the two images for this recipe from https://github.com/GeospatialPython/qgis/blob/gh-pages/change-detection.zip?raw=true and put them in a directory named change-detection
in the rasters
directory of your qgis_data
directory. Note that the file is 55 megabytes, so it may take several minutes to download.
We'll use the QGIS raster calculator to subtract the images in order to get the difference, which will highlight significant changes. We'll also add a color ramp shader to the output in order to visualize the changes. To do this, we need to perform the following steps:
from PyQt4.QtGui import * from PyQt4.QtCore import * from qgis.analysis import *
before = "/Users/joellawhead/qgis_data/rasters/change-detection/before.tif" after = "/Users/joellawhead/qgis_data/rasters/change-detection/after.tif" beforeName = "Before" afterName = "After"
beforeRaster = QgsRasterLayer(before, beforeName) afterRaster = QgsRasterLayer(after, afterName)
beforeEntry = QgsRasterCalculatorEntry() afterEntry = QgsRasterCalculatorEntry() beforeEntry.raster = beforeRaster afterEntry.raster = afterRaster beforeEntry.bandNumber = 1 afterEntry.bandNumber = 2 beforeEntry.ref = beforeName + "@1" afterEntry.ref = afterName + "@2" entries = [afterEntry, beforeEntry]
exp = "%s - %s" % (afterEntry.ref, beforeEntry.ref)
output = "/Users/joellawhead/qgis_data/rasters/change-detection/change.tif" e = beforeRaster.extent() w = beforeRaster.width() h = beforeRaster.height()
change = QgsRasterCalculator(exp, output, "GTiff", e, w, h, entries) change.processCalculation()
lyr = QgsRasterLayer(output, "Change") algorithm = QgsContrastEnhancement.StretchToMinimumMaximum limits = QgsRaster.ContrastEnhancementMinMax lyr.setContrastEnhancement(algorithm, limits) s = QgsRasterShader() c = QgsColorRampShader() c.setColorRampType(QgsColorRampShader.INTERPOLATED) i = [] qri = QgsColorRampShader.ColorRampItem i.append(qri(0, QColor(0,0,0,0), 'NODATA')) i.append(qri(-101, QColor(123,50,148,255), 'Significant Itensity Decrease')) i.append(qri(-42.2395, QColor(194,165,207,255), 'Minor Itensity Decrease')) i.append(qri(16.649, QColor(247,247,247,0), 'No Change')) i.append(qri(75.5375, QColor(166,219,160,255), 'Minor Itensity Increase')) i.append(qri(135, QColor(0,136,55,255), 'Significant Itensity Increase')) c.setColorRampItemList(i) s.setRasterShaderFunction(c) ps = QgsSingleBandPseudoColorRenderer(lyr.dataProvider(), 1, s) lyr.setRenderer(ps) QgsMapLayerRegistry.instance().addMapLayer(lyr)
The concept is simple. We subtract the older image data from the new image data. Concentrating on urban areas tends to be highly reflective and results in higher image pixel values. If a building is added in the new image, it will be brighter than its surroundings. If a building is removed, the new image will be darker in that area. The same holds true for vegetation, to some extent.