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