PyQGIS Error – How to Fix ‘Could Not Load Source Layer for MASK: Invalid Value’ While Iterating Over Features

clipiteratorpyqgisqgsfeaturerequest

I have just started using PyQGIS and need to loop over parcels in a vector layer to clip a raster layer.

For each parcel, I want to generate a .tif file with the feature.id() in the filename. I will also be saving the attributes in a separate .csv/.txt file by the same name. Because of this, I can't run the script using the iterator in the GUI.

This is what I have come up with thus far:

raster = 'C:/Datasets/orthophotos/OMWRGB21VL_K14_K15/OMWRGB21_VL_K14_K15.tif'
Lbgbrprc = 'C:/Datasets/Landbouwgebruikspercelen/Landbouwgebruikspercelen_2020/Shapefile/Lbgbrprc20_SintNiklaas.shp'
Lbgbrprc = QgsVectorLayer(Lbgbrprc, 'landbouw', 'ogr')

params = {
    'ALPHA_BAND' : False,
    'CROP_TO_CUTLINE' : True,
    'DATA_TYPE' : 0,
    'EXTRA' : '',
    'INPUT' : raster,
    'KEEP_RESOLUTION' : False,
    'MULTITHREADING' : False,
    'NODATA' : None,
    'OPTIONS' : '',
    'SET_RESOLUTION' : False,
    'SOURCE_CRS' : QgsCoordinateReferenceSystem('EPSG:31370'),
    'TARGET_CRS' : QgsCoordinateReferenceSystem('EPSG:31370'),
    'X_RESOLUTION' : None,
    'Y_RESOLUTION' : None
}

request = QgsFeatureRequest()
for feature in Lbgbrprc.getFeatures(request):
    if int(feature.id()) < 5:
        print(type(feature)) # <class 'qgis._core.QgsFeature'>
        params['MASK'] = feature
        params['OUTPUT'] = 'C:/Output/ortho_Lbgbrprc/{}.tif'.format(feature.id())
        
        processing.run("gdal:cliprasterbymasklayer", params)

This is the error I get:

Could not load source layer for MASK: invalid value

I think the issue is that the 'MASK' parameter needs to be a QgsVectorLayer not a QgsFeature, which is what "feature" is now. How do I go about this?

Best Answer

Apparently, the type of Mask layer should be a [vector: polygon] i.e. QgsVectorLayer, see documentation.

Also, visible via processing.algorithmHelp("gdal:cliprasterbymasklayer"):

...
MASK: Mask layer

    Parameter type: QgsProcessingParameterFeatureSource

    Accepted data types:
        - str: layer ID
        - str: layer name
        - str: layer source
        - QgsProcessingFeatureSourceDefinition
        - QgsProperty
        - QgsVectorLayer
...

So, one shall modify this parameter:

params['MASK'] = feature

as was also mentioned by @MrXsquared to this:

params['MASK'] = Lbgbrprc.materialize(QgsFeatureRequest().setFilterFid(feature.id()))

Another option, that can be less resource-consuming, utilizes the QgsProcessingFeatureSourceDefinition class.

Input:

input

from os.path import abspath
from qgis import processing
from qgis.core import QgsProject

project_path = abspath('C:/Users/Taras/Downloads/GIS data/')

vector_layer = QgsProject.instance().mapLayersByName('Lbgbrprc21_selection')[0]
raster_layer = QgsProject.instance().mapLayersByName('OMWRGB14VL_K338z')[0]

params = {
    'ALPHA_BAND' : False,
    'CROP_TO_CUTLINE' : True,
    'DATA_TYPE' : 0,
    'EXTRA' : '',
    'INPUT' : raster_layer,
    'KEEP_RESOLUTION' : False,
    'MULTITHREADING' : False,
    'NODATA' : None,
    'OPTIONS' : '',
    'SET_RESOLUTION' : False,
    'SOURCE_CRS' : QgsCoordinateReferenceSystem('EPSG:31370'),
    'TARGET_CRS' : QgsCoordinateReferenceSystem('EPSG:31370'),
    'X_RESOLUTION' : None,
    'Y_RESOLUTION' : None
}

for feature in vector_layer.getFeatures():
    if int(feature.id()) < 5:
        vector_layer.select(feature.id())
        params['MASK'] = QgsProcessingFeatureSourceDefinition(vector_layer.id(), True)
        params['OUTPUT'] = f"{project_path}/{feature.id()}.tif"
        processing.run("gdal:cliprasterbymasklayer", params)
        vector_layer.removeSelection()

Outputs:

outputs


References:

Related Question