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 const int radius = parameterAsInt( parameters, u
"RADIUS"_s, context );
119 const QString creationOptions = parameterAsString( parameters, u
"CREATION_OPTIONS"_s, context ).trimmed();
121 const QString outputFile = parameterAsOutputLayer( parameters, u
"OUTPUT"_s, context );
122 const QString outputFormat = parameterAsOutputRasterFormat( parameters, u
"OUTPUT"_s, context );
124 auto outputWriter = std::make_unique<QgsRasterFileWriter>( outputFile );
125 outputWriter->setOutputProviderKey( u
"gdal"_s );
126 if ( !creationOptions.isEmpty() )
128 outputWriter->setCreationOptions( creationOptions.split(
'|' ) );
130 outputWriter->setOutputFormat( outputFormat );
132 std::unique_ptr<QgsRasterDataProvider> destProvider( outputWriter->createOneBandRaster( mDataType, mLayerWidth, mLayerHeight, mExtent, mCrs ) );
135 if ( !destProvider->isValid() )
138 destProvider->setNoDataValue( 1, mNoData );
139 destProvider->setEditable(
true );
142 const int kernelSize = 2 * radius + 1;
143 std::vector<double> kernel( kernelSize );
146 const double sigma = radius / 3.0;
147 const double expCoefficient = -1.0 / ( 2.0 * sigma * sigma );
149 for (
int i = -radius; i <= radius; ++i )
151 double result = std::exp( i * i * expCoefficient );
152 kernel[i + radius] = result;
156 for (
double &w : kernel )
162 iter.startRasterRead( mBand, mLayerWidth, mLayerHeight, mExtent );
174 std::vector<double> horizBuffer;
175 std::vector<qint8> horizNoData;
179 horizBuffer.reserve( maxBufferSize );
180 horizNoData.reserve( maxBufferSize );
182 const bool hasReportsDuringClose = destProvider->hasReportsDuringClose();
183 const double maxProgressDuringBlockWriting = hasReportsDuringClose ? 50.0 : 100.0;
185 std::unique_ptr<QgsRasterBlock> inputBlock;
186 while ( iter.readNextRasterPart( mBand, iterCols, iterRows, inputBlock, iterLeft, iterTop, &blockExtent, &tileCols, &tileRows, &tileLeft, &tileTop ) )
188 feedback->
setProgress( maxProgressDuringBlockWriting * iter.progress( mBand, 0 ) );
193 auto outputBlock = std::make_unique<QgsRasterBlock>( mDataType, tileCols, tileRows );
195 const int tileBoundaryLeft = tileLeft - iterLeft;
196 const int tileBoundaryTop = tileTop - iterTop;
200 const int horizWidth = tileCols;
202 const std::size_t bufferSize =
static_cast< std::size_t
>( horizWidth ) * iterRows;
203 horizBuffer.resize( bufferSize );
204 horizNoData.assign( bufferSize, 0 );
206 bool isNoData =
false;
207 double *horizPtr = horizBuffer.data();
208 qint8 *noDataPtr = horizNoData.data();
210 for (
int r = 0; r < iterRows; ++r )
212 feedback->
setProgress( maxProgressDuringBlockWriting * iter.progress( mBand, r /
static_cast< double >( iterRows ) * 0.5 ) );
217 for (
int c = 0;
c < tileCols; ++
c )
219 const int inputColumn =
c + tileBoundaryLeft;
220 inputBlock->valueAndNoData( r, inputColumn, isNoData );
229 double sumValues = 0.0;
230 double sumWeight = 0.0;
232 for (
int k = -radius; k <= radius; ++k )
234 const int neighborColumn = inputColumn + k;
235 if ( neighborColumn < 0 || neighborColumn >= iterCols )
238 const double val = inputBlock->valueAndNoData( r, neighborColumn, isNoData );
241 double w = kernel[k + radius];
242 sumValues += val * w;
247 if ( sumWeight > 0.0 )
250 *horizPtr++ = sumValues / sumWeight;
265 for (
int r = 0; r < tileRows; ++r )
267 feedback->
setProgress( maxProgressDuringBlockWriting * iter.progress( mBand, 0.5 + r /
static_cast< double >( tileRows ) * 0.5 ) );
272 const int inputRow = r + tileBoundaryTop;
273 for (
int c = 0;
c < tileCols; ++
c )
275 const std::size_t targetPixelBufferIndex = inputRow *
static_cast< std::size_t
>( horizWidth ) +
c;
276 if ( horizNoData[targetPixelBufferIndex] )
278 outputBlock->setValue( r,
c, mNoData );
282 double sumValues = 0.0;
283 double sumWeight = 0.0;
285 for (
int k = -radius; k <= radius; ++k )
287 const int neighborRow = inputRow + k;
288 if ( neighborRow < 0 || neighborRow >= iterRows )
291 const std::size_t neighborIndex =
static_cast< std::size_t
>( neighborRow ) * horizWidth +
c;
292 if ( !horizNoData[neighborIndex] )
294 double w = kernel[k + radius];
295 sumValues += horizBuffer[neighborIndex] * w;
300 if ( sumWeight > 0.0 )
302 outputBlock->setValue( r,
c, sumValues / sumWeight );
306 outputBlock->setValue( r,
c, mNoData );
311 if ( !destProvider->writeBlock( outputBlock.get(), 1, tileLeft, tileTop ) )
313 throw QgsProcessingException( QObject::tr(
"Could not write raster block: %1" ).arg( destProvider->error().summary() ) );
316 destProvider->setEditable(
false );
318 if ( feedback && hasReportsDuringClose )
321 if ( !destProvider->closeWithProgress( scaledFeedback.get() ) )
330 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