22 QString QgsRasterLayerUniqueValuesReportAlgorithm::name()
const 24 return QStringLiteral(
"rasterlayeruniquevaluesreport" );
27 QString QgsRasterLayerUniqueValuesReportAlgorithm::displayName()
const 29 return QObject::tr(
"Raster layer unique values report" );
32 QStringList QgsRasterLayerUniqueValuesReportAlgorithm::tags()
const 34 return QObject::tr(
"count,area,statistics" ).split(
',' );
37 QString QgsRasterLayerUniqueValuesReportAlgorithm::group()
const 39 return QObject::tr(
"Raster analysis" );
42 QString QgsRasterLayerUniqueValuesReportAlgorithm::groupId()
const 44 return QStringLiteral(
"rasteranalysis" );
47 void QgsRasterLayerUniqueValuesReportAlgorithm::initAlgorithm(
const QVariantMap & )
50 QObject::tr(
"Input layer" ) ) );
52 QObject::tr(
"Band number" ), 1, QStringLiteral(
"INPUT" ) ) );
54 QObject::tr(
"Unique values report" ), QObject::tr(
"HTML files (*.html)" ), QVariant(),
true ) );
61 addOutput(
new QgsProcessingOutputNumber( QStringLiteral(
"NODATA_PIXEL_COUNT" ), QObject::tr(
"NODATA pixel count" ) ) );
64 QString QgsRasterLayerUniqueValuesReportAlgorithm::shortHelpString()
const 66 return QObject::tr(
"This algorithm returns the count and area of each unique value in a given raster layer." );
69 QgsRasterLayerUniqueValuesReportAlgorithm *QgsRasterLayerUniqueValuesReportAlgorithm::createInstance()
const 71 return new QgsRasterLayerUniqueValuesReportAlgorithm();
76 QgsRasterLayer *layer = parameterAsRasterLayer( parameters, QStringLiteral(
"INPUT" ), context );
77 int band = parameterAsInt( parameters, QStringLiteral(
"BAND" ), context );
84 mLayerWidth = layer->
width();
85 mLayerHeight = layer->
height();
97 int band = parameterAsInt( parameters, QStringLiteral(
"BAND" ), context );
98 QString outputFile = parameterAsFileOutput( parameters, QStringLiteral(
"OUTPUT_HTML_FILE" ), context );
100 QHash< double, qgssize > uniqueValues;
103 qgssize layerSize =
static_cast< qgssize >( mLayerWidth ) * static_cast< qgssize >( mLayerHeight );
105 int maxHeight = 4000;
106 int nbBlocksWidth = std::ceil( 1.0 * mLayerWidth / maxWidth );
107 int nbBlocksHeight = std::ceil( 1.0 * mLayerHeight / maxHeight );
108 int nbBlocks = nbBlocksWidth * nbBlocksHeight;
112 iter.setMaximumTileHeight( maxHeight );
113 iter.startRasterRead( band, mLayerWidth, mLayerHeight, mExtent );
120 while ( iter.readNextRasterPart( band, iterCols, iterRows, &rasterBlock, iterLeft, iterTop ) )
122 feedback->
setProgress( 100 * ( ( iterTop / maxHeight * nbBlocksWidth ) + iterLeft / maxWidth ) / nbBlocks );
123 for (
int row = 0; row < iterRows; row++ )
127 for (
int column = 0; column < iterCols; column++ )
129 if ( mHasNoDataValue && rasterBlock->
isNoData( row, column ) )
135 double value = rasterBlock->
value( row, column );
136 uniqueValues[ value ]++;
143 QMap< double, qgssize > sortedUniqueValues;
144 for (
auto it = uniqueValues.constBegin(); it != uniqueValues.constEnd(); ++it )
146 sortedUniqueValues.insert( it.key(), it.value() );
150 outputs.insert( QStringLiteral(
"EXTENT" ), mExtent.toString() );
151 outputs.insert( QStringLiteral(
"CRS_AUTHID" ), mCrs.authid() );
152 outputs.insert( QStringLiteral(
"WIDTH_IN_PIXELS" ), mLayerWidth );
153 outputs.insert( QStringLiteral(
"HEIGHT_IN_PIXELS" ), mLayerHeight );
154 outputs.insert( QStringLiteral(
"TOTAL_PIXEL_COUNT" ), layerSize );
155 outputs.insert( QStringLiteral(
"NODATA_PIXEL_COUNT" ), noDataCount );
157 if ( !outputFile.isEmpty() )
159 QFile file( outputFile );
160 if ( file.open( QIODevice::WriteOnly | QIODevice::Text ) )
163 double pixelArea = mRasterUnitsPerPixelX * mRasterUnitsPerPixelY;
165 QTextStream out( &file );
166 out << QString(
"<html><head><meta http-equiv=\"Content-Type\" content=\"text/html;charset=utf-8\"/></head><body>\n" );
167 out << QString(
"<p>%1: %2 (%3 %4)</p>\n" ).arg( QObject::tr(
"Analyzed file" ), mSource, QObject::tr(
"band" ) ).arg( band );
168 out << QObject::tr(
"<p>%1: %2</p>\n" ).arg( QObject::tr(
"Extent" ), mExtent.toString() );
169 out << QObject::tr(
"<p>%1: %2 (%3)</p>\n" ).arg( QObject::tr(
"Projection" ), mCrs.description(), mCrs.authid() );
170 out << QObject::tr(
"<p>%1: %2 (%3 %4)</p>\n" ).arg( QObject::tr(
"Width in pixels" ) ).arg( mLayerWidth ).arg( QObject::tr(
"units per pixel" ) ).arg( mRasterUnitsPerPixelX );
171 out << QObject::tr(
"<p>%1: %2 (%3 %4)</p>\n" ).arg( QObject::tr(
"Height in pixels" ) ).arg( mLayerHeight ).arg( QObject::tr(
"units per pixel" ) ).arg( mRasterUnitsPerPixelY );
172 out << QObject::tr(
"<p>%1: %2</p>\n" ).arg( QObject::tr(
"Total pixel count" ) ).arg( layerSize );
173 if ( mHasNoDataValue )
174 out << QObject::tr(
"<p>%1: %2</p>\n" ).arg( QObject::tr(
"NODATA pixel count" ) ).arg( noDataCount );
175 out << QString(
"<table><tr><td>%1</td><td>%2</td><td>%3 (%4)</td></tr>\n" ).arg( QObject::tr(
"Value" ), QObject::tr(
"Pixel count" ), QObject::tr(
"Area" ), areaUnit );
177 for (
auto it = sortedUniqueValues.constBegin(); it != sortedUniqueValues.constEnd(); ++it )
179 double area = it.value() * pixelArea;
180 out << QString(
"<tr><td>%1</td><td>%2</td><td>%3</td></tr>\n" ).arg( it.key() ).arg( it.value() ).arg( QString::number( area,
'g', 16 ) );
182 out << QString(
"</table>\n</body></html>" );
183 outputs.insert( QStringLiteral(
"OUTPUT_HTML_FILE" ), outputFile );
int width() const
Accessor that returns the width of the (unclipped) raster.
Base class for providing feedback from a processing algorithm.
Iterator for sequentially processing raster cells.
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. In a world file, this is normally the first row (without the sign)
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. In a world file, this is normally the first row (without the sign)
A numeric output for processing algorithms.
A raster band parameter for Processing algorithms.
int height() const
Accessor that returns the height of the (unclipped) raster.
bool isNoData(int row, int column)
Check if value at position is no data.
virtual QgsRectangle extent() const
Returns the extent of the layer.
A string output for processing algorithms.
QgsRasterDataProvider * dataProvider() override
A raster layer parameter for processing algorithms.
static Q_INVOKABLE QString toAbbreviatedString(QgsUnitTypes::DistanceUnit unit)
Returns a translated abbreviation representing a distance unit.
QgsCoordinateReferenceSystem crs() const
Returns the layer's spatial reference system.
A generic file based destination parameter, for specifying the destination path for a file (non-map l...
virtual bool sourceHasNoDataValue(int bandNo) const
Return 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...
void setMaximumTileWidth(int w)
bool isCanceled() const
Tells whether the operation has been canceled already.
QString source() const
Returns the source for the layer.
double value(int row, int column) const
Read a single value if type of block is numeric.
Contains information about the context in which a processing algorithm is executed.
static Q_INVOKABLE QgsUnitTypes::AreaUnit distanceToAreaUnit(QgsUnitTypes::DistanceUnit distanceUnit)
Converts a distance unit to its corresponding area unit, e.g., meters to square meters.