23 QString QgsRasterLayerUniqueValuesReportAlgorithm::name()
const
25 return QStringLiteral(
"rasterlayeruniquevaluesreport" );
28 QString QgsRasterLayerUniqueValuesReportAlgorithm::displayName()
const
30 return QObject::tr(
"Raster layer unique values report" );
33 QStringList QgsRasterLayerUniqueValuesReportAlgorithm::tags()
const
35 return QObject::tr(
"count,area,statistics" ).split(
',' );
38 QString QgsRasterLayerUniqueValuesReportAlgorithm::group()
const
40 return QObject::tr(
"Raster analysis" );
43 QString QgsRasterLayerUniqueValuesReportAlgorithm::groupId()
const
45 return QStringLiteral(
"rasteranalysis" );
48 void QgsRasterLayerUniqueValuesReportAlgorithm::initAlgorithm(
const QVariantMap & )
51 QObject::tr(
"Input layer" ) ) );
53 QObject::tr(
"Band number" ), 1, QStringLiteral(
"INPUT" ) ) );
55 QObject::tr(
"Unique values report" ), QObject::tr(
"HTML files (*.html)" ), QVariant(),
true ) );
64 addOutput(
new QgsProcessingOutputNumber( QStringLiteral(
"NODATA_PIXEL_COUNT" ), QObject::tr(
"NODATA pixel count" ) ) );
67 QString QgsRasterLayerUniqueValuesReportAlgorithm::shortHelpString()
const
69 return QObject::tr(
"This algorithm returns the count and area of each unique value in a given raster layer." );
72 QgsRasterLayerUniqueValuesReportAlgorithm *QgsRasterLayerUniqueValuesReportAlgorithm::createInstance()
const
74 return new QgsRasterLayerUniqueValuesReportAlgorithm();
79 QgsRasterLayer *layer = parameterAsRasterLayer( parameters, QStringLiteral(
"INPUT" ), context );
80 int band = parameterAsInt( parameters, QStringLiteral(
"BAND" ), context );
85 mBand = parameterAsInt( parameters, QStringLiteral(
"BAND" ), context );
86 if ( mBand < 1 || mBand > layer->
bandCount() )
87 throw QgsProcessingException( QObject::tr(
"Invalid band number for BAND (%1): Valid values for input raster are 1 to %2" ).arg( mBand )
92 mLayerWidth = layer->
width();
93 mLayerHeight = layer->
height();
105 QString outputFile = parameterAsFileOutput( parameters, QStringLiteral(
"OUTPUT_HTML_FILE" ), context );
110 std::unique_ptr< QgsFeatureSink > sink;
111 if ( parameters.contains( QStringLiteral(
"OUTPUT_TABLE" ) ) && parameters.value( QStringLiteral(
"OUTPUT_TABLE" ) ).isValid() )
114 outFields.
append(
QgsField( QStringLiteral(
"value" ), QVariant::Double, QString(), 20, 8 ) );
115 outFields.
append(
QgsField( QStringLiteral(
"count" ), QVariant::Int, QString(), 20 ) );
116 outFields.
append(
QgsField( areaUnit.replace( QStringLiteral(
"²" ), QStringLiteral(
"2" ) ), QVariant::Double, QString(), 20, 8 ) );
122 QHash< double, qgssize > uniqueValues;
128 int nbBlocksWidth = std::ceil( 1.0 * mLayerWidth / maxWidth );
129 int nbBlocksHeight = std::ceil( 1.0 * mLayerHeight / maxHeight );
130 int nbBlocks = nbBlocksWidth * nbBlocksHeight;
133 iter.startRasterRead( mBand, mLayerWidth, mLayerHeight, mExtent );
139 bool isNoData =
false;
140 std::unique_ptr< QgsRasterBlock > rasterBlock;
141 while ( iter.readNextRasterPart( mBand, iterCols, iterRows, rasterBlock, iterLeft, iterTop ) )
143 feedback->
setProgress( 100 * ( ( iterTop / maxHeight * nbBlocksWidth ) + iterLeft / maxWidth ) / nbBlocks );
144 for (
int row = 0; row < iterRows; row++ )
148 for (
int column = 0; column < iterCols; column++ )
150 double value = rasterBlock->valueAndNoData( row, column, isNoData );
151 if ( mHasNoDataValue && isNoData )
157 uniqueValues[ value ]++;
163 QMap< double, qgssize > sortedUniqueValues;
164 for (
auto it = uniqueValues.constBegin(); it != uniqueValues.constEnd(); ++it )
166 sortedUniqueValues.insert( it.key(), it.value() );
170 outputs.insert( QStringLiteral(
"EXTENT" ), mExtent.toString() );
171 outputs.insert( QStringLiteral(
"CRS_AUTHID" ), mCrs.authid() );
172 outputs.insert( QStringLiteral(
"WIDTH_IN_PIXELS" ), mLayerWidth );
173 outputs.insert( QStringLiteral(
"HEIGHT_IN_PIXELS" ), mLayerHeight );
174 outputs.insert( QStringLiteral(
"TOTAL_PIXEL_COUNT" ), layerSize );
175 outputs.insert( QStringLiteral(
"NODATA_PIXEL_COUNT" ), noDataCount );
177 double pixelArea = mRasterUnitsPerPixelX * mRasterUnitsPerPixelY;
179 if ( !outputFile.isEmpty() )
181 QFile file( outputFile );
182 if ( file.open( QIODevice::WriteOnly | QIODevice::Text ) )
186 QTextStream out( &file );
187 out << QStringLiteral(
"<html><head><meta http-equiv=\"Content-Type\" content=\"text/html;charset=utf-8\"/></head><body>\n" );
188 out << QStringLiteral(
"<p>%1: %2 (%3 %4)</p>\n" ).arg( QObject::tr(
"Analyzed file" ), mSource, QObject::tr(
"band" ) ).arg( mBand );
189 out << QObject::tr(
"<p>%1: %2</p>\n" ).arg( QObject::tr(
"Extent" ), mExtent.toString() );
190 out << QObject::tr(
"<p>%1: %2</p>\n" ).arg( QObject::tr(
"Projection" ), mCrs.userFriendlyIdentifier() );
191 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 );
192 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 );
193 out << QObject::tr(
"<p>%1: %2</p>\n" ).arg( QObject::tr(
"Total pixel count" ) ).arg( layerSize );
194 if ( mHasNoDataValue )
195 out << QObject::tr(
"<p>%1: %2</p>\n" ).arg( QObject::tr(
"NODATA pixel count" ) ).arg( noDataCount );
196 out << QStringLiteral(
"<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" ), encodedAreaUnit );
198 for (
auto it = sortedUniqueValues.constBegin(); it != sortedUniqueValues.constEnd(); ++it )
200 double area = it.value() * pixelArea;
201 out << QStringLiteral(
"<tr><td>%1</td><td>%2</td><td>%3</td></tr>\n" ).arg( it.key() ).arg( it.value() ).arg( QString::number( area,
'g', 16 ) );
203 out << QStringLiteral(
"</table>\n</body></html>" );
204 outputs.insert( QStringLiteral(
"OUTPUT_HTML_FILE" ), outputFile );
210 for (
auto it = sortedUniqueValues.constBegin(); it != sortedUniqueValues.constEnd(); ++it )
213 double area = it.value() * pixelArea;
217 outputs.insert( QStringLiteral(
"OUTPUT_TABLE" ), tableDest );