TransWikia.com

Importing QGIS3 processing tools in standalone script

Geographic Information Systems Asked by alphabetasoup on May 7, 2021

Inspired by this question, but for QGIS 3 (and therefore Python 3), I would like to use the QGIS processing algorithms in a standalone Python script without a GUI, with a standard installation of Ubuntu Linux.

A simple import processing is insufficient:

import processing
processing.run(
   "qgis:rasterlayerstatistics",
   {
       'INPUT': .'/somefile.tif',
       'BAND': 1,
       'OUTPUT_HTML_FILE': './result.html'
   }
)

Results in:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ModuleNotFoundError: No module named 'processing'

How do you get access to the QGIS processing module to use the QGIS processing algorithms in a standalone Python script (not the QGIS interpreter)?

One Answer

This is an example of getting access to processing to run the QGIS "raster statistics" process, which returns useful information about a raster layer. In particular, raster statistics is useful for obtaining the sum of all values in a raster, which (AFAIK) cannot be done in GDAL alone.

#!/usr/bin/env python3
import os
import sys
import warnings
from functools import wraps


def ignore_warnings(f):
    @wraps(f)
    def inner(*args, **kwargs):
        with warnings.catch_warnings(record=True) as w:
            warnings.simplefilter("ignore")
            response = f(*args, **kwargs)
        return response
    return inner


def import_qgis_processing():
    sys.path.append('/usr/lib/qgis')
    sys.path.append('/usr/share/qgis/python/plugins')
    from qgis.core import QgsApplication, QgsProcessingFeedback, QgsRasterLayer
    app = QgsApplication([], False)
    feedback = QgsProcessingFeedback()
    return (app, feedback, QgsRasterLayer)


app, feedback, QgsRasterLayer = import_qgis_processing()
app.initQgis()


@ignore_warnings # Ignored because we want the output of this script to be a single value, and "import processing" is noisy
def initialise_processing(app):
    from qgis.analysis import QgsNativeAlgorithms
    import processing
    from processing.core.Processing import Processing
    Processing.initialize()
    app.processingRegistry().addProvider(QgsNativeAlgorithms())
    return (app, processing,)


def check_input_validity(QgsRasterLayer):
    raster = QgsRasterLayer(sys.argv[1], 'raster', 'gdal')
    if not raster.isValid():
        raise Exception('Invalid raster')


def raster_stats():
    params = {
        'INPUT': sys.argv[1],
        'BAND': 1
    }
    return processing.run(
        "qgis:rasterlayerstatistics",
        params, feedback=feedback
    )


def get_raster_stat(stat='SUM'):
    return raster_stats().get(stat)


app, processing = initialise_processing(app)
check_input_validity(QgsRasterLayer)
print(get_raster_stat(stat=sys.argv[2]))
app.exitQgis()

The ignore_warnings wrapper function is included because without it there are three deprecation warnings emitted when importing processing, and I wanted the script to have a simple output to stdout. You can leave that out if desired.

Importing modules within functions is done to control the order of import, and to stop linters (e.g. autopep8) from attempting to move all import statements to the top.

The key places to include in sys.path are:

  • /usr/lib/qgis
  • /usr/share/qgis/python/plugins

These would be different on different operating systems, and probably in different Linux distributions.

This script can be run like: ./rasterstats.py ./somefile.tif SUM, and it would output the sum of all values in the raster to stdout (ignoring no-data values if present). MAX, MIN, etc. work also.

The key functions are import_qgis_processing and initialise_processing.

Correct answer by alphabetasoup on May 7, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP