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
56 "This algorithm applies a Gaussian blur filter to an input raster layer.\n\n"
57 "The radius parameter controls the strength of the blur. "
58 "A larger radius results in a smoother output, at the cost of execution time."
62QString QgsRasterGaussianBlurAlgorithm::shortDescription()
const
64 return QObject::tr(
"Applies a Gaussian blur filter to a raster layer." );
67void QgsRasterGaussianBlurAlgorithm::initAlgorithm(
const QVariantMap & )
74 addParameter( sigmaParam.release() );
76 auto creationOptsParam = std::make_unique<QgsProcessingParameterString>( u
"CREATION_OPTIONS"_s, QObject::tr(
"Creation options" ), QVariant(),
false,
true );
77 creationOptsParam->setMetadata( QVariantMap( { { u
"widget_wrapper"_s, QVariantMap( { { u
"widget_type"_s, u
"rasteroptions"_s } } ) } } ) );
79 addParameter( creationOptsParam.release() );
81 auto outputLayerParam = std::make_unique<QgsProcessingParameterRasterDestination>( u
"OUTPUT"_s, QObject::tr(
"Output layer" ) );
82 addParameter( outputLayerParam.release() );
85QgsRasterGaussianBlurAlgorithm *QgsRasterGaussianBlurAlgorithm::createInstance()
const
87 return new QgsRasterGaussianBlurAlgorithm();
92 QgsRasterLayer *layer = parameterAsRasterLayer( parameters, u
"INPUT"_s, context );
96 const int band = parameterAsInt( parameters, u
"BAND"_s, context );
98 mBand = parameterAsInt( parameters, u
"BAND"_s, context );
99 if ( mBand < 1 || mBand > layer->
bandCount() )
100 throw QgsProcessingException( QObject::tr(
"Invalid band number for BAND (%1): Valid values for input raster are 1 to %2" ).arg( mBand ).arg( layer->
bandCount() ) );
104 mLayerWidth = layer->
width();
105 mLayerHeight = layer->
height();
106 mExtent = layer->
extent();
117 QGS_MARK_ALGORITHM_SOURCE
119 const int radius = parameterAsInt( parameters, u
"RADIUS"_s, context );
121 const QString creationOptions = parameterAsString( parameters, u
"CREATION_OPTIONS"_s, context ).trimmed();
123 const QString outputFile = parameterAsOutputLayer( parameters, u
"OUTPUT"_s, context );
124 const QString outputFormat = parameterAsOutputRasterFormat( parameters, u
"OUTPUT"_s, context );
126 auto outputWriter = std::make_unique<QgsRasterFileWriter>( outputFile );
127 outputWriter->setOutputProviderKey( u
"gdal"_s );
128 if ( !creationOptions.isEmpty() )
130 outputWriter->setCreationOptions( creationOptions.split(
'|' ) );
132 outputWriter->setOutputFormat( outputFormat );
134 std::unique_ptr<QgsRasterDataProvider> destProvider( outputWriter->createOneBandRaster( mDataType, mLayerWidth, mLayerHeight, mExtent, mCrs ) );
137 if ( !destProvider->isValid() )
140 destProvider->setNoDataValue( 1, mNoData );
141 destProvider->setEditable(
true );
144 const int kernelSize = 2 * radius + 1;
145 std::vector<double> kernel( kernelSize );
148 const double sigma = radius / 3.0;
149 const double expCoefficient = -1.0 / ( 2.0 * sigma * sigma );
151 for (
int i = -radius; i <= radius; ++i )
153 double result = std::exp( i * i * expCoefficient );
154 kernel[i + radius] = result;
158 for (
double &w : kernel )
164 iter.startRasterRead( mBand, mLayerWidth, mLayerHeight, mExtent );
176 std::vector<double> horizBuffer;
177 std::vector<qint8> horizNoData;
181 horizBuffer.reserve( maxBufferSize );
182 horizNoData.reserve( maxBufferSize );
184 const bool hasReportsDuringClose = destProvider->hasReportsDuringClose();
185 const double maxProgressDuringBlockWriting = hasReportsDuringClose ? 50.0 : 100.0;
187 std::unique_ptr<QgsRasterBlock> inputBlock;
188 while ( iter.readNextRasterPart( mBand, iterCols, iterRows, inputBlock, iterLeft, iterTop, &blockExtent, &tileCols, &tileRows, &tileLeft, &tileTop ) )
190 feedback->
setProgress( maxProgressDuringBlockWriting * iter.progress( mBand, 0 ) );
195 auto outputBlock = std::make_unique<QgsRasterBlock>( mDataType, tileCols, tileRows );
197 const int tileBoundaryLeft = tileLeft - iterLeft;
198 const int tileBoundaryTop = tileTop - iterTop;
202 const int horizWidth = tileCols;
204 const std::size_t bufferSize =
static_cast< std::size_t
>( horizWidth ) * iterRows;
205 horizBuffer.resize( bufferSize );
206 horizNoData.assign( bufferSize, 0 );
208 bool isNoData =
false;
209 double *horizPtr = horizBuffer.data();
210 qint8 *noDataPtr = horizNoData.data();
212 for (
int r = 0; r < iterRows; ++r )
214 feedback->
setProgress( maxProgressDuringBlockWriting * iter.progress( mBand, r /
static_cast< double >( iterRows ) * 0.5 ) );
219 for (
int c = 0;
c < tileCols; ++
c )
221 const int inputColumn =
c + tileBoundaryLeft;
222 inputBlock->valueAndNoData( r, inputColumn, isNoData );
231 double sumValues = 0.0;
232 double sumWeight = 0.0;
234 for (
int k = -radius; k <= radius; ++k )
236 const int neighborColumn = inputColumn + k;
237 if ( neighborColumn < 0 || neighborColumn >= iterCols )
240 const double val = inputBlock->valueAndNoData( r, neighborColumn, isNoData );
243 double w = kernel[k + radius];
244 sumValues += val * w;
249 if ( sumWeight > 0.0 )
252 *horizPtr++ = sumValues / sumWeight;
267 for (
int r = 0; r < tileRows; ++r )
269 feedback->
setProgress( maxProgressDuringBlockWriting * iter.progress( mBand, 0.5 + r /
static_cast< double >( tileRows ) * 0.5 ) );
274 const int inputRow = r + tileBoundaryTop;
275 for (
int c = 0;
c < tileCols; ++
c )
277 const std::size_t targetPixelBufferIndex = inputRow *
static_cast< std::size_t
>( horizWidth ) +
c;
278 if ( horizNoData[targetPixelBufferIndex] )
280 outputBlock->setValue( r,
c, mNoData );
284 double sumValues = 0.0;
285 double sumWeight = 0.0;
287 for (
int k = -radius; k <= radius; ++k )
289 const int neighborRow = inputRow + k;
290 if ( neighborRow < 0 || neighborRow >= iterRows )
293 const std::size_t neighborIndex =
static_cast< std::size_t
>( neighborRow ) * horizWidth +
c;
294 if ( !horizNoData[neighborIndex] )
296 double w = kernel[k + radius];
297 sumValues += horizBuffer[neighborIndex] * w;
302 if ( sumWeight > 0.0 )
304 outputBlock->setValue( r,
c, sumValues / sumWeight );
308 outputBlock->setValue( r,
c, mNoData );
313 if ( !destProvider->writeBlock( outputBlock.get(), 1, tileLeft, tileTop ) )
315 throw QgsProcessingException( QObject::tr(
"Could not write raster block: %1" ).arg( destProvider->error().summary() ) );
318 destProvider->setEditable(
false );
320 if ( feedback && hasReportsDuringClose )
323 if ( !destProvider->closeWithProgress( scaledFeedback.get() ) )
332 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 Q_INVOKABLE 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