[processing] restore clip raster by mask algorithm

This commit is contained in:
Alexander Bruy 2017-09-06 11:18:13 +03:00
parent 1744ad7114
commit 587907e003
4 changed files with 230 additions and 302 deletions

View File

@ -61,6 +61,8 @@ class ClipByExtent(GdalAlgorithm):
def initAlgorithm(self, config=None): def initAlgorithm(self, config=None):
self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT, self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT,
self.tr('Input layer'))) self.tr('Input layer')))
self.addParameter(QgsProcessingParameterExtent(self.EXTENT,
self.tr('Clipping extent')))
self.addParameter(QgsProcessingParameterNumber(self.NODATA, self.addParameter(QgsProcessingParameterNumber(self.NODATA,
self.tr('Assign a specified nodata value to output bands'), self.tr('Assign a specified nodata value to output bands'),
type=QgsProcessingParameterNumber.Double, type=QgsProcessingParameterNumber.Double,
@ -68,8 +70,6 @@ class ClipByExtent(GdalAlgorithm):
maxValue=99999999.999999, maxValue=99999999.999999,
defaultValue=0.0, defaultValue=0.0,
optional=True)) optional=True))
self.addParameter(QgsProcessingParameterExtent(self.EXTENT,
self.tr('Clipping extent')))
options_param = QgsProcessingParameterString(self.OPTIONS, options_param = QgsProcessingParameterString(self.OPTIONS,
self.tr('Additional creation parameters'), self.tr('Additional creation parameters'),

View File

@ -16,7 +16,6 @@
* * * *
*************************************************************************** ***************************************************************************
""" """
from builtins import str
__author__ = 'Alexander Bruy' __author__ = 'Alexander Bruy'
__date__ = 'September 2013' __date__ = 'September 2013'
@ -30,66 +29,80 @@ import os
from qgis.PyQt.QtGui import QIcon from qgis.PyQt.QtGui import QIcon
from qgis.core import QgsProcessingUtils from qgis.core import (QgsRasterFileWriter,
from osgeo import gdal QgsProcessing,
QgsProcessingParameterDefinition,
from processing.core.parameters import (ParameterRaster, QgsProcessingParameterVectorLayer,
ParameterVector, QgsProcessingParameterRasterLayer,
ParameterBoolean, QgsProcessingParameterEnum,
ParameterString, QgsProcessingParameterString,
ParameterSelection) QgsProcessingParameterNumber,
QgsProcessingParameterBoolean,
from processing.core.outputs import OutputRaster QgsProcessingParameterRasterDestination)
from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm
from processing.algs.gdal.GdalUtils import GdalUtils from processing.algs.gdal.GdalUtils import GdalUtils
from processing.tools import dataobjects
pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0] pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0]
class ClipByMask(GdalAlgorithm): class ClipByMask(GdalAlgorithm):
INPUT = 'INPUT' INPUT = 'INPUT'
OUTPUT = 'OUTPUT'
NO_DATA = 'NO_DATA'
MASK = 'MASK' MASK = 'MASK'
NODATA = 'NODATA'
ALPHA_BAND = 'ALPHA_BAND' ALPHA_BAND = 'ALPHA_BAND'
CROP_TO_CUTLINE = 'CROP_TO_CUTLINE' CROP_TO_CUTLINE = 'CROP_TO_CUTLINE'
KEEP_RESOLUTION = 'KEEP_RESOLUTION' KEEP_RESOLUTION = 'KEEP_RESOLUTION'
OPTIONS = 'OPTIONS' OPTIONS = 'OPTIONS'
RTYPE = 'RTYPE' DATA_TYPE = 'DATA_TYPE'
TYPE = ['Byte', 'Int16', 'UInt16', 'UInt32', 'Int32', 'Float32', 'Float64'] OUTPUT = 'OUTPUT'
TYPES = ['Byte', 'Int16', 'UInt16', 'UInt32', 'Int32', 'Float32', 'Float64', 'CInt16', 'CInt32', 'CFloat32', 'CFloat64']
def __init__(self): def __init__(self):
super().__init__() super().__init__()
def initAlgorithm(self, config=None): def initAlgorithm(self, config=None):
self.addParameter(ParameterRaster(self.INPUT, self.tr('Input layer'), False)) self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT,
self.addParameter(ParameterVector(self.MASK, self.tr('Mask layer'), self.tr('Input layer')))
[dataobjects.TYPE_VECTOR_POLYGON])) self.addParameter(QgsProcessingParameterVectorLayer(self.MASK,
self.addParameter(ParameterString(self.NO_DATA, self.tr('Mask layer'),
self.tr("Nodata value, leave blank to take the nodata value from input"), [QgsProcessing.TypeVectorPolygon]))
'', optional=True)) self.addParameter(QgsProcessingParameterNumber(self.NODATA,
self.addParameter(ParameterBoolean(self.ALPHA_BAND, self.tr('Assign a specified nodata value to output bands'),
self.tr('Create and output alpha band'), type=QgsProcessingParameterNumber.Double,
False)) minValue=-99999999.999999,
self.addParameter(ParameterBoolean(self.CROP_TO_CUTLINE, maxValue=99999999.999999,
self.tr('Crop the extent of the target dataset to the extent of the cutline'), defaultValue=0.0,
True)) optional=True))
self.addParameter(ParameterBoolean(self.KEEP_RESOLUTION, self.addParameter(QgsProcessingParameterBoolean(self.ALPHA_BAND,
self.tr('Keep resolution of output raster'), self.tr('Create and output alpha band'),
False)) defaultValue=False))
self.addParameter(ParameterString(self.OPTIONS, self.addParameter(QgsProcessingParameterBoolean(self.CROP_TO_CUTLINE,
self.tr('Additional creation options'), self.tr('Crop the extent of the target dataset to the extent of the cutline'),
optional=True, defaultValue=True))
metadata={'widget_wrapper': 'processing.algs.gdal.ui.RasterOptionsWidget.RasterOptionsWidgetWrapper'})) self.addParameter(QgsProcessingParameterBoolean(self.KEEP_RESOLUTION,
self.addParameter(ParameterSelection(self.RTYPE, self.tr('Keep resolution of output raster'),
self.tr('Output raster type'), defaultValue=False))
self.TYPE, 5))
self.addOutput(OutputRaster(self.OUTPUT, self.tr('Clipped (mask)'))) options_param = QgsProcessingParameterString(self.OPTIONS,
self.tr('Additional creation parameters'),
defaultValue='',
optional=True)
options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.FlagAdvanced)
options_param.setMetadata({
'widget_wrapper': {
'class': 'processing.algs.gdal.ui.RasterOptionsWidget.RasterOptionsWidgetWrapper'}})
self.addParameter(options_param)
self.addParameter(QgsProcessingParameterEnum(self.DATA_TYPE,
self.tr('Output data type'),
self.TYPES,
allowMultiple=False,
defaultValue=5))
self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT,
self.tr('Clipped (mask)')))
def name(self): def name(self):
return 'cliprasterbymasklayer' return 'cliprasterbymasklayer'
@ -104,60 +117,48 @@ class ClipByMask(GdalAlgorithm):
return self.tr('Raster extraction') return self.tr('Raster extraction')
def getConsoleCommands(self, parameters, context, feedback): def getConsoleCommands(self, parameters, context, feedback):
out = self.getOutputValue(self.OUTPUT) inLayer = self.parameterAsRasterLayer(parameters, self.INPUT, context)
mask = self.getParameterValue(self.MASK)
context = dataobjects.createContext()
maskLayer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.MASK), context)
ogrMask = GdalUtils.ogrConnectionString(mask, context)[1:-1]
noData = self.getParameterValue(self.NO_DATA)
opts = self.getParameterValue(self.OPTIONS)
if noData is not None: maskLayer = self.parameterAsVectorLayer(parameters, self.MASK, context)
noData = str(noData) connectionString = GdalUtils.ogrConnectionString(maskLayer.source(), context)
addAlphaBand = self.getParameterValue(self.ALPHA_BAND) nodata = self.parameterAsDouble(parameters, self.NODATA, context)
cropToCutline = self.getParameterValue(self.CROP_TO_CUTLINE) options = self.parameterAsString(parameters, self.OPTIONS, context)
keepResolution = self.getParameterValue(self.KEEP_RESOLUTION) out = self.parameterAsOutputLayer(parameters, self.OUTPUT, context)
arguments = [] arguments = []
arguments.append('-ot') arguments.append('-ot')
arguments.append(self.TYPE[self.getParameterValue(self.RTYPE)]) arguments.append(self.TYPES[self.parameterAsEnum(parameters, self.DATA_TYPE, context)])
arguments.append('-q')
arguments.append('-of')
arguments.append(GdalUtils.getFormatShortNameFromFilename(out))
if noData and len(noData) > 0:
arguments.append('-dstnodata')
arguments.append(noData)
if keepResolution: arguments.append('-of')
r = gdal.Open(self.getParameterValue(self.INPUT)) arguments.append(QgsRasterFileWriter.driverForExtension(os.path.splitext(out)[1]))
geoTransform = r.GetGeoTransform()
r = None if self.parameterAsBool(self.KEEP_RESOLUTION):
arguments.append('-tr') arguments.append('-tr')
arguments.append(str(geoTransform[1])) arguments.append(str(inLayer.rasterUnitsPerPixelX()))
arguments.append(str(geoTransform[5])) arguments.append(str(-inLayer.rasterUnitsPerPixelY()))
arguments.append('-tap') arguments.append('-tap')
arguments.append('-cutline') arguments.append('-cutline')
arguments.append(ogrMask) arguments.append(connectionString)
if maskLayer and maskLayer.subsetString() != '': if maskLayer.subsetString():
arguments.append('-cwhere') arguments.append('-cwhere')
arguments.append(maskLayer.subsetString()) arguments.append(maskLayer.subsetString())
if cropToCutline: if self.parameterAsBool(self.CROP_TO_CUTLINE):
arguments.append('-crop_to_cutline') arguments.append('-crop_to_cutline')
if addAlphaBand: if self.parameterAsBool(self.ALPHA_BAND):
arguments.append('-dstalpha') arguments.append('-dstalpha')
if opts: if nodata:
arguments.append('-dstnodata {}'.format(nodata))
if options:
arguments.append('-co') arguments.append('-co')
arguments.append(opts) arguments.append(options)
if GdalUtils.version() in [2010000, 2010100]: arguments.append(inLayer.source())
arguments.append("--config GDALWARP_IGNORE_BAD_CUTLINE YES")
arguments.append(self.getParameterValue(self.INPUT))
arguments.append(out) arguments.append(out)
return ['gdalwarp', GdalUtils.escapeAndJoin(arguments)] return ['gdalwarp', GdalUtils.escapeAndJoin(arguments)]

