1

For training purposes I'm writing a QGIS 3.6 Python script. The script takes as inputs a raster layer and band, and three float numbers (refmult, refadd, sunel) and computes a simple formula: ((layer@band * refmult + refadd) / sin(sunel * 3.14159/180)

It seems passing the tree float numbers as parameters to the formula on gdal:rastercalculator is not as simple, since the result is a ful NaN raster (when I hardcode the float numbers on the code, the result is fine).

How to pass the input numbers to the formula?

Here is the full script:

from qgis.core import QgsProcessing
from qgis.core import QgsProcessingAlgorithm
from qgis.core import QgsProcessingMultiStepFeedback
from qgis.core import QgsProcessingParameterBand
from qgis.core import QgsProcessingParameterRasterLayer
from qgis.core import QgsProcessingParameterNumber
from qgis.core import QgsProcessingParameterRasterDestination
import processing


class RasterCalculator(QgsProcessingAlgorithm):

def initAlgorithm(self, config=None):
    self.addParameter(QgsProcessingParameterBand('band', 'band', parentLayerParameterName='rasterlayer', allowMultiple=False, defaultValue=None))
    self.addParameter(QgsProcessingParameterRasterLayer('rasterlayer', 'layer', defaultValue=None))
    self.addParameter(QgsProcessingParameterNumber('refadd', 'refadd', type=QgsProcessingParameterNumber.Double, defaultValue=-0.1))
    self.addParameter(QgsProcessingParameterNumber('refmult', 'refmult', type=QgsProcessingParameterNumber.Double, defaultValue=2E-5))
    self.addParameter(QgsProcessingParameterNumber('sunel', 'sunel', type=QgsProcessingParameterNumber.Double, defaultValue=60))
    self.addParameter(QgsProcessingParameterRasterDestination('Reflectance', 'reflectance', createByDefault=True, defaultValue=None))

def processAlgorithm(self, parameters, context, model_feedback):
    # Use a multi-step feedback, so that individual child algorithm progress reports are adjusted for the
    # overall progress through the model
    feedback = QgsProcessingMultiStepFeedback(1, model_feedback)
    results = {}
    outputs = {}

    # Raster calculator
    alg_params = {
        'BAND_A': 1,
        'BAND_B': None,
        'BAND_C': None,
        'BAND_D': None,
        'BAND_E': None,
        'BAND_F': None,
        'FORMULA': '(A* refmult +(refadd) ) /( sin(sunel * 3.14159/180  ) )',
        'INPUT_A': parameters['rasterlayer'],
        'INPUT_B': None,
        'INPUT_C': None,
        'INPUT_D': None,
        'INPUT_E': None,
        'INPUT_F': None,
        'NO_DATA': None,
        'OPTIONS': '',
        'RTYPE': 5,
        'OUTPUT': parameters['Reflectance']
    }
    outputs['RasterCalculator'] = processing.run('gdal:rastercalculator', alg_params, context=context, feedback=feedback, is_child_algorithm=True)
    results['Reflectance'] = outputs['RasterCalculator']['OUTPUT']
    return results

def name(self):
    return 'raster calculator'

def displayName(self):
    return 'raster calculator'

def group(self):
    return 'remote sensing'

def groupId(self):
    return 'remote sensing'

def createInstance(self):
    return RasterCalculator()
1

If you want to reference an input parameter, you would need to call it inside your processAlgorithm() function using something like:

refadd = self.parameterAsString(parameters, 'refadd', context)
refmult = self.parameterAsString(parameters, 'refmult', context)
sunel = self.parameterAsString(parameters, 'sunel', context)

We call the parameter as a string as these will be used inside the 'FORMULA' parameter which requires a string input. You would then need to call the parameters inside:

'FORMULA': '(A* ' + refmult + '+(' + refadd + ') ) /( sin(' + sunel +' * 3.14159/180  ) )',

So your complete script could look like:

from qgis.core import (QgsProcessing,
                        QgsProcessingAlgorithm,
                        QgsProcessingMultiStepFeedback,
                        QgsProcessingParameterBand,
                        QgsProcessingParameterRasterLayer,
                        QgsProcessingParameterNumber,
                        QgsProcessingParameterRasterDestination)
import processing


class RasterCalculator(QgsProcessingAlgorithm):
    def initAlgorithm(self, config=None):
        self.addParameter(QgsProcessingParameterBand('band', 'band', parentLayerParameterName='rasterlayer', allowMultiple=False, defaultValue=None))
        self.addParameter(QgsProcessingParameterRasterLayer('rasterlayer', 'layer', defaultValue=None))
        self.addParameter(QgsProcessingParameterNumber('refadd', 'refadd', type=QgsProcessingParameterNumber.Double, defaultValue=-0.1))
        self.addParameter(QgsProcessingParameterNumber('refmult', 'refmult', type=QgsProcessingParameterNumber.Double, defaultValue=2E-5))
        self.addParameter(QgsProcessingParameterNumber('sunel', 'sunel', type=QgsProcessingParameterNumber.Double, defaultValue=60))
        self.addParameter(QgsProcessingParameterRasterDestination('Reflectance', 'reflectance', createByDefault=True, defaultValue=None))

    def processAlgorithm(self, parameters, context, model_feedback):
        # Use a multi-step feedback, so that individual child algorithm progress reports are adjusted for the
        # overall progress through the model
        feedback = QgsProcessingMultiStepFeedback(1, model_feedback)
        results = {}
        outputs = {}

        refadd = self.parameterAsString(parameters, 'refadd', context)
        refmult = self.parameterAsString(parameters, 'refmult', context)
        sunel = self.parameterAsString(parameters, 'sunel', context)

        # Raster calculator
        alg_params = {
            'BAND_A': 1,
            'BAND_B': None,
            'BAND_C': None,
            'BAND_D': None,
            'BAND_E': None,
            'BAND_F': None,
            'FORMULA': '(A* ' + refmult + '+(' + refadd + ') ) /( sin(' + sunel +' * 3.14159/180  ) )',
            'INPUT_A': parameters['rasterlayer'],
            'INPUT_B': None,
            'INPUT_C': None,
            'INPUT_D': None,
            'INPUT_E': None,
            'INPUT_F': None,
            'NO_DATA': None,
            'OPTIONS': '',
            'RTYPE': 5,
            'OUTPUT': parameters['Reflectance']
        }

        outputs['RasterCalculator'] = processing.run('gdal:rastercalculator', alg_params, context=context, feedback=feedback, is_child_algorithm=True)
        results['Reflectance'] = outputs['RasterCalculator']['OUTPUT']
        return results

    def name(self):
        return 'raster calculator'

    def displayName(self):
        return 'raster calculator'

    def group(self):
        return 'remote sensing'

    def groupId(self):
        return 'remote sensing'

    def createInstance(self):
        return RasterCalculator()
| improve this answer | |
  • 1
    Worked perfectly! Thanks for the explanation on including the call to the parameters from INSIDE the function. – Temporalista May 20 '19 at 16:58
  • @Temporalista - Most welcome! Glad it helped :) – Joseph May 21 '19 at 9:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.