25 QString QgsRasterLayerZonalStatsAlgorithm::name()
const 27 return QStringLiteral(
"rasterlayerzonalstats" );
30 QString QgsRasterLayerZonalStatsAlgorithm::displayName()
const 32 return QObject::tr(
"Raster layer zonal statistics" );
35 QStringList QgsRasterLayerZonalStatsAlgorithm::tags()
const 37 return QObject::tr(
"count,area,statistics,stats,zones,categories,minimum,maximum,mean,sum,total" ).split(
',' );
40 QString QgsRasterLayerZonalStatsAlgorithm::group()
const 42 return QObject::tr(
"Raster analysis" );
45 QString QgsRasterLayerZonalStatsAlgorithm::groupId()
const 47 return QStringLiteral(
"rasteranalysis" );
50 void QgsRasterLayerZonalStatsAlgorithm::initAlgorithm(
const QVariantMap & )
53 QObject::tr(
"Input layer" ) ) );
55 QObject::tr(
"Band number" ), 1, QStringLiteral(
"INPUT" ) ) );
57 QObject::tr(
"Zones layer" ) ) );
59 QObject::tr(
"Zones band number" ), 1, QStringLiteral(
"ZONES" ) ) );
61 std::unique_ptr< QgsProcessingParameterEnum > refParam = qgis::make_unique< QgsProcessingParameterEnum >( QStringLiteral(
"REF_LAYER" ), QObject::tr(
"Reference layer" ),
62 QStringList() << QObject::tr(
"Input layer" ) << QObject::tr(
"Zones layer" ),
false, 0 );
64 addParameter( refParam.release() );
74 addOutput(
new QgsProcessingOutputNumber( QStringLiteral(
"NODATA_PIXEL_COUNT" ), QObject::tr(
"NODATA pixel count" ) ) );
77 QString QgsRasterLayerZonalStatsAlgorithm::shortDescription()
const 79 return QObject::tr(
"Calculates statistics for a raster layer's values, categorized by zones defined in another raster layer." );
82 QString QgsRasterLayerZonalStatsAlgorithm::shortHelpString()
const 84 return QObject::tr(
"This algorithm calculates statistics for a raster layer's values, categorized by zones defined in another raster layer.\n\n" 85 "If the reference layer parameter is set to \"Input layer\", then zones are determined by sampling the zone raster layer value at the centroid of each pixel from the source raster layer.\n\n" 86 "If the reference layer parameter is set to \"Zones layer\", then the input raster layer will be sampled at the centroid of each pixel from the zones raster layer.\n\n" 87 "If either the source raster layer or the zone raster layer value is NODATA for a pixel, that pixel's value will be skipped and not including in the calculated statistics." );
90 QgsRasterLayerZonalStatsAlgorithm *QgsRasterLayerZonalStatsAlgorithm::createInstance()
const 92 return new QgsRasterLayerZonalStatsAlgorithm();
97 mRefLayer =
static_cast< RefLayer
>( parameterAsEnum( parameters, QStringLiteral(
"REF_LAYER" ), context ) );
99 QgsRasterLayer *layer = parameterAsRasterLayer( parameters, QStringLiteral(
"INPUT" ), context );
100 int band = parameterAsInt( parameters, QStringLiteral(
"BAND" ), context );
105 mBand = parameterAsInt( parameters, QStringLiteral(
"BAND" ), context );
106 if ( mBand < 1 || mBand > layer->
bandCount() )
107 throw QgsProcessingException( QObject::tr(
"Invalid band number for BAND (%1): Valid values for input raster are 1 to %2" ).arg( mBand )
112 QgsRasterLayer *zonesLayer = parameterAsRasterLayer( parameters, QStringLiteral(
"ZONES" ), context );
117 mZonesBand = parameterAsInt( parameters, QStringLiteral(
"ZONES_BAND" ), context );
118 if ( mZonesBand < 1 || mZonesBand > zonesLayer->
bandCount() )
119 throw QgsProcessingException( QObject::tr(
"Invalid band number for ZONES_BAND (%1): Valid values for input raster are 1 to %2" ).arg( mZonesBand )
124 mSourceInterface = mSourceDataProvider.get();
126 mZonesInterface = mZonesDataProvider.get();
134 mLayerWidth = layer->
width();
135 mLayerHeight = layer->
height();
136 mExtent = layer->
extent();
139 if ( layer->
crs() != zonesLayer->
crs() )
141 mProjector = qgis::make_unique< QgsRasterProjector >();
142 mProjector->setInput( mZonesDataProvider.get() );
144 mZonesInterface = mProjector.get();
149 mCrs = zonesLayer->
crs();
152 mLayerWidth = zonesLayer->
width();
153 mLayerHeight = zonesLayer->
height();
154 mExtent = zonesLayer->
extent();
157 if ( layer->
crs() != zonesLayer->
crs() )
159 mProjector = qgis::make_unique< QgsRasterProjector >();
160 mProjector->setInput( mSourceDataProvider.get() );
162 mSourceInterface = mProjector.get();
175 std::unique_ptr< QgsFeatureSink > sink;
176 if ( parameters.contains( QStringLiteral(
"OUTPUT_TABLE" ) ) && parameters.value( QStringLiteral(
"OUTPUT_TABLE" ) ).isValid() )
179 outFields.
append(
QgsField( QStringLiteral(
"zone" ), QVariant::Double, QString(), 20, 8 ) );
180 outFields.
append(
QgsField( areaUnit.replace( QStringLiteral(
"²" ), QStringLiteral(
"2" ) ), QVariant::Double, QString(), 20, 8 ) );
181 outFields.
append(
QgsField( QStringLiteral(
"sum" ), QVariant::Double, QString(), 20, 8 ) );
182 outFields.
append(
QgsField( QStringLiteral(
"count" ), QVariant::LongLong, QString(), 20 ) );
183 outFields.
append(
QgsField( QStringLiteral(
"min" ), QVariant::Double, QString(), 20, 8 ) );
184 outFields.
append(
QgsField( QStringLiteral(
"max" ), QVariant::Double, QString(), 20, 8 ) );
185 outFields.
append(
QgsField( QStringLiteral(
"mean" ), QVariant::Double, QString(), 20, 8 ) );
192 struct StatCalculator
198 QHash<double, StatCalculator > zoneStats;
201 qgssize layerSize =
static_cast< qgssize >( mLayerWidth ) * static_cast< qgssize >( mLayerHeight );
204 int nbBlocksWidth =
static_cast< int>( std::ceil( 1.0 * mLayerWidth / maxWidth ) );
205 int nbBlocksHeight =
static_cast< int >( std::ceil( 1.0 * mLayerHeight / maxHeight ) );
206 int nbBlocks = nbBlocksWidth * nbBlocksHeight;
209 : QgsRasterIterator( mZonesInterface );
210 iter.
startRasterRead( mRefLayer == Source ? mBand : mZonesBand, mLayerWidth, mLayerHeight, mExtent );
217 std::unique_ptr< QgsRasterBlock > rasterBlock;
218 std::unique_ptr< QgsRasterBlock > zonesRasterBlock;
219 bool isNoData =
false;
222 if ( mRefLayer == Source )
224 if ( !iter.
readNextRasterPart( mBand, iterCols, iterRows, rasterBlock, iterLeft, iterTop, &blockExtent ) )
227 zonesRasterBlock.reset( mZonesInterface->block( mZonesBand, blockExtent, iterCols, iterRows ) );
228 if ( !zonesRasterBlock )
233 if ( !iter.
readNextRasterPart( mZonesBand, iterCols, iterRows, zonesRasterBlock, iterLeft, iterTop, &blockExtent ) )
236 rasterBlock.reset( mSourceInterface->block( mBand, blockExtent, iterCols, iterRows ) );
241 feedback->
setProgress( 100 * ( ( iterTop / maxHeight * nbBlocksWidth ) + iterLeft / maxWidth ) / nbBlocks );
242 if ( !rasterBlock->isValid() || rasterBlock->isEmpty() || !zonesRasterBlock->isValid() || zonesRasterBlock->isEmpty() )
245 for (
int row = 0; row < iterRows; row++ )
250 for (
int column = 0; column < iterCols; column++ )
252 double value = rasterBlock->valueAndNoData( row, column, isNoData );
253 if ( mHasNoDataValue && isNoData )
258 double zone = zonesRasterBlock->valueAndNoData( row, column, isNoData );
259 if ( mZonesHasNoDataValue && isNoData )
264 zoneStats[ zone ].s.addValue( value );
270 outputs.insert( QStringLiteral(
"EXTENT" ), mExtent.toString() );
271 outputs.insert( QStringLiteral(
"CRS_AUTHID" ), mCrs.authid() );
272 outputs.insert( QStringLiteral(
"WIDTH_IN_PIXELS" ), mLayerWidth );
273 outputs.insert( QStringLiteral(
"HEIGHT_IN_PIXELS" ), mLayerHeight );
274 outputs.insert( QStringLiteral(
"TOTAL_PIXEL_COUNT" ), layerSize );
275 outputs.insert( QStringLiteral(
"NODATA_PIXEL_COUNT" ), noDataCount );
277 double pixelArea = mRasterUnitsPerPixelX * mRasterUnitsPerPixelY;
279 for (
auto it = zoneStats.begin(); it != zoneStats.end(); ++it )
284 it->s.min() << it->s.max() << it->s.mean() );
287 outputs.insert( QStringLiteral(
"OUTPUT_TABLE" ), tableDest );
int width() const
Returns the width of the (unclipped) raster.
Use faster inserts, at the cost of updating the passed features to reflect changes made at the provid...
A rectangle specified with double values.
Base class for providing feedback from a processing algorithm.
Parameter is an advanced parameter which should be hidden from users by default.
Iterator for sequentially processing raster cells.
int bandCount() const
Returns the number of bands in this layer.
This class provides qgis with the ability to render raster datasets onto the mapcanvas.
double rasterUnitsPerPixelX() const
Returns the number of raster units per each raster pixel in X axis.
QgsRasterInterface * clone() const override=0
Clone itself, create deep copy.
void setProgress(double progress)
Sets the current progress for the feedback object.
double rasterUnitsPerPixelY() const
Returns the number of raster units per each raster pixel in Y axis.
Container of fields for a vector layer.
void setAttributes(const QgsAttributes &attrs)
Sets the feature's attributes.
A numeric output for processing algorithms.
A raster band parameter for Processing algorithms.
int height() const
Returns the height of the (unclipped) raster.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
A feature sink output for processing algorithms.
virtual QgsRectangle extent() const
Returns the extent of the layer.
A string output for processing algorithms.
QgsRasterDataProvider * dataProvider() override
Returns the layer's data provider, it may be nullptr.
A raster layer parameter for processing algorithms.
static Q_INVOKABLE QString toAbbreviatedString(QgsUnitTypes::DistanceUnit unit)
Returns a translated abbreviation representing a distance unit.
static const int DEFAULT_MAXIMUM_TILE_HEIGHT
Default maximum tile height.
Custom exception class for processing related exceptions.
QgsCoordinateTransformContext transformContext() const
Returns the coordinate transform context.
bool append(const QgsField &field, FieldOrigin origin=OriginProvider, int originIndex=-1)
Appends a field. The field must have unique name, otherwise it is rejected (returns false) ...
Encapsulate a field in an attribute table or data source.
bool readNextRasterPart(int bandNumber, int &nCols, int &nRows, QgsRasterBlock **block, int &topLeftCol, int &topLeftRow)
Fetches next part of raster data, caller takes ownership of the block and caller should delete the bl...
virtual bool sourceHasNoDataValue(int bandNo) const
Returns true if source band has no data value.
unsigned long long qgssize
Qgssize is used instead of size_t, because size_t is stdlib type, unknown by SIP, and it would be har...
bool isCanceled() const
Tells whether the operation has been canceled already.
This class represents a coordinate reference system (CRS).
Tables (i.e. vector layers with or without geometry). When used for a sink this indicates the sink ha...
Calculator for summary statistics for a list of doubles.
Contains information about the context in which a processing algorithm is executed.
static const int DEFAULT_MAXIMUM_TILE_WIDTH
Default maximum tile width.
static Q_INVOKABLE QgsUnitTypes::AreaUnit distanceToAreaUnit(QgsUnitTypes::DistanceUnit distanceUnit)
Converts a distance unit to its corresponding area unit, e.g., meters to square meters.
void startRasterRead(int bandNumber, int nCols, int nRows, const QgsRectangle &extent, QgsRasterBlockFeedback *feedback=nullptr)
Start reading of raster band.
QgsCoordinateReferenceSystem crs