View File

@ -37,6 +37,7 @@ from .AssignProjection import AssignProjection
from .aspect import aspect from .aspect import aspect
from .buildvrt import buildvrt from .buildvrt import buildvrt
from .ClipByExtent import ClipByExtent from .ClipByExtent import ClipByExtent
from .ClipByMask import ClipByMask
from .ColorRelief import ColorRelief from .ColorRelief import ColorRelief
from .contour import contour from .contour import contour
from .fillnodata import fillnodata from .fillnodata import fillnodata
@ -63,7 +64,6 @@ from .warp import warp
# from .merge import merge # from .merge import merge
# from .gdaladdo import gdaladdo # from .gdaladdo import gdaladdo
# from .ClipByMask import ClipByMask
# from .rasterize import rasterize # from .rasterize import rasterize
# from .proximity import proximity # from .proximity import proximity
# from .extractprojection import ExtractProjection # from .extractprojection import ExtractProjection
@ -140,6 +140,7 @@ class GdalAlgorithmProvider(QgsProcessingProvider):
aspect(), aspect(),
buildvrt(), buildvrt(),
ClipByExtent(), ClipByExtent(),
ClipByMask(),
ColorRelief(), ColorRelief(),
contour(), contour(),
fillnodata(), fillnodata(),
@ -165,7 +166,6 @@ class GdalAlgorithmProvider(QgsProcessingProvider):
warp(), warp(),
# merge(), # merge(),
# gdaladdo(), # gdaladdo(),
# ClipByMask(),
# rasterize(), # rasterize(),
# proximity(), # proximity(),
# ExtractProjection(), # ExtractProjection(),

