QGIS API Documentation  3.16.0-Hannover (43b64b13f3)
qgsalgorithmrescaleraster.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsalgorithmrescaleraster.cpp
3  ---------------------
4  begin : July 2020
5  copyright : (C) 2020 by Alexander Bruy
6  email : alexander dot bruy at gmail dot com
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
18 #include <limits>
19 #include "math.h"
21 #include "qgsrasterfilewriter.h"
22 
24 
25 QString QgsRescaleRasterAlgorithm::name() const
26 {
27  return QStringLiteral( "rescaleraster" );
28 }
29 
30 QString QgsRescaleRasterAlgorithm::displayName() const
31 {
32  return QObject::tr( "Rescale raster" );
33 }
34 
35 QStringList QgsRescaleRasterAlgorithm::tags() const
36 {
37  return QObject::tr( "raster,rescale,minimum,maximum,range" ).split( ',' );
38 }
39 
40 QString QgsRescaleRasterAlgorithm::group() const
41 {
42  return QObject::tr( "Raster analysis" );
43 }
44 
45 QString QgsRescaleRasterAlgorithm::groupId() const
46 {
47  return QStringLiteral( "rasteranalysis" );
48 }
49 
50 QString QgsRescaleRasterAlgorithm::shortHelpString() const
51 {
52  return QObject::tr( "Rescales raster layer to a new value range, while preserving the shape "
53  "(distribution) of the raster's histogram (pixel values). Input values "
54  "are mapped using a linear interpolation from the source raster's minimum "
55  "and maximum pixel values to the destination minimum and maximum pixel range.\n\n"
56  "By default the algorithm preserves original the NODATA value, but there is "
57  "an option to override it." );
58 }
59 
60 QgsRescaleRasterAlgorithm *QgsRescaleRasterAlgorithm::createInstance() const
61 {
62  return new QgsRescaleRasterAlgorithm();
63 }
64 
65 void QgsRescaleRasterAlgorithm::initAlgorithm( const QVariantMap & )
66 {
67  addParameter( new QgsProcessingParameterRasterLayer( QStringLiteral( "INPUT" ), QStringLiteral( "Input raster" ) ) );
68  addParameter( new QgsProcessingParameterBand( QStringLiteral( "BAND" ), QObject::tr( "Band number" ), 1, QStringLiteral( "INPUT" ) ) );
69  addParameter( new QgsProcessingParameterNumber( QStringLiteral( "MINIMUM" ), QObject::tr( "New minimum value" ), QgsProcessingParameterNumber::Double, 0 ) );
70  addParameter( new QgsProcessingParameterNumber( QStringLiteral( "MAXIMUM" ), QObject::tr( "New maximum value" ), QgsProcessingParameterNumber::Double, 255 ) );
71  addParameter( new QgsProcessingParameterNumber( QStringLiteral( "NODATA" ), QObject::tr( "New NODATA value" ), QgsProcessingParameterNumber::Double, QVariant(), true ) );
72  addParameter( new QgsProcessingParameterRasterDestination( QStringLiteral( "OUTPUT" ), QObject::tr( "Rescaled" ) ) );
73 }
74 
75 bool QgsRescaleRasterAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
76 {
77  Q_UNUSED( feedback );
78 
79  QgsRasterLayer *layer = parameterAsRasterLayer( parameters, QStringLiteral( "INPUT" ), context );
80  if ( !layer )
81  throw QgsProcessingException( invalidRasterError( parameters, QStringLiteral( "INPUT" ) ) );
82 
83  mBand = parameterAsInt( parameters, QStringLiteral( "BAND" ), context );
84  if ( mBand < 1 || mBand > layer->bandCount() )
85  throw QgsProcessingException( QObject::tr( "Invalid band number for BAND (%1): Valid values for input raster are 1 to %2" )
86  .arg( mBand )
87  .arg( layer->bandCount() ) );
88 
89  mMinimum = parameterAsDouble( parameters, QStringLiteral( "MINIMUM" ), context );
90  mMaximum = parameterAsDouble( parameters, QStringLiteral( "MAXIMUM" ), context );
91 
92  mInterface.reset( layer->dataProvider()->clone() );
93 
94  mCrs = layer->crs();
95  mLayerWidth = layer->width();
96  mLayerHeight = layer->height();
97  mExtent = layer->extent();
98  if ( parameters.value( QStringLiteral( "NODATA" ) ).isValid() )
99  {
100  mNoData = parameterAsDouble( parameters, QStringLiteral( "NODATA" ), context );
101  }
102  else
103  {
104  mNoData = layer->dataProvider()->sourceNoDataValue( mBand );
105  }
106  mXSize = mInterface->xSize();
107  mYSize = mInterface->ySize();
108 
109  return true;
110 }
111 
112 QVariantMap QgsRescaleRasterAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
113 {
114  feedback->pushInfo( QObject::tr( "Calculating raster minimum and maximum values…" ) );
115  QgsRasterBandStats stats = mInterface->bandStatistics( mBand, QgsRasterBandStats::Min | QgsRasterBandStats::Max, QgsRectangle(), 0 );
116 
117  feedback->pushInfo( QObject::tr( "Rescaling values…" ) );
118  const QString outputFile = parameterAsOutputLayer( parameters, QStringLiteral( "OUTPUT" ), context );
119  QFileInfo fi( outputFile );
120  const QString outputFormat = QgsRasterFileWriter::driverForExtension( fi.suffix() );
121  std::unique_ptr< QgsRasterFileWriter > writer = qgis::make_unique< QgsRasterFileWriter >( outputFile );
122  writer->setOutputProviderKey( QStringLiteral( "gdal" ) );
123  writer->setOutputFormat( outputFormat );
124  std::unique_ptr<QgsRasterDataProvider > provider( writer->createOneBandRaster( Qgis::Float32, mXSize, mYSize, mExtent, mCrs ) );
125  if ( !provider )
126  throw QgsProcessingException( QObject::tr( "Could not create raster output: %1" ).arg( outputFile ) );
127  if ( !provider->isValid() )
128  throw QgsProcessingException( QObject::tr( "Could not create raster output %1: %2" ).arg( outputFile, provider->error().message( QgsErrorMessage::Text ) ) );
129 
130  QgsRasterDataProvider *destProvider = provider.get();
131  destProvider->setEditable( true );
132  destProvider->setNoDataValue( 1, mNoData );
133 
136  int numBlocksX = static_cast< int >( std::ceil( 1.0 * mLayerWidth / blockWidth ) );
137  int numBlocksY = static_cast< int >( std::ceil( 1.0 * mLayerHeight / blockHeight ) );
138  int numBlocks = numBlocksX * numBlocksY;
139 
140  QgsRasterIterator iter( mInterface.get() );
141  iter.startRasterRead( mBand, mLayerWidth, mLayerHeight, mExtent );
142  int iterLeft = 0;
143  int iterTop = 0;
144  int iterCols = 0;
145  int iterRows = 0;
146  std::unique_ptr< QgsRasterBlock > block;
147  while ( iter.readNextRasterPart( mBand, iterCols, iterRows, block, iterLeft, iterTop ) )
148  {
149  feedback->setProgress( 100 * ( ( iterTop / blockHeight * numBlocksX ) + iterLeft / blockWidth ) / numBlocks );
150 
151  for ( int row = 0; row < iterRows; row++ )
152  {
153  if ( feedback->isCanceled() )
154  break;
155 
156  for ( int col = 0; col < iterCols; col++ )
157  {
158  bool isNoData = false;
159  double val = block->valueAndNoData( row, col, isNoData );
160  if ( isNoData )
161  {
162  block->setValue( row, col, mNoData );
163  }
164  else
165  {
166  double newValue = ( ( val - stats.minimumValue ) * ( mMaximum - mMinimum ) / ( stats.maximumValue - stats.minimumValue ) ) + mMinimum;
167  block->setValue( row, col, newValue );
168  }
169  }
170  }
171  destProvider->writeBlock( block.get(), mBand, iterLeft, iterTop );
172  }
173  destProvider->setEditable( false );
174 
175  QVariantMap outputs;
176  outputs.insert( QStringLiteral( "OUTPUT" ), outputFile );
177  return outputs;
178 }
179 
QgsMapLayer::crs
QgsCoordinateReferenceSystem crs
Definition: qgsmaplayer.h:89
QgsFeedback::setProgress
void setProgress(double progress)
Sets the current progress for the feedback object.
Definition: qgsfeedback.h:62
Qgis::Float32
@ Float32
Thirty two bit floating point (float)
Definition: qgis.h:109
QgsRasterLayer::bandCount
int bandCount() const
Returns the number of bands in this layer.
Definition: qgsrasterlayer.cpp:217
QgsProcessingParameterNumber::Double
@ Double
Double/float values.
Definition: qgsprocessingparameters.h:1967
qgsalgorithmrescaleraster.h
QgsProcessingParameterNumber
A numeric parameter for processing algorithms.
Definition: qgsprocessingparameters.h:1960
QgsProcessingFeedback
Base class for providing feedback from a processing algorithm.
Definition: qgsprocessingfeedback.h:38
QgsRasterBandStats
The RasterBandStats struct is a container for statistics about a single raster band.
Definition: qgsrasterbandstats.h:35
QgsRasterFileWriter::driverForExtension
static QString driverForExtension(const QString &extension)
Returns the GDAL driver name for a specified file extension.
Definition: qgsrasterfilewriter.cpp:1063
QgsProcessingFeedback::pushInfo
virtual void pushInfo(const QString &info)
Pushes a general informational message from the algorithm.
Definition: qgsprocessingfeedback.cpp:48
QgsProcessingParameterRasterDestination
A raster layer destination parameter, for specifying the destination path for a raster layer created ...
Definition: qgsprocessingparameters.h:3066
QgsRasterDataProvider::setEditable
virtual bool setEditable(bool enabled)
Turns on/off editing mode of the provider.
Definition: qgsrasterdataprovider.h:451
QgsRectangle
A rectangle specified with double values.
Definition: qgsrectangle.h:42
qgsrasterfilewriter.h
QgsRasterDataProvider::clone
QgsRasterDataProvider * clone() const override=0
Clone itself, create deep copy.
QgsRasterBandStats::maximumValue
double maximumValue
The maximum cell value in the raster band.
Definition: qgsrasterbandstats.h:88
QgsRasterLayer::width
int width() const
Returns the width of the (unclipped) raster.
Definition: qgsrasterlayer.cpp:2448
QgsProcessingContext
Contains information about the context in which a processing algorithm is executed.
Definition: qgsprocessingcontext.h:44
QgsRasterDataProvider::writeBlock
bool writeBlock(QgsRasterBlock *block, int band, int xOffset=0, int yOffset=0)
Writes pixel data from a raster block into the provider data source.
Definition: qgsrasterdataprovider.cpp:353
QgsRasterLayer::height
int height() const
Returns the height of the (unclipped) raster.
Definition: qgsrasterlayer.cpp:2454
QgsMapLayer::extent
virtual QgsRectangle extent() const
Returns the extent of the layer.
Definition: qgsmaplayer.cpp:197
QgsRasterIterator::DEFAULT_MAXIMUM_TILE_HEIGHT
static const int DEFAULT_MAXIMUM_TILE_HEIGHT
Default maximum tile height.
Definition: qgsrasteriterator.h:151
QgsRasterLayer::dataProvider
QgsRasterDataProvider * dataProvider() override
Returns the source data provider.
Definition: qgsrasterlayer.cpp:234
QgsProcessingParameterRasterLayer
A raster layer parameter for processing algorithms.
Definition: qgsprocessingparameters.h:2223
QgsRasterBandStats::Min
@ Min
Definition: qgsrasterbandstats.h:40
QgsRasterDataProvider::sourceNoDataValue
virtual double sourceNoDataValue(int bandNo) const
Value representing no data value.
Definition: qgsrasterdataprovider.h:255
QgsRasterLayer
Represents a raster layer.
Definition: qgsrasterlayer.h:71
QgsRasterIterator
Iterator for sequentially processing raster cells.
Definition: qgsrasteriterator.h:35
QgsRasterBandStats::minimumValue
double minimumValue
The minimum cell value in the raster band.
Definition: qgsrasterbandstats.h:94
QgsFeedback::isCanceled
bool isCanceled() const
Tells whether the operation has been canceled already.
Definition: qgsfeedback.h:53
QgsRasterBandStats::Max
@ Max
Definition: qgsrasterbandstats.h:41
QgsRasterDataProvider::setNoDataValue
virtual bool setNoDataValue(int bandNo, double noDataValue)
Set no data value on created dataset.
Definition: qgsrasterdataprovider.h:499
QgsRasterIterator::DEFAULT_MAXIMUM_TILE_WIDTH
static const int DEFAULT_MAXIMUM_TILE_WIDTH
Default maximum tile width.
Definition: qgsrasteriterator.h:148
QgsErrorMessage::Text
@ Text
Definition: qgserror.h:38
QgsProcessingParameterBand
A raster band parameter for Processing algorithms.
Definition: qgsprocessingparameters.h:3225
QgsProcessingException
Custom exception class for processing related exceptions.
Definition: qgsexception.h:83
QgsRasterDataProvider
Base class for raster data providers.
Definition: qgsrasterdataprovider.h:89