QGIS API Documentation 3.99.0-Master (26c88405ac0)
Loading...
Searching...
No Matches
qgscontrastenhancement.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgscontrastenhancement.cpp - description
3 -------------------
4begin : Mon Oct 22 2007
5copyright : (C) 2007 by Peter J. Ersts
7
8This class contains code that was originally part of the larger QgsRasterLayer
9class originally created circa 2004 by T.Sutton, Gary E.Sherman, Steve Halasz
10****************************************************************************/
11
12/***************************************************************************
13 * *
14 * This program is free software; you can redistribute it and/or modify *
15 * it under the terms of the GNU General Public License as published by *
16 * the Free Software Foundation; either version 2 of the License, or *
17 * (at your option) any later version. *
18 * *
19 ***************************************************************************/
20
22
23#include <memory>
24
29#include "qgslogger.h"
30#include "qgsrasterblock.h"
31
32#include <QDomDocument>
33#include <QDomElement>
34
36 : mMinimumValue( minimumValuePossible( dataType ) )
37 , mMaximumValue( maximumValuePossible( dataType ) )
38 , mRasterDataType( dataType )
39 , mRasterDataTypeRange( mMaximumValue - mMinimumValue )
40 , mLookupTableOffset( mMinimumValue * -1 )
41{
42 mContrastEnhancementFunction = std::make_unique<QgsContrastEnhancementFunction>( mRasterDataType, mMinimumValue, mMaximumValue );
43
44 //If the data type is larger than 16-bit do not generate a lookup table
45 if ( mRasterDataTypeRange <= 65535.0 )
46 {
47 mLookupTable = std::make_unique<int[]>( static_cast <int>( mRasterDataTypeRange + 1 ) );
48 }
49}
50
52 : mEnhancementDirty( true )
53 , mMinimumValue( ce.mMinimumValue )
54 , mMaximumValue( ce.mMaximumValue )
55 , mRasterDataType( ce.mRasterDataType )
56 , mRasterDataTypeRange( ce.mRasterDataTypeRange )
57{
58 mLookupTableOffset = minimumValuePossible( mRasterDataType ) * -1;
59
60 // setContrastEnhancementAlgorithm sets also QgsContrastEnhancementFunction
61 setContrastEnhancementAlgorithm( ce.mContrastEnhancementAlgorithm, false );
62
63 //If the data type is larger than 16-bit do not generate a lookup table
64 if ( mRasterDataTypeRange <= 65535.0 )
65 {
66 mLookupTable = std::make_unique<int[]>( static_cast <int>( mRasterDataTypeRange + 1 ) );
67 }
68}
69
74
76{
77 if ( mEnhancementDirty )
78 {
79 generateLookupTable();
80 }
81
82 if ( mLookupTable && NoEnhancement != mContrastEnhancementAlgorithm )
83 {
84 const double shiftedValue = value + mLookupTableOffset;
85 if ( shiftedValue >= 0 && shiftedValue < mRasterDataTypeRange + 1 )
86 return mLookupTable[static_cast <int>( shiftedValue )];
87 return 0;
88 }
89 else
90 {
91 // Even if the contrast enhancement algorithms is set to NoEnhancement
92 // The input values will still have to be scaled for all data types
93 // greater than 1 byte.
94 return mContrastEnhancementFunction->enhance( value );
95 }
96}
97
98bool QgsContrastEnhancement::generateLookupTable()
99{
100 mEnhancementDirty = false;
101
102 if ( !mContrastEnhancementFunction )
103 return false;
104 if ( NoEnhancement == mContrastEnhancementAlgorithm )
105 return false;
106
107 switch ( mRasterDataType )
108 {
113 break;
114
126 return false;
127 }
128
129 if ( !mLookupTable )
130 return false;
131
132 QgsDebugMsgLevel( QStringLiteral( "building lookup table" ), 4 );
133 QgsDebugMsgLevel( QStringLiteral( "***MinimumValue : %1" ).arg( mMinimumValue ), 4 );
134 QgsDebugMsgLevel( QStringLiteral( "***MaximumValue : %1" ).arg( mMaximumValue ), 4 );
135 QgsDebugMsgLevel( QStringLiteral( "***mLookupTableOffset : %1" ).arg( mLookupTableOffset ), 4 );
136 QgsDebugMsgLevel( QStringLiteral( "***mRasterDataTypeRange : %1" ).arg( mRasterDataTypeRange ), 4 );
137
138 for ( int myIterator = 0; myIterator <= mRasterDataTypeRange; myIterator++ )
139 {
140 mLookupTable[myIterator] = mContrastEnhancementFunction->enhance( static_cast< double >( myIterator ) - mLookupTableOffset );
141 }
142
143 return true;
144}
145
147{
148 if ( mContrastEnhancementFunction )
149 {
150 return mContrastEnhancementFunction->isValueInDisplayableRange( value );
151 }
152
153 return false;
154}
155
157{
158 switch ( algorithm )
159 {
161 mContrastEnhancementFunction = std::make_unique<QgsLinearMinMaxEnhancement>( mRasterDataType, mMinimumValue, mMaximumValue );
162 break;
164 mContrastEnhancementFunction = std::make_unique<QgsLinearMinMaxEnhancementWithClip>( mRasterDataType, mMinimumValue, mMaximumValue );
165 break;
167 mContrastEnhancementFunction = std::make_unique<QgsClipToMinMaxEnhancement>( mRasterDataType, mMinimumValue, mMaximumValue );
168 break;
170 //Do nothing
171 break;
172 default:
173 mContrastEnhancementFunction = std::make_unique<QgsContrastEnhancementFunction>( mRasterDataType, mMinimumValue, mMaximumValue );
174 break;
175 }
176
177 mEnhancementDirty = true;
178 mContrastEnhancementAlgorithm = algorithm;
179
180 if ( generateTable )
181 {
182 generateLookupTable();
183 }
184}
185
187{
188 QgsDebugMsgLevel( QStringLiteral( "called" ), 4 );
189
190 if ( function )
191 {
192 mContrastEnhancementFunction.reset( function );
193 mContrastEnhancementAlgorithm = UserDefinedEnhancement;
194 generateLookupTable();
195 }
196}
197
198void QgsContrastEnhancement::setMaximumValue( double value, bool generateTable )
199{
200 QgsDebugMsgLevel( "called value: " + QString::number( value ) + " generate lookup table: " + QString::number( static_cast< int >( generateTable ) ), 4 );
201
202 if ( value > maximumValuePossible( mRasterDataType ) )
203 {
204 mMaximumValue = maximumValuePossible( mRasterDataType );
205 }
206 else
207 {
208 mMaximumValue = value;
209 }
210
211 if ( mContrastEnhancementFunction )
212 {
213 mContrastEnhancementFunction->setMaximumValue( value );
214 }
215
216 mEnhancementDirty = true;
217
218 if ( generateTable )
219 {
220 generateLookupTable();
221 }
222}
223
224void QgsContrastEnhancement::setMinimumValue( double value, bool generateTable )
225{
226 QgsDebugMsgLevel( "called value: " + QString::number( value ) + " generate lookup table: " + QString::number( static_cast< int >( generateTable ) ), 4 );
227
228 if ( value < minimumValuePossible( mRasterDataType ) )
229 {
230 mMinimumValue = minimumValuePossible( mRasterDataType );
231 }
232 else
233 {
234 mMinimumValue = value;
235 }
236
237 if ( mContrastEnhancementFunction )
238 {
239 mContrastEnhancementFunction->setMinimumValue( value );
240 }
241
242 mEnhancementDirty = true;
243
244 if ( generateTable )
245 {
246 generateLookupTable();
247 }
248}
249
250void QgsContrastEnhancement::writeXml( QDomDocument &doc, QDomElement &parentElem ) const
251{
252 //minimum value
253 QDomElement minElem = doc.createElement( QStringLiteral( "minValue" ) );
254 const QDomText minText = doc.createTextNode( QgsRasterBlock::printValue( mMinimumValue ) );
255 minElem.appendChild( minText );
256 parentElem.appendChild( minElem );
257
258 //maximum value
259 QDomElement maxElem = doc.createElement( QStringLiteral( "maxValue" ) );
260 const QDomText maxText = doc.createTextNode( QgsRasterBlock::printValue( mMaximumValue ) );
261 maxElem.appendChild( maxText );
262 parentElem.appendChild( maxElem );
263
264 //algorithm
265 QDomElement algorithmElem = doc.createElement( QStringLiteral( "algorithm" ) );
266 const QDomText algorithmText = doc.createTextNode( contrastEnhancementAlgorithmString( mContrastEnhancementAlgorithm ) );
267 algorithmElem.appendChild( algorithmText );
268 parentElem.appendChild( algorithmElem );
269}
270
271void QgsContrastEnhancement::readXml( const QDomElement &elem )
272{
273 const QDomElement minValueElem = elem.firstChildElement( QStringLiteral( "minValue" ) );
274 if ( !minValueElem.isNull() )
275 {
276 mMinimumValue = minValueElem.text().toDouble();
277 }
278 const QDomElement maxValueElem = elem.firstChildElement( QStringLiteral( "maxValue" ) );
279 if ( !maxValueElem.isNull() )
280 {
281 mMaximumValue = maxValueElem.text().toDouble();
282 }
283 const QDomElement algorithmElem = elem.firstChildElement( QStringLiteral( "algorithm" ) );
284 if ( !algorithmElem.isNull() )
285 {
286 const QString algorithmString = algorithmElem.text();
288 // old version ( < 19 Apr 2013) was using enum directly -> for backward compatibility
289 if ( algorithmString == QLatin1String( "0" ) )
290 {
292 }
293 else if ( algorithmString == QLatin1String( "1" ) )
294 {
296 }
297 else if ( algorithmString == QLatin1String( "2" ) )
298 {
300 }
301 else if ( algorithmString == QLatin1String( "3" ) )
302 {
304 }
305 else if ( algorithmString == QLatin1String( "4" ) )
306 {
308 }
309 else
310 {
312 }
313
315 }
316}
317
318void QgsContrastEnhancement::toSld( QDomDocument &doc, QDomElement &element ) const
319{
320 if ( doc.isNull() || element.isNull() )
321 return;
322
323 QString algName;
325 {
327 algName = QStringLiteral( "StretchToMinimumMaximum" );
328 break;
329 /* TODO: check if ClipToZero => StretchAndClipToMinimumMaximum
330 * because value outside min/max ar considered as NoData instead of 0 */
332 algName = QStringLiteral( "ClipToMinimumMaximum" );
333 break;
335 algName = QStringLiteral( "ClipToMinimumMaximum" );
336 break;
337 case NoEnhancement:
338 return;
341 QgsDebugError( QStringLiteral( "No SLD1.0 conversion yet for stretch algorithm %1" ).arg( algName ) );
342 return;
343 }
344
345 // Only <Normalize> is supported
346 // minValue and maxValue are that values as set depending on "Min /Max value settings"
347 // parameters
348 QDomElement normalizeElem = doc.createElement( QStringLiteral( "sld:Normalize" ) );
349 element.appendChild( normalizeElem );
350
351 QDomElement vendorOptionAlgorithmElem = doc.createElement( QStringLiteral( "sld:VendorOption" ) );
352 vendorOptionAlgorithmElem.setAttribute( QStringLiteral( "name" ), QStringLiteral( "algorithm" ) );
353 vendorOptionAlgorithmElem.appendChild( doc.createTextNode( algName ) );
354 normalizeElem.appendChild( vendorOptionAlgorithmElem );
355
356 QDomElement vendorOptionMinValueElem = doc.createElement( QStringLiteral( "sld:VendorOption" ) );
357 vendorOptionMinValueElem.setAttribute( QStringLiteral( "name" ), QStringLiteral( "minValue" ) );
358 vendorOptionMinValueElem.appendChild( doc.createTextNode( QString::number( minimumValue() ) ) );
359 normalizeElem.appendChild( vendorOptionMinValueElem );
360
361 QDomElement vendorOptionMaxValueElem = doc.createElement( QStringLiteral( "sld:VendorOption" ) );
362 vendorOptionMaxValueElem.setAttribute( QStringLiteral( "name" ), QStringLiteral( "maxValue" ) );
363 vendorOptionMaxValueElem.appendChild( doc.createTextNode( QString::number( maximumValue() ) ) );
364 normalizeElem.appendChild( vendorOptionMaxValueElem );
365}
366
368{
369 switch ( algorithm )
370 {
371 case NoEnhancement:
372 return QStringLiteral( "NoEnhancement" );
374 return QStringLiteral( "StretchToMinimumMaximum" );
376 return QStringLiteral( "StretchAndClipToMinimumMaximum" );
378 return QStringLiteral( "ClipToMinimumMaximum" );
380 return QStringLiteral( "UserDefinedEnhancement" );
381 }
382 return QStringLiteral( "NoEnhancement" );
383}
384
386{
387 if ( contrastEnhancementString == QLatin1String( "StretchToMinimumMaximum" ) )
388 {
390 }
391 else if ( contrastEnhancementString == QLatin1String( "StretchAndClipToMinimumMaximum" ) )
392 {
394 }
395 else if ( contrastEnhancementString == QLatin1String( "ClipToMinimumMaximum" ) )
396 {
398 }
399 else if ( contrastEnhancementString == QLatin1String( "UserDefinedEnhancement" ) )
400 {
402 }
403 else
404 {
405 return NoEnhancement;
406 }
407}
DataType
Raster data types.
Definition qgis.h:372
@ CInt32
Complex Int32.
Definition qgis.h:383
@ Float32
Thirty two bit floating point (float).
Definition qgis.h:380
@ CFloat64
Complex Float64.
Definition qgis.h:385
@ Int16
Sixteen bit signed integer (qint16).
Definition qgis.h:377
@ ARGB32_Premultiplied
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32_Premultiplied.
Definition qgis.h:387
@ Int8
Eight bit signed integer (qint8) (added in QGIS 3.30).
Definition qgis.h:375
@ UInt16
Sixteen bit unsigned integer (quint16).
Definition qgis.h:376
@ Byte
Eight bit unsigned integer (quint8).
Definition qgis.h:374
@ UnknownDataType
Unknown or unspecified type.
Definition qgis.h:373
@ ARGB32
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32.
Definition qgis.h:386
@ Int32
Thirty two bit signed integer (qint32).
Definition qgis.h:379
@ Float64
Sixty four bit floating point (double).
Definition qgis.h:381
@ CFloat32
Complex Float32.
Definition qgis.h:384
@ CInt16
Complex Int16.
Definition qgis.h:382
@ UInt32
Thirty two bit unsigned integer (quint32).
Definition qgis.h:378
A contrast enhancement function is the base class for all raster contrast enhancements.
ContrastEnhancementAlgorithm
This enumerator describes the types of contrast enhancement algorithms that can be used.
@ StretchToMinimumMaximum
Linear histogram.
@ NoEnhancement
Default color scaling algorithm, no scaling is applied.
QgsContrastEnhancement(Qgis::DataType datatype=Qgis::DataType::Byte)
Constructor for QgsContrastEnhancement, for the specified data type.
void setMinimumValue(double value, bool generateTable=true)
Sets the minimum value for the contrast enhancement range.
static QString contrastEnhancementAlgorithmString(ContrastEnhancementAlgorithm algorithm)
Returns a string to serialize ContrastEnhancementAlgorithm.
static ContrastEnhancementAlgorithm contrastEnhancementAlgorithmFromString(const QString &contrastEnhancementString)
Deserialize ContrastEnhancementAlgorithm.
static double maximumValuePossible(Qgis::DataType dataType)
Helper function that returns the maximum possible value for a data type.
void setContrastEnhancementAlgorithm(ContrastEnhancementAlgorithm algorithm, bool generateTable=true)
Sets the contrast enhancement algorithm.
bool isValueInDisplayableRange(double value)
Returns true if a pixel value is in displayable range, false if pixel is outside of range (i....
int enhanceContrast(double value)
Applies the contrast enhancement to a value.
void writeXml(QDomDocument &doc, QDomElement &parentElem) const
void readXml(const QDomElement &elem)
double minimumValue() const
Returns the minimum value for the contrast enhancement range.
static double minimumValuePossible(Qgis::DataType dataType)
Helper function that returns the minimum possible value for a data type.
void setContrastEnhancementFunction(QgsContrastEnhancementFunction *function)
Allows the user to set their own custom contrast enhancement function.
void toSld(QDomDocument &doc, QDomElement &element) const
Write ContrastEnhancement tags following SLD v1.0 specs SLD1.0 is limited to the parameters listed in...
ContrastEnhancementAlgorithm contrastEnhancementAlgorithm() const
void setMaximumValue(double value, bool generateTable=true)
Sets the maximum value for the contrast enhancement range.
double maximumValue() const
Returns the maximum value for the contrast enhancement range.
static QString printValue(double value, bool localized=false)
Print double value with all necessary significant digits.
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 allowing algorithms to be written in pure substantial changes are required in order to port existing x Processing algorithms for QGIS x The most significant changes are outlined not GeoAlgorithm For algorithms which operate on features one by consider subclassing the QgsProcessingFeatureBasedAlgorithm class This class allows much of the boilerplate code for looping over features from a vector layer to be bypassed and instead requires implementation of a processFeature method Ensure that your algorithm(or algorithm 's parent class) implements the new pure virtual createInstance(self) call
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:61
#define QgsDebugError(str)
Definition qgslogger.h:57