Jeremy's answer is nice but I found an issue with when there is an RGB band with a value of 0
This causes, for example, a pixel in a dark area in the shadow of a tree to become nodata, because there was an RGB value there of 0
What has been working so far for me is setting nodata to all 4 bands of the image in areas where the alpha band was originally 0
The below code has been helping me so far
Curious to know if there are any more concise solutions than this
import glob, os, processing
#this is where we set the processing folders
inputFolder = "D:/Imagery 2022/QGIS Desperation Band Splitting/In/"
bandHoldFolder = "E:/Imagery 2022/QGIS Desperation Band Splitting/BandsP2/"
outputFolder = 'E:/Imagery 2022/QGIS Desperation Band Splitting/OutP2/'
os.chdir(inputFolder)
#now we use a for to count through the images
for fname in glob.glob("*.tif"):
fullPath = inputFolder + fname
print(fullPath)
if (fname[-4])!= '.':
print('Your raster extension needs to be 3 characters (I think)')
#reset the list of the split out bands
filelistBand = []
#split out the first band and set any pixels with an alpha value less than 127 to be null through a division of zero
output_raster = bandHoldFolder + fname[:-4] + "Band1.tif"
proc = processing.run("qgis:rastercalculator", {'EXPRESSION':' \"' + fname[:-4] + '@1\" * (1/(\"' + fname[:-4] + '@4\" > 127))','LAYERS':[fullPath],'CELLSIZE':0,'EXTENT':None,'CRS':None,'OUTPUT':'TEMPORARY_OUTPUT'})
tempOutput = proc['OUTPUT']
#now we need to compress these bands because they're big as, note that I'm exporting to an Australian CRS
processing.runAndLoadResults("gdal:translate", {'INPUT':tempOutput,'TARGET_CRS':QgsCoordinateReferenceSystem('EPSG:7855'),'NODATA':None,'COPY_SUBDATASETS':False,'OPTIONS':'COMPRESS=LZW|PREDICTOR=2|ZLEVEL=9|NUM_THREADS=8|BIGTIFF=IF_SAFER','EXTRA':'','DATA_TYPE':0,'OUTPUT':output_raster})
#add this to the list of bands to put in the virtual raster
filelistBand.append(output_raster)
os.remove(tempOutput)
#split out the second band
output_raster = bandHoldFolder + fname[:-4] + "Band2.tif"
proc = processing.run("qgis:rastercalculator", {'EXPRESSION':' \"' + fname[:-4] + '@2\" * (1/(\"' + fname[:-4] + '@4\" > 127))','LAYERS':[fullPath],'CELLSIZE':0,'EXTENT':None,'CRS':None,'OUTPUT':'TEMPORARY_OUTPUT'})
tempOutput = proc['OUTPUT']
processing.runAndLoadResults("gdal:translate", {'INPUT':tempOutput,'TARGET_CRS':QgsCoordinateReferenceSystem('EPSG:7855'),'NODATA':None,'COPY_SUBDATASETS':False,'OPTIONS':'COMPRESS=LZW|PREDICTOR=2|ZLEVEL=9|NUM_THREADS=8|BIGTIFF=IF_SAFER','EXTRA':'','DATA_TYPE':0,'OUTPUT':output_raster})
filelistBand.append(output_raster)
os.remove(tempOutput)
#split out the third band
output_raster = bandHoldFolder + fname[:-4] + "Band3.tif"
proc = processing.run("qgis:rastercalculator", {'EXPRESSION':' \"' + fname[:-4] + '@3\" * (1/(\"' + fname[:-4] + '@4\" > 127))','LAYERS':[fullPath],'CELLSIZE':0,'EXTENT':None,'CRS':None,'OUTPUT':'TEMPORARY_OUTPUT'})
tempOutput = proc['OUTPUT']
processing.runAndLoadResults("gdal:translate", {'INPUT':tempOutput,'TARGET_CRS':QgsCoordinateReferenceSystem('EPSG:7855'),'NODATA':None,'COPY_SUBDATASETS':False,'OPTIONS':'COMPRESS=LZW|PREDICTOR=2|ZLEVEL=9|NUM_THREADS=8|BIGTIFF=IF_SAFER','EXTRA':'','DATA_TYPE':0,'OUTPUT':output_raster})
filelistBand.append(output_raster)
os.remove(tempOutput)
fullAlphaPath = bandHoldFolder + fname[:-4] + 'Alpha.tif'
#we need to reclassify the alpha band to make sure it's either nodata or 255
processing.run("native:reclassifybytable", {'INPUT_RASTER':fullPath,'RASTER_BAND':4,'TABLE':[128,256,255],'NO_DATA':-1,'RANGE_BOUNDARIES':0,'NODATA_FOR_MISSING':True,'DATA_TYPE':1,'OUTPUT':fullAlphaPath})
filelistBand.append(fullAlphaPath)
#this is where we will send the output
print(fname[:-4])
outputVrt = outputFolder + fname[:-4] + '.vrt'
#we make a virtual raster using the list of bands that we have been appending onto
processing.runAndLoadResults("gdal:buildvirtualraster", {'INPUT':filelistBand,'RESOLUTION':0,'SEPARATE':True,'PROJ_DIFFERENCE':False,'ADD_ALPHA':False,'ASSIGN_CRS':None,'RESAMPLING':0,'SRC_NODATA':'','EXTRA':'','OUTPUT':outputVrt})
After this you can manually make a virtual raster of all of the constituent virtual rasters, before saving it out as a rendered image
The virtual raster of virtual rasters should show the blank areas as all nodata, with no gaps in between the original images
With the final rendered image showing those areas as 0 in all bands