QGIS API Documentation 3.99.0-Master (d270888f95f)
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#include <QString>
35
36using namespace Qt::StringLiterals;
37
39 : mMinimumValue( minimumValuePossible( dataType ) )
40 , mMaximumValue( maximumValuePossible( dataType ) )
41 , mRasterDataType( dataType )
42 , mRasterDataTypeRange( mMaximumValue - mMinimumValue )
43 , mLookupTableOffset( mMinimumValue * -1 )
44{
45 mContrastEnhancementFunction = std::make_unique<QgsContrastEnhancementFunction>( mRasterDataType, mMinimumValue, mMaximumValue );
46
47 //If the data type is larger than 16-bit do not generate a lookup table
48 if ( mRasterDataTypeRange <= 65535.0 )
49 {
50 mLookupTable = std::make_unique<int[]>( static_cast <int>( mRasterDataTypeRange + 1 ) );
51 }
52}
53
55 : mEnhancementDirty( true )
56 , mMinimumValue( ce.mMinimumValue )
57 , mMaximumValue( ce.mMaximumValue )
58 , mRasterDataType( ce.mRasterDataType )
59 , mRasterDataTypeRange( ce.mRasterDataTypeRange )
60{
61 mLookupTableOffset = minimumValuePossible( mRasterDataType ) * -1;
62
63 // setContrastEnhancementAlgorithm sets also QgsContrastEnhancementFunction
64 setContrastEnhancementAlgorithm( ce.mContrastEnhancementAlgorithm, false );
65
66 //If the data type is larger than 16-bit do not generate a lookup table
67 if ( mRasterDataTypeRange <= 65535.0 )
68 {
69 mLookupTable = std::make_unique<int[]>( static_cast <int>( mRasterDataTypeRange + 1 ) );
70 }
71}
72
77
79{
80 if ( mEnhancementDirty )
81 {
82 generateLookupTable();
83 }
84
85 if ( mLookupTable && NoEnhancement != mContrastEnhancementAlgorithm )
86 {
87 const double shiftedValue = value + mLookupTableOffset;
88 if ( shiftedValue >= 0 && shiftedValue < mRasterDataTypeRange + 1 )
89 return mLookupTable[static_cast <int>( shiftedValue )];
90 return 0;
91 }
92 else
93 {
94 // Even if the contrast enhancement algorithms is set to NoEnhancement
95 // The input values will still have to be scaled for all data types
96 // greater than 1 byte.
97 return mContrastEnhancementFunction->enhance( value );
98 }
99}
100
101bool QgsContrastEnhancement::generateLookupTable()
102{
103 mEnhancementDirty = false;
104
105 if ( !mContrastEnhancementFunction )
106 return false;
107 if ( NoEnhancement == mContrastEnhancementAlgorithm )
108 return false;
109
110 switch ( mRasterDataType )
111 {
116 break;
117
129 return false;
130 }
131
132 if ( !mLookupTable )
133 return false;
134
135 QgsDebugMsgLevel( u"building lookup table"_s, 4 );
136 QgsDebugMsgLevel( u"***MinimumValue : %1"_s.arg( mMinimumValue ), 4 );
137 QgsDebugMsgLevel( u"***MaximumValue : %1"_s.arg( mMaximumValue ), 4 );
138 QgsDebugMsgLevel( u"***mLookupTableOffset : %1"_s.arg( mLookupTableOffset ), 4 );
139 QgsDebugMsgLevel( u"***mRasterDataTypeRange : %1"_s.arg( mRasterDataTypeRange ), 4 );
140
141 for ( int myIterator = 0; myIterator <= mRasterDataTypeRange; myIterator++ )
142 {
143 mLookupTable[myIterator] = mContrastEnhancementFunction->enhance( static_cast< double >( myIterator ) - mLookupTableOffset );
144 }
145
146 return true;
147}
148
150{
151 if ( mContrastEnhancementFunction )
152 {
153 return mContrastEnhancementFunction->isValueInDisplayableRange( value );
154 }
155
156 return false;
157}
158
160{
161 switch ( algorithm )
162 {
164 mContrastEnhancementFunction = std::make_unique<QgsLinearMinMaxEnhancement>( mRasterDataType, mMinimumValue, mMaximumValue );
165 break;
167 mContrastEnhancementFunction = std::make_unique<QgsLinearMinMaxEnhancementWithClip>( mRasterDataType, mMinimumValue, mMaximumValue );
168 break;
170 mContrastEnhancementFunction = std::make_unique<QgsClipToMinMaxEnhancement>( mRasterDataType, mMinimumValue, mMaximumValue );
171 break;
173 //Do nothing
174 break;
175 default:
176 mContrastEnhancementFunction = std::make_unique<QgsContrastEnhancementFunction>( mRasterDataType, mMinimumValue, mMaximumValue );
177 break;
178 }
179
180 mEnhancementDirty = true;
181 mContrastEnhancementAlgorithm = algorithm;
182
183 if ( generateTable )
184 {
185 generateLookupTable();
186 }
187}
188
190{
191 QgsDebugMsgLevel( u"called"_s, 4 );
192
193 if ( function )
194 {
195 mContrastEnhancementFunction.reset( function );
196 mContrastEnhancementAlgorithm = UserDefinedEnhancement;
197 generateLookupTable();
198 }
199}
200
201void QgsContrastEnhancement::setMaximumValue( double value, bool generateTable )
202{
203 QgsDebugMsgLevel( "called value: " + QString::number( value ) + " generate lookup table: " + QString::number( static_cast< int >( generateTable ) ), 4 );
204
205 if ( value > maximumValuePossible( mRasterDataType ) )
206 {
207 mMaximumValue = maximumValuePossible( mRasterDataType );
208 }
209 else
210 {
211 mMaximumValue = value;
212 }
213
214 if ( mContrastEnhancementFunction )
215 {
216 mContrastEnhancementFunction->setMaximumValue( value );
217 }
218
219 mEnhancementDirty = true;
220
221 if ( generateTable )
222 {
223 generateLookupTable();
224 }
225}
226
227void QgsContrastEnhancement::setMinimumValue( double value, bool generateTable )
228{
229 QgsDebugMsgLevel( "called value: " + QString::number( value ) + " generate lookup table: " + QString::number( static_cast< int >( generateTable ) ), 4 );
230
231 if ( value < minimumValuePossible( mRasterDataType ) )
232 {
233 mMinimumValue = minimumValuePossible( mRasterDataType );
234 }
235 else
236 {
237 mMinimumValue = value;
238 }
239
240 if ( mContrastEnhancementFunction )
241 {
242 mContrastEnhancementFunction->setMinimumValue( value );
243 }
244
245 mEnhancementDirty = true;
246
247 if ( generateTable )
248 {
249 generateLookupTable();
250 }
251}
252
253void QgsContrastEnhancement::writeXml( QDomDocument &doc, QDomElement &parentElem ) const
254{
255 //minimum value
256 QDomElement minElem = doc.createElement( u"minValue"_s );
257 const QDomText minText = doc.createTextNode( QgsRasterBlock::printValue( mMinimumValue ) );
258 minElem.appendChild( minText );
259 parentElem.appendChild( minElem );
260
261 //maximum value
262 QDomElement maxElem = doc.createElement( u"maxValue"_s );
263 const QDomText maxText = doc.createTextNode( QgsRasterBlock::printValue( mMaximumValue ) );
264 maxElem.appendChild( maxText );
265 parentElem.appendChild( maxElem );
266
267 //algorithm
268 QDomElement algorithmElem = doc.createElement( u"algorithm"_s );
269 const QDomText algorithmText = doc.createTextNode( contrastEnhancementAlgorithmString( mContrastEnhancementAlgorithm ) );
270 algorithmElem.appendChild( algorithmText );
271 parentElem.appendChild( algorithmElem );
272}
273
274void QgsContrastEnhancement::readXml( const QDomElement &elem )
275{
276 const QDomElement minValueElem = elem.firstChildElement( u"minValue"_s );
277 if ( !minValueElem.isNull() )
278 {
279 mMinimumValue = minValueElem.text().toDouble();
280 }
281 const QDomElement maxValueElem = elem.firstChildElement( u"maxValue"_s );
282 if ( !maxValueElem.isNull() )
283 {
284 mMaximumValue = maxValueElem.text().toDouble();
285 }
286 const QDomElement algorithmElem = elem.firstChildElement( u"algorithm"_s );
287 if ( !algorithmElem.isNull() )
288 {
289 const QString algorithmString = algorithmElem.text();
291 // old version ( < 19 Apr 2013) was using enum directly -> for backward compatibility
292 if ( algorithmString == "0"_L1 )
293 {
295 }
296 else if ( algorithmString == "1"_L1 )
297 {
299 }
300 else if ( algorithmString == "2"_L1 )
301 {
303 }
304 else if ( algorithmString == "3"_L1 )
305 {
307 }
308 else if ( algorithmString == "4"_L1 )
309 {
311 }
312 else
313 {
315 }
316
318 }
319}
320
321void QgsContrastEnhancement::toSld( QDomDocument &doc, QDomElement &element ) const
322{
323 if ( doc.isNull() || element.isNull() )
324 return;
325
326 QString algName;
328 {
330 algName = u"StretchToMinimumMaximum"_s;
331 break;
332 /* TODO: check if ClipToZero => StretchAndClipToMinimumMaximum
333 * because value outside min/max ar considered as NoData instead of 0 */
335 algName = u"ClipToMinimumMaximum"_s;
336 break;
338 algName = u"ClipToMinimumMaximum"_s;
339 break;
340 case NoEnhancement:
341 return;
344 QgsDebugError( u"No SLD1.0 conversion yet for stretch algorithm %1"_s.arg( algName ) );
345 return;
346 }
347
348 // Only <Normalize> is supported
349 // minValue and maxValue are that values as set depending on "Min /Max value settings"
350 // parameters
351 QDomElement normalizeElem = doc.createElement( u"sld:Normalize"_s );
352 element.appendChild( normalizeElem );
353
354 QDomElement vendorOptionAlgorithmElem = doc.createElement( u"sld:VendorOption"_s );
355 vendorOptionAlgorithmElem.setAttribute( u"name"_s, u"algorithm"_s );
356 vendorOptionAlgorithmElem.appendChild( doc.createTextNode( algName ) );
357 normalizeElem.appendChild( vendorOptionAlgorithmElem );
358
359 QDomElement vendorOptionMinValueElem = doc.createElement( u"sld:VendorOption"_s );
360 vendorOptionMinValueElem.setAttribute( u"name"_s, u"minValue"_s );
361 vendorOptionMinValueElem.appendChild( doc.createTextNode( QString::number( minimumValue() ) ) );
362 normalizeElem.appendChild( vendorOptionMinValueElem );
363
364 QDomElement vendorOptionMaxValueElem = doc.createElement( u"sld:VendorOption"_s );
365 vendorOptionMaxValueElem.setAttribute( u"name"_s, u"maxValue"_s );
366 vendorOptionMaxValueElem.appendChild( doc.createTextNode( QString::number( maximumValue() ) ) );
367 normalizeElem.appendChild( vendorOptionMaxValueElem );
368}
369
371{
372 switch ( algorithm )
373 {
374 case NoEnhancement:
375 return u"NoEnhancement"_s;
377 return u"StretchToMinimumMaximum"_s;
379 return u"StretchAndClipToMinimumMaximum"_s;
381 return u"ClipToMinimumMaximum"_s;
383 return u"UserDefinedEnhancement"_s;
384 }
385 return u"NoEnhancement"_s;
386}
387
389{
390 if ( contrastEnhancementString == "StretchToMinimumMaximum"_L1 )
391 {
393 }
394 else if ( contrastEnhancementString == "StretchAndClipToMinimumMaximum"_L1 )
395 {
397 }
398 else if ( contrastEnhancementString == "ClipToMinimumMaximum"_L1 )
399 {
401 }
402 else if ( contrastEnhancementString == "UserDefinedEnhancement"_L1 )
403 {
405 }
406 else
407 {
408 return NoEnhancement;
409 }
410}
DataType
Raster data types.
Definition qgis.h:379
@ CInt32
Complex Int32.
Definition qgis.h:390
@ Float32
Thirty two bit floating point (float).
Definition qgis.h:387
@ CFloat64
Complex Float64.
Definition qgis.h:392
@ Int16
Sixteen bit signed integer (qint16).
Definition qgis.h:384
@ ARGB32_Premultiplied
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32_Premultiplied.
Definition qgis.h:394
@ Int8
Eight bit signed integer (qint8) (added in QGIS 3.30).
Definition qgis.h:382
@ UInt16
Sixteen bit unsigned integer (quint16).
Definition qgis.h:383
@ Byte
Eight bit unsigned integer (quint8).
Definition qgis.h:381
@ UnknownDataType
Unknown or unspecified type.
Definition qgis.h:380
@ ARGB32
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32.
Definition qgis.h:393
@ Int32
Thirty two bit signed integer (qint32).
Definition qgis.h:386
@ Float64
Sixty four bit floating point (double).
Definition qgis.h:388
@ CFloat32
Complex Float32.
Definition qgis.h:391
@ CInt16
Complex Int16.
Definition qgis.h:389
@ UInt32
Thirty two bit unsigned integer (quint32).
Definition qgis.h:385
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:63
#define QgsDebugError(str)
Definition qgslogger.h:59