24using namespace Qt::StringLiterals;
28QString QgsRasterGaussianBlurAlgorithm::name()
const
30 return u
"rastergaussianblur"_s;
33QString QgsRasterGaussianBlurAlgorithm::displayName()
const
35 return QObject::tr(
"Gaussian blur" );
38QStringList QgsRasterGaussianBlurAlgorithm::tags()
const
40 return QObject::tr(
"smooth,filter,denoise" ).split(
',' );
43QString QgsRasterGaussianBlurAlgorithm::group()
const
45 return QObject::tr(
"Raster analysis" );
48QString QgsRasterGaussianBlurAlgorithm::groupId()
const
50 return u
"rasteranalysis"_s;
53QString QgsRasterGaussianBlurAlgorithm::shortHelpString()
const
55 return QObject::tr(
"This algorithm applies a Gaussian blur filter to an input raster layer.\n\n"
56 "The radius parameter controls the strength of the blur. "
57 "A larger radius results in a smoother output, at the cost of execution time." );
60QString QgsRasterGaussianBlurAlgorithm::shortDescription()
const
62 return QObject::tr(
"Applies a Gaussian blur filter to a raster layer." );
65void QgsRasterGaussianBlurAlgorithm::initAlgorithm(
const QVariantMap & )
72 addParameter( sigmaParam.release() );
74 auto creationOptsParam = std::make_unique<QgsProcessingParameterString>( u
"CREATION_OPTIONS"_s, QObject::tr(
"Creation options" ), QVariant(),
false,
true );
75 creationOptsParam->setMetadata( QVariantMap( { { u
"widget_wrapper"_s, QVariantMap( { { u
"widget_type"_s, u
"rasteroptions"_s } } ) } } ) );
77 addParameter( creationOptsParam.release() );
79 auto outputLayerParam = std::make_unique<QgsProcessingParameterRasterDestination>( u
"OUTPUT"_s, QObject::tr(
"Output layer" ) );
80 addParameter( outputLayerParam.release() );
83QgsRasterGaussianBlurAlgorithm *QgsRasterGaussianBlurAlgorithm::createInstance()
const
85 return new QgsRasterGaussianBlurAlgorithm();
90 QgsRasterLayer *layer = parameterAsRasterLayer( parameters, u
"INPUT"_s, context );
94 const int band = parameterAsInt( parameters, u
"BAND"_s, context );
96 mBand = parameterAsInt( parameters, u
"BAND"_s, context );
97 if ( mBand < 1 || mBand > layer->
bandCount() )
98 throw QgsProcessingException( QObject::tr(
"Invalid band number for BAND (%1): Valid values for input raster are 1 to %2" ).arg( mBand ).arg( layer->
bandCount() ) );
102 mLayerWidth = layer->
width();
103 mLayerHeight = layer->
height();
104 mExtent = layer->
extent();
115 const int radius = parameterAsInt( parameters, u
"RADIUS"_s, context );
117 const QString creationOptions = parameterAsString( parameters, u
"CREATION_OPTIONS"_s, context ).trimmed();
119 const QString outputFile = parameterAsOutputLayer( parameters, u
"OUTPUT"_s, context );
120 const QString outputFormat = parameterAsOutputRasterFormat( parameters, u
"OUTPUT"_s, context );
122 auto outputWriter = std::make_unique<QgsRasterFileWriter>( outputFile );
123 outputWriter->setOutputProviderKey( u
"gdal"_s );
124 if ( !creationOptions.isEmpty() )
126 outputWriter->setCreationOptions( creationOptions.split(
'|' ) );
128 outputWriter->setOutputFormat( outputFormat );
130 std::unique_ptr<QgsRasterDataProvider> destProvider( outputWriter->createOneBandRaster( mDataType, mLayerWidth, mLayerHeight, mExtent, mCrs ) );
133 if ( !destProvider->isValid() )
136 destProvider->setNoDataValue( 1, mNoData );
137 destProvider->setEditable(
true );
140 const int kernelSize = 2 * radius + 1;
141 std::vector<double> kernel( kernelSize );
144 const double sigma = radius / 3.0;
145 const double expCoefficient = -1.0 / ( 2.0 * sigma * sigma );
147 for (
int i = -radius; i <= radius; ++i )
149 double result = std::exp( i * i * expCoefficient );
150 kernel[i + radius] = result;
154 for (
double &w : kernel )
160 iter.startRasterRead( mBand, mLayerWidth, mLayerHeight, mExtent );
172 std::vector<double> horizBuffer;
173 std::vector<qint8> horizNoData;
176 horizBuffer.reserve( maxBufferSize );
177 horizNoData.reserve( maxBufferSize );
179 const bool hasReportsDuringClose = destProvider->hasReportsDuringClose();
180 const double maxProgressDuringBlockWriting = hasReportsDuringClose ? 50.0 : 100.0;
182 std::unique_ptr<QgsRasterBlock> inputBlock;
183 while ( iter.readNextRasterPart( mBand, iterCols, iterRows, inputBlock, iterLeft, iterTop, &blockExtent, &tileCols, &tileRows, &tileLeft, &tileTop ) )
185 feedback->
setProgress( maxProgressDuringBlockWriting * iter.progress( mBand, 0 ) );
190 auto outputBlock = std::make_unique<QgsRasterBlock>( mDataType, tileCols, tileRows );
192 const int tileBoundaryLeft = tileLeft - iterLeft;
193 const int tileBoundaryTop = tileTop - iterTop;
197 const int horizWidth = tileCols;
199 const std::size_t bufferSize =
static_cast< std::size_t
>( horizWidth ) * iterRows;
200 horizBuffer.resize( bufferSize );
201 horizNoData.assign( bufferSize, 0 );
203 bool isNoData =
false;
204 double *horizPtr = horizBuffer.data();
205 qint8 *noDataPtr = horizNoData.data();
207 for (
int r = 0; r < iterRows; ++r )
209 feedback->
setProgress( maxProgressDuringBlockWriting * iter.progress( mBand, r /
static_cast< double >( iterRows ) * 0.5 ) );
214 for (
int c = 0;
c < tileCols; ++
c )
216 const int inputColumn =
c + tileBoundaryLeft;
217 inputBlock->valueAndNoData( r, inputColumn, isNoData );
226 double sumValues = 0.0;
227 double sumWeight = 0.0;
229 for (
int k = -radius; k <= radius; ++k )
231 const int neighborColumn = inputColumn + k;
232 if ( neighborColumn < 0 || neighborColumn >= iterCols )
235 const double val = inputBlock->valueAndNoData( r, neighborColumn, isNoData );
238 double w = kernel[k + radius];
239 sumValues += val * w;
244 if ( sumWeight > 0.0 )
247 *horizPtr++ = sumValues / sumWeight;
262 for (
int r = 0; r < tileRows; ++r )
264 feedback->
setProgress( maxProgressDuringBlockWriting * iter.progress( mBand, 0.5 + r /
static_cast< double >( tileRows ) * 0.5 ) );
269 const int inputRow = r + tileBoundaryTop;
270 for (
int c = 0;
c < tileCols; ++
c )
272 const std::size_t targetPixelBufferIndex = inputRow *
static_cast< std::size_t
>( horizWidth ) +
c;
273 if ( horizNoData[targetPixelBufferIndex] )
275 outputBlock->setValue( r,
c, mNoData );
279 double sumValues = 0.0;
280 double sumWeight = 0.0;
282 for (
int k = -radius; k <= radius; ++k )
284 const int neighborRow = inputRow + k;
285 if ( neighborRow < 0 || neighborRow >= iterRows )
288 const std::size_t neighborIndex =
static_cast< std::size_t
>( neighborRow ) * horizWidth +
c;
289 if ( !horizNoData[neighborIndex] )
291 double w = kernel[k + radius];
292 sumValues += horizBuffer[neighborIndex] * w;
297 if ( sumWeight > 0.0 )
299 outputBlock->setValue( r,
c, sumValues / sumWeight );
303 outputBlock->setValue( r,
c, mNoData );
308 if ( !destProvider->writeBlock( outputBlock.get(), 1, tileLeft, tileTop ) )
310 throw QgsProcessingException( QObject::tr(
"Could not write raster block: %1" ).arg( destProvider->error().summary() ) );
313 destProvider->setEditable(
false );
315 if ( feedback && hasReportsDuringClose )
318 if ( !destProvider->closeWithProgress( scaledFeedback.get() ) )
327 outputs.insert( u
"OUTPUT"_s, outputFile );
@ Advanced
Parameter is an advanced parameter which should be hidden from users by default.
bool isCanceled() const
Tells whether the operation has been canceled already.
void setProgress(double progress)
Sets the current progress for the feedback object.
static std::unique_ptr< QgsFeedback > createScaledFeedback(QgsFeedback *parentFeedback, double startPercentage, double endPercentage)
Returns a feedback object whose [0, 100] progression range will be mapped to parentFeedback [startPer...
virtual QgsRectangle extent() const
Returns the extent of the layer.
QgsCoordinateReferenceSystem crs
Contains information about the context in which a processing algorithm is executed.
Custom exception class for processing related exceptions.
Base class for providing feedback from a processing algorithm.
A raster band parameter for Processing algorithms.
A raster layer parameter for processing algorithms.
QgsRasterDataProvider * clone() const override=0
Clone itself, create deep copy.
virtual bool sourceHasNoDataValue(int bandNo) const
Returns true if source band has no data value.
virtual double sourceNoDataValue(int bandNo) const
Value representing no data value.
Qgis::DataType dataType(int bandNo) const override=0
Returns data type for the band specified by number.
Iterator for sequentially processing raster cells.
static const int DEFAULT_MAXIMUM_TILE_WIDTH
Default maximum tile width.
static const int DEFAULT_MAXIMUM_TILE_HEIGHT
Default maximum tile height.
Represents a raster layer.
int height() const
Returns the height of the (unclipped) raster.
int bandCount() const
Returns the number of bands in this layer.
double rasterUnitsPerPixelX() const
Returns the number of raster units per each raster pixel in X axis.
QgsRasterDataProvider * dataProvider() override
Returns the source data provider.
double rasterUnitsPerPixelY() const
Returns the number of raster units per each raster pixel in Y axis.
int width() const
Returns the width of the (unclipped) raster.
A rectangle specified with double values.
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c