View File

@ -16,228 +16,6 @@ tests:
- 'Band 1 Block=16x14 Type=Float32, ColorInterp=Gray' - 'Band 1 Block=16x14 Type=Float32, ColorInterp=Gray'
- ' NoData Value=-32768' - ' NoData Value=-32768'
# - algorithm: gdal:ogrinfo
# name: ogrinfo
# params:
# INPUT:
# name: lines.gml
# type: vector
# SUMMARY_ONLY: 'True'
# results:
# OUTPUT:
# name: expected/gdal/vector_info.html
# type: regex
# rules:
# - 'Extent: \(-1.000000, -3.000000\) - \(11.000000, 5.000000\)'
# - 'Geometry: Line String'
# - 'Feature Count: [6|7]' # On some platforms returns 6 instead of 7...
#
# - algorithm: gdal:buffervectors
# name: Buffer lines
# params:
# DISSOLVEALL: false
# DISTANCE: 1.0
# GEOMETRY: geometry
# INPUT_LAYER:
# name: lines.gml
# type: vector
# MULTI: false
# results:
# OUTPUT_LAYER:
# name: expected/gdal/buffer_lines.gml
# type: vector
# compare:
# geometry:
# precision: 7
# expectedFailure:
# - int(1)
#
# - algorithm: gdal:buffervectors
# name: Basic polygon buffer
# params:
# DISSOLVEALL: false
# DISTANCE: 0.5
# GEOMETRY: geometry
# INPUT_LAYER:
# name: polys.gml
# type: vector
# MULTI: false
# results:
# OUTPUT_LAYER:
# name: expected/gdal/buffer_polys.gml
# type: vector
# compare:
# geometry:
# precision: 7
#
# - algorithm: gdal:buffervectors
# name: Polygon buffer with dissolve
# params:
# DISSOLVEALL: true
# DISTANCE: 0.5
# GEOMETRY: geometry
# INPUT_LAYER:
# name: polys.gml
# type: vector
# MULTI: false
# results:
# OUTPUT_LAYER:
# name: expected/gdal/buffer_polys_dissolve.gml
# type: vector
# compare:
# geometry:
# precision: 7
#
- algorithm: gdal:createpointsalonglines
name: Points along lines
params:
DISTANCE: 0.25
GEOMETRY: geometry
INPUT:
name: lines.gml
type: vector
results:
OUTPUT:
name: expected/gdal/points_along_lines.gml
type: vector
pk: fid
compare:
ignore_crs_check: true
# - algorithm: gdal:offsetlinesforlines
# name: Offset lines for lines (right-handed)
# params:
# GEOMETRY: geometry
# INPUT_LAYER:
# name: lines.gml
# type: vector
# RADIUS: -0.5
# results:
# OUTPUT_LAYER:
# name: expected/gdal/offset_lines.gml
# type: vector
# compare:
# geometry:
# precision: 7
#
# - algorithm: gdal:singlesidedbufferforlines
# name: One-side buffer for lines (left-handed)
# params:
# DISSOLVEALL: false
# GEOMETRY: geometry
# INPUT_LAYER:
# name: lines.gml
# type: vector
# LEFTRIGHT: '1'
# MULTI: false
# RADIUS: 0.5
# results:
# OUTPUT_LAYER:
# name: expected/gdal/one_side_buffer.gml
# type: vector
# compare:
# geometry:
# precision: 7
#
# - algorithm: gdal:cliprasterbyextent
# name: Clip raster by extent and change no data values
# params:
# BIGTIFF: '0'
# COMPRESS: '4'
# INPUT:
# name: dem.tif
# type: raster
# JPEGCOMPRESSION: 75
# NO_DATA: '-9999'
# PREDICTOR: 1
# PROJWIN: 18.67460436727692,18.698371162148714,45.78995019401027,45.804344168369234
# RTYPE: '5'
# TFW: false
# TILED: false
# ZLEVEL: 6
# results:
# OUTPUT:
# hash: df5de501bcec0c10f738d77f3b48d5545b48f0a22e0e028a8b1ccbe7
# type: rasterhash
#
# - algorithm: gdal:cliprasterbymasklayer
# name: Clip raster by mask layer
# params:
# ALPHA_BAND: false
# BIGTIFF: '0'
# COMPRESS: '4'
# CROP_TO_CUTLINE: true
# INPUT:
# name: dem.tif
# type: raster
# JPEGCOMPRESSION: 75
# KEEP_RESOLUTION: false
# MASK:
# name: custom/polygon_mask.gml
# type: vector
# NO_DATA: ''
# PREDICTOR: 1
# RTYPE: '5'
# TFW: false
# TILED: false
# ZLEVEL: 6
# results:
# OUTPUT:
# hash: 4f4720e4efe59a7f238f622659917bbeb5262369d15d5e2917dbcf8b
# type: rasterhash
#
# - algorithm: gdal:cliprasterbymasklayer
# name: Clip raster by mask layer and change no data value
# params:
# ALPHA_BAND: false
# BIGTIFF: '0'
# COMPRESS: '4'
# CROP_TO_CUTLINE: true
# INPUT:
# name: dem.tif
# type: raster
# JPEGCOMPRESSION: 75
# KEEP_RESOLUTION: false
# MASK:
# name: custom/polygon_mask.gml
# type: vector
# NO_DATA: '-9999'
# PREDICTOR: 1
# RTYPE: '5'
# TFW: false
# TILED: false
# ZLEVEL: 6
# results:
# OUTPUT:
# hash: 1e0252e63c65dcf4ed1f2b17d2490d3e0331aeb59d8f59b59554f442
# type: rasterhash
#
# - algorithm: gdal:cliprasterbymasklayer
# name: Clip raster by mask layer and add alpha band
# params:
# ALPHA_BAND: true
# BIGTIFF: '0'
# COMPRESS: '4'
# CROP_TO_CUTLINE: true
# INPUT:
# name: dem.tif
# type: raster
# JPEGCOMPRESSION: 75
# KEEP_RESOLUTION: false
# MASK:
# name: custom/polygon_mask.gml
# type: vector
# NO_DATA: ''
# PREDICTOR: 1
# RTYPE: '5'
# TFW: false
# TILED: false
# ZLEVEL: 6
# results:
# OUTPUT:
# hash: 8f69431c6ff7db5174c1ca8e879ae39582fd4ce86f9b53edae0f38ce
# type: rasterhash
- algorithm: gdal:aspect - algorithm: gdal:aspect
name: Aspect name: Aspect
params: params:
@ -452,6 +230,155 @@ tests:
hash: 9913a7c0e1ced2c2ce1cd8f0e8103475bc2b0dd4d1d0adafe4920f93 hash: 9913a7c0e1ced2c2ce1cd8f0e8103475bc2b0dd4d1d0adafe4920f93
type: rasterhash type: rasterhash
- algorithm: gdal:cliprasterbymasklayer
name: Clip raster by mask layer
params:
ALPHA_BAND: false
BIGTIFF: '0'
COMPRESS: '4'
CROP_TO_CUTLINE: true
INPUT:
name: dem.tif
type: raster
JPEGCOMPRESSION: 75
KEEP_RESOLUTION: false
MASK:
name: custom/polygon_mask.gml
type: vector
NO_DATA: ''
PREDICTOR: 1
RTYPE: '5'
TFW: false
TILED: false
ZLEVEL: 6
results:
OUTPUT:
hash: 4f4720e4efe59a7f238f622659917bbeb5262369d15d5e2917dbcf8b
type: rasterhash
# - algorithm: gdal:ogrinfo
# name: ogrinfo
# params:
# INPUT:
# name: lines.gml
# type: vector
# SUMMARY_ONLY: 'True'
# results:
# OUTPUT:
# name: expected/gdal/vector_info.html
# type: regex
# rules:
# - 'Extent: \(-1.000000, -3.000000\) - \(11.000000, 5.000000\)'
# - 'Geometry: Line String'
# - 'Feature Count: [6|7]' # On some platforms returns 6 instead of 7...
#
# - algorithm: gdal:buffervectors
# name: Buffer lines
# params:
# DISSOLVEALL: false
# DISTANCE: 1.0
# GEOMETRY: geometry
# INPUT_LAYER:
# name: lines.gml
# type: vector
# MULTI: false
# results:
# OUTPUT_LAYER:
# name: expected/gdal/buffer_lines.gml
# type: vector
# compare:
# geometry:
# precision: 7
# expectedFailure:
# - int(1)
#
# - algorithm: gdal:buffervectors
# name: Basic polygon buffer
# params:
# DISSOLVEALL: false
# DISTANCE: 0.5
# GEOMETRY: geometry
# INPUT_LAYER:
# name: polys.gml
# type: vector
# MULTI: false
# results:
# OUTPUT_LAYER:
# name: expected/gdal/buffer_polys.gml
# type: vector
# compare:
# geometry:
# precision: 7
#
# - algorithm: gdal:buffervectors
# name: Polygon buffer with dissolve
# params:
# DISSOLVEALL: true
# DISTANCE: 0.5
# GEOMETRY: geometry
# INPUT_LAYER:
# name: polys.gml
# type: vector
# MULTI: false
# results:
# OUTPUT_LAYER:
# name: expected/gdal/buffer_polys_dissolve.gml
# type: vector
# compare:
# geometry:
# precision: 7
#
- algorithm: gdal:createpointsalonglines
name: Points along lines
params:
DISTANCE: 0.25
GEOMETRY: geometry
INPUT:
name: lines.gml
type: vector
results:
OUTPUT:
name: expected/gdal/points_along_lines.gml
type: vector
pk: fid
compare:
ignore_crs_check: true
# - algorithm: gdal:offsetlinesforlines
# name: Offset lines for lines (right-handed)
# params:
# GEOMETRY: geometry
# INPUT_LAYER:
# name: lines.gml
# type: vector
# RADIUS: -0.5
# results:
# OUTPUT_LAYER:
# name: expected/gdal/offset_lines.gml
# type: vector
# compare:
# geometry:
# precision: 7
#
# - algorithm: gdal:singlesidedbufferforlines
# name: One-side buffer for lines (left-handed)
# params:
# DISSOLVEALL: false
# GEOMETRY: geometry
# INPUT_LAYER:
# name: lines.gml
# type: vector
# LEFTRIGHT: '1'
# MULTI: false
# RADIUS: 0.5
# results:
# OUTPUT_LAYER:
# name: expected/gdal/one_side_buffer.gml
# type: vector
# compare:
# geometry:
# precision: 7
#
# - algorithm: gdal:merge # - algorithm: gdal:merge
# name: Merge 2 raster layers # name: Merge 2 raster layers
# params: # params: