O motivo dessa aparência aparente é que cada imagem é desenhada com uma escala de cinza esticada de imagem min para imagem max e NÃO entre a min / max global. Quando você mescla todas as imagens em uma, bem, há apenas um mínimo / máximo. O mesmo vale para o VRT, já que o VRT trata todas as imagens como uma (quando você dá uma olhada no arquivo VRT, verá as estatísticas comuns).
Quando ambos, mesclagem e VRT, não são uma opção, o script a seguir pode ajudar.
No primeiro loop, eu itero sobre todas as camadas, escolhendo os rasters e obtendo uma estimativa do intervalo mínimo / máximo. É assim que o próprio QGIS funciona. A partir desses valores mínimo / máximo, calculo o valor mínimo / máximo global
No segundo loop, os renderizadores para todas as camadas de varredura são configurados de modo que a escala de cinza seja esticada no intervalo global mínimo / máximo.
gmin = 9999
gmax = -9999
layers = []
# loop over all layers, take rasters and estimate min, max values
for layer in iface.mapCanvas().layers():
if isinstance(layer, QgsRasterLayer):
# change percentages and sample size to increase or decrease accuracy
min_max = layer.dataProvider().cumulativeCut(1, 0.02, 0.98, theSampleSize=250000)
gmin = min(gmin, min_max[0])
gmax = max(gmax, min_max[1])
layers.append(layer)
# for all rasters create a single band gray scale renderer with
# gray scale stretched across the interval [gmin..gmax]
for rasterlayer in layers:
renderer = QgsSingleBandGrayRenderer(rasterlayer.dataProvider(), 1)
# take the first band (0)
ce = QgsContrastEnhancement(rasterlayer.dataProvider().dataType(0))
ce.setContrastEnhancementAlgorithm(QgsContrastEnhancement.StretchToMinimumMaximum)
ce.setMinimumValue(gmin)
ce.setMaximumValue(gmax)
renderer.setContrastEnhancement(ce)
rasterlayer.setRenderer(renderer)
# refresh canvas to show changes
iface.mapCanvas().refresh()