retile.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. """
  2. ***************************************************************************
  3. retile.py
  4. ---------------------
  5. Date : January 2016
  6. Copyright : (C) 2016 by Médéric Ribreux
  7. Email : mederic dot ribreux at medspx dot fr
  8. ***************************************************************************
  9. * *
  10. * This program is free software; you can redistribute it and/or modify *
  11. * it under the terms of the GNU General Public License as published by *
  12. * the Free Software Foundation; either version 2 of the License, or *
  13. * (at your option) any later version. *
  14. * *
  15. ***************************************************************************
  16. """
  17. __author__ = 'Médéric Ribreux'
  18. __date__ = 'January 2016'
  19. __copyright__ = '(C) 2016, Médéric Ribreux'
  20. from qgis.core import (QgsProcessing,
  21. QgsProcessingException,
  22. QgsProcessingParameterDefinition,
  23. QgsProcessingParameterMultipleLayers,
  24. QgsProcessingParameterCrs,
  25. QgsProcessingParameterEnum,
  26. QgsProcessingParameterString,
  27. QgsProcessingParameterNumber,
  28. QgsProcessingParameterBoolean,
  29. QgsProcessingParameterFileDestination,
  30. QgsProcessingParameterFolderDestination)
  31. from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm
  32. from processing.algs.gdal.GdalUtils import GdalUtils
  33. from processing.tools.system import isWindows
  34. class retile(GdalAlgorithm):
  35. INPUT = 'INPUT'
  36. TILE_SIZE_X = 'TILE_SIZE_X'
  37. TILE_SIZE_Y = 'TILE_SIZE_Y'
  38. OVERLAP = 'OVERLAP'
  39. LEVELS = 'LEVELS'
  40. SOURCE_CRS = 'SOURCE_CRS'
  41. FORMAT = 'FORMAT'
  42. RESAMPLING = 'RESAMPLING'
  43. OPTIONS = 'OPTIONS'
  44. EXTRA = 'EXTRA'
  45. DATA_TYPE = 'DATA_TYPE'
  46. DELIMITER = 'DELIMITER'
  47. ONLY_PYRAMIDS = 'ONLY_PYRAMIDS'
  48. DIR_FOR_ROW = 'DIR_FOR_ROW'
  49. OUTPUT = 'OUTPUT'
  50. OUTPUT_CSV = 'OUTPUT_CSV'
  51. TYPES = ['Byte', 'Int16', 'UInt16', 'UInt32', 'Int32', 'Float32', 'Float64', 'CInt16', 'CInt32', 'CFloat32', 'CFloat64', 'Int8']
  52. def __init__(self):
  53. super().__init__()
  54. def initAlgorithm(self, config=None):
  55. self.methods = ((self.tr('Nearest Neighbour'), 'near'),
  56. (self.tr('Bilinear (2x2 Kernel)'), 'bilinear'),
  57. (self.tr('Cubic (4x4 Kernel)'), 'cubic'),
  58. (self.tr('Cubic B-Spline (4x4 Kernel)'), 'cubicspline'),
  59. (self.tr('Lanczos (6x6 Kernel)'), 'lanczos'),)
  60. self.addParameter(QgsProcessingParameterMultipleLayers(self.INPUT,
  61. self.tr('Input files'),
  62. QgsProcessing.TypeRaster))
  63. self.addParameter(QgsProcessingParameterNumber(self.TILE_SIZE_X,
  64. self.tr('Tile width'),
  65. type=QgsProcessingParameterNumber.Integer,
  66. minValue=0,
  67. defaultValue=256))
  68. self.addParameter(QgsProcessingParameterNumber(self.TILE_SIZE_Y,
  69. self.tr('Tile height'),
  70. type=QgsProcessingParameterNumber.Integer,
  71. minValue=0,
  72. defaultValue=256))
  73. self.addParameter(QgsProcessingParameterNumber(self.OVERLAP,
  74. self.tr('Overlap in pixels between consecutive tiles'),
  75. type=QgsProcessingParameterNumber.Integer,
  76. minValue=0,
  77. defaultValue=0))
  78. self.addParameter(QgsProcessingParameterNumber(self.LEVELS,
  79. self.tr('Number of pyramids levels to build'),
  80. type=QgsProcessingParameterNumber.Integer,
  81. minValue=0,
  82. defaultValue=1))
  83. params = [
  84. QgsProcessingParameterCrs(self.SOURCE_CRS,
  85. self.tr('Source coordinate reference system'),
  86. optional=True,
  87. ),
  88. QgsProcessingParameterEnum(self.RESAMPLING,
  89. self.tr('Resampling method'),
  90. options=[i[0] for i in self.methods],
  91. allowMultiple=False,
  92. defaultValue=0),
  93. QgsProcessingParameterString(self.DELIMITER,
  94. self.tr('Column delimiter used in the CSV file'),
  95. defaultValue=';',
  96. optional=True)
  97. ]
  98. options_param = QgsProcessingParameterString(self.OPTIONS,
  99. self.tr('Additional creation options'),
  100. defaultValue='',
  101. optional=True)
  102. options_param.setMetadata({
  103. 'widget_wrapper': {
  104. 'class': 'processing.algs.gdal.ui.RasterOptionsWidget.RasterOptionsWidgetWrapper'}})
  105. params.append(options_param)
  106. params.append(QgsProcessingParameterString(self.EXTRA,
  107. self.tr('Additional command-line parameters'),
  108. defaultValue=None,
  109. optional=True))
  110. params.append(QgsProcessingParameterEnum(self.DATA_TYPE,
  111. self.tr('Output data type'),
  112. self.TYPES,
  113. allowMultiple=False,
  114. defaultValue=5))
  115. params.append(QgsProcessingParameterBoolean(self.ONLY_PYRAMIDS,
  116. self.tr('Build only the pyramids'),
  117. defaultValue=False))
  118. params.append(QgsProcessingParameterBoolean(self.DIR_FOR_ROW,
  119. self.tr('Use separate directory for each tiles row'),
  120. defaultValue=False))
  121. for param in params:
  122. param.setFlags(param.flags() | QgsProcessingParameterDefinition.FlagAdvanced)
  123. self.addParameter(param)
  124. self.addParameter(QgsProcessingParameterFolderDestination(self.OUTPUT,
  125. self.tr('Output directory')))
  126. output_csv_param = QgsProcessingParameterFileDestination(self.OUTPUT_CSV,
  127. self.tr('CSV file containing the tile(s) georeferencing information'),
  128. 'CSV files (*.csv)',
  129. optional=True)
  130. output_csv_param.setCreateByDefault(False)
  131. self.addParameter(output_csv_param)
  132. def name(self):
  133. return 'retile'
  134. def displayName(self):
  135. return self.tr('Retile')
  136. def group(self):
  137. return self.tr('Raster miscellaneous')
  138. def groupId(self):
  139. return 'rastermiscellaneous'
  140. def commandName(self):
  141. return "gdal_retile"
  142. def getConsoleCommands(self, parameters, context, feedback, executing=True):
  143. arguments = [
  144. '-ps',
  145. str(self.parameterAsInt(parameters, self.TILE_SIZE_X, context)),
  146. str(self.parameterAsInt(parameters, self.TILE_SIZE_Y, context)),
  147. '-overlap',
  148. str(self.parameterAsInt(parameters, self.OVERLAP, context)),
  149. '-levels',
  150. str(self.parameterAsInt(parameters, self.LEVELS, context))
  151. ]
  152. crs = self.parameterAsCrs(parameters, self.SOURCE_CRS, context)
  153. if crs.isValid():
  154. arguments.append('-s_srs')
  155. arguments.append(GdalUtils.gdal_crs_string(crs))
  156. arguments.append('-r')
  157. arguments.append(self.methods[self.parameterAsEnum(parameters, self.RESAMPLING, context)][1])
  158. data_type = self.parameterAsEnum(parameters, self.DATA_TYPE, context)
  159. if self.TYPES[data_type] == 'Int8' and GdalUtils.version() < 3070000:
  160. raise QgsProcessingException(self.tr('Int8 data type requires GDAL version 3.7 or later'))
  161. arguments.append('-ot ' + self.TYPES[data_type])
  162. options = self.parameterAsString(parameters, self.OPTIONS, context)
  163. if options:
  164. arguments.extend(GdalUtils.parseCreationOptions(options))
  165. if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ''):
  166. extra = self.parameterAsString(parameters, self.EXTRA, context)
  167. arguments.append(extra)
  168. if self.parameterAsBoolean(parameters, self.DIR_FOR_ROW, context):
  169. arguments.append('-useDirForEachRow')
  170. if self.parameterAsBoolean(parameters, self.ONLY_PYRAMIDS, context):
  171. arguments.append('-pyramidOnly')
  172. csvFile = self.parameterAsFileOutput(parameters, self.OUTPUT_CSV, context)
  173. if csvFile:
  174. arguments.append('-csv')
  175. arguments.append(csvFile)
  176. delimiter = self.parameterAsString(parameters, self.DELIMITER, context)
  177. if delimiter:
  178. arguments.append('-csvDelim')
  179. arguments.append(delimiter)
  180. arguments.append('-targetDir')
  181. arguments.append(self.parameterAsString(parameters, self.OUTPUT, context))
  182. layers = [l.source() for l in self.parameterAsLayerList(parameters, self.INPUT, context)]
  183. arguments.extend(layers)
  184. return [self.commandName() + ('.bat' if isWindows() else '.py'), GdalUtils.escapeAndJoin(arguments)]