# PyQGIS: GDAL hillshade patchwork effect

I have used QGIS to batch import and visualise tiled elevation data. This is illuminated greyscale, with identical parameters used each time, so I would have expected the result to be seamless and the tile boundaries to be essentially invisible.

However, the result is a 'patchwork quilt' effect. The shading is not consistent from one tile to the next. I do not understand why not. This is the code used to apply the hillshading:

  def ShadeRaster(raster, pth):

import processing

parameters = {'INPUT': "",
'BAND': 1,
'COMPUTE_EDGES': False,
'ZEVENBERGEN': False,
'Z_FACTOR': 1.0,
'SCALE': 1.0,
'AZIMUTH': 315,
'COMBINED': False,
'ALTITUDE': 45,
'MULTIDIRECTIONAL': False,
'OUTPUT': ""}

parameters['INPUT'] =raster.name()
parameters['OUTPUT'] = pth + '/' + raster.name() + '.tif'



As you can see, the elevation and azimuth of the light source are always the same. But this is how it looks:

Why?

• What software are you viewing this in? Is each tile a unique file or is the hillshade a mosaic? It looks to me like the tiles are single images which have been stretched by default, if you mosaic or build a VRT of the hillshade tiles the contrast stretch should be applied over all the tiles the same. – Michael Stimson Nov 9 '18 at 0:08
• It is viewed in QGIS. The code shown above generates a TIFF image for each tile, and it is at this point that the inconsistent shading occurs. Agreed, it does look as if the contrast is being stretched, but I am not sure why or how to prevent it. Once generated I dragged and dropped the images into QGIS with the result as shown. – wotnot Nov 9 '18 at 1:27
• ArcMap does the same thing, I suggest creating a VRT with GDALBuildVRT (from the command line). A VRT is an XML file that points to your existing raster so is fast to create and takes up only a little space then add the VRT to your QGIS project. Your other option is to go to each hillshade tile layer and turn the stretching off in the layer properties, I think it's MIN-MAX or 'standard deviations' by default; because each tile has different statistics the stretched values do not match. – Michael Stimson Nov 9 '18 at 1:33
• Thanks for the info ; I will investigate. First option wouldn't necessarily work since the hillshading is done within a plugin and should be fully automatic. Turning off stretching for each raster layer (before generating images) sounds like a better bet. I could presumably automate that. – wotnot Nov 9 '18 at 1:45
• Seems I need to set the contrast enhancement for the raster layer to 'no enhancement' before running the hillshading. – wotnot Nov 9 '18 at 2:38

OK... Got it. I changed approach a little bit, having realised that I don't have to run the Hillshade algorithm and generate a TIFF. I can just apply hillshade rendering to the memory raster layer.

I have now got a three stage process (repeated for each grid tile):

1. Create raster layer from xyz ASCII file
2. Set contrast enhancement to 'none'

Stages 2 and 3 can actually be done via the QGIS GUI quite easily and applied to multiple layers, but I have done it programmatically.

def ImportRaster(self, raster):

from PyQt5.QtCore import QFileInfo

fileInfo = QFileInfo(raster)
path = fileInfo.filePath()
baseName = fileInfo.baseName()

layer = QgsRasterLayer(path, baseName)

return layer if layer.isValid() else None

def setNoEnhancement(self, layer): # set contrast enhancement to 'no enhancement'
ContrastEnhancement = QgsContrastEnhancement.NoEnhancement
myBand = layer.renderer().grayBand()
myType = layer.renderer().dataType(myBand)
myEnhancement = QgsContrastEnhancement(myType)
myEnhancement.setContrastEnhancementAlgorithm(ContrastEnhancement, True)
layer.renderer().setContrastEnhancement(myEnhancement)

r = QgsHillshadeRenderer(layer.dataProvider(), 1, 315, 45)
layer.setRenderer(r)