QGIS API Documentation 3.28.0-Firenze (ed3ad0430f)
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
21#include "qgslogger.h"
22
28#include "qgsrasterblock.h"
29#include <QDomDocument>
30#include <QDomElement>
31
33 : mMinimumValue( minimumValuePossible( dataType ) )
34 , mMaximumValue( maximumValuePossible( dataType ) )
35 , mRasterDataType( dataType )
36 , mRasterDataTypeRange( mMaximumValue - mMinimumValue )
37 , mLookupTableOffset( mMinimumValue * -1 )
38{
39 mContrastEnhancementFunction.reset( new QgsContrastEnhancementFunction( mRasterDataType, mMinimumValue, mMaximumValue ) );
40
41 //If the data type is larger than 16-bit do not generate a lookup table
42 if ( mRasterDataTypeRange <= 65535.0 )
43 {
44 mLookupTable = new int[static_cast <int>( mRasterDataTypeRange + 1 )];
45 }
46}
47
49 : mEnhancementDirty( true )
50 , mMinimumValue( ce.mMinimumValue )
51 , mMaximumValue( ce.mMaximumValue )
52 , mRasterDataType( ce.mRasterDataType )
53 , mRasterDataTypeRange( ce.mRasterDataTypeRange )
54{
55 mLookupTableOffset = minimumValuePossible( mRasterDataType ) * -1;
56
57 // setContrastEnhancementAlgorithm sets also QgsContrastEnhancementFunction
58 setContrastEnhancementAlgorithm( ce.mContrastEnhancementAlgorithm, false );
59
60 //If the data type is larger than 16-bit do not generate a lookup table
61 if ( mRasterDataTypeRange <= 65535.0 )
62 {
63 mLookupTable = new int[static_cast <int>( mRasterDataTypeRange + 1 )];
64 }
65}
66
68{
69 delete [] mLookupTable;
70}
71
73{
74 if ( mEnhancementDirty )
75 {
76 generateLookupTable();
77 }
78
79 if ( mLookupTable && NoEnhancement != mContrastEnhancementAlgorithm )
80 {
81 const double shiftedValue = value + mLookupTableOffset;
82 if ( shiftedValue >= 0 && shiftedValue < mRasterDataTypeRange + 1 )
83 return mLookupTable[static_cast <int>( shiftedValue )];
84 return 0;
85 }
86 else
87 {
88 // Even if the contrast enhancement algorithms is set to NoEnhancement
89 // The input values will still have to be scaled for all data types
90 // greater than 1 byte.
91 return mContrastEnhancementFunction->enhance( value );
92 }
93}
94
95bool QgsContrastEnhancement::generateLookupTable()
96{
97 mEnhancementDirty = false;
98
99 if ( !mContrastEnhancementFunction )
100 return false;
101 if ( NoEnhancement == mContrastEnhancementAlgorithm )
102 return false;
103 if ( Qgis::DataType::Byte != mRasterDataType && Qgis::DataType::UInt16 != mRasterDataType && Qgis::DataType::Int16 != mRasterDataType )
104 return false;
105 if ( !mLookupTable )
106 return false;
107
108 QgsDebugMsgLevel( QStringLiteral( "building lookup table" ), 4 );
109 QgsDebugMsgLevel( QStringLiteral( "***MinimumValue : %1" ).arg( mMinimumValue ), 4 );
110 QgsDebugMsgLevel( QStringLiteral( "***MaximumValue : %1" ).arg( mMaximumValue ), 4 );
111 QgsDebugMsgLevel( QStringLiteral( "***mLookupTableOffset : %1" ).arg( mLookupTableOffset ), 4 );
112 QgsDebugMsgLevel( QStringLiteral( "***mRasterDataTypeRange : %1" ).arg( mRasterDataTypeRange ), 4 );
113
114 for ( int myIterator = 0; myIterator <= mRasterDataTypeRange; myIterator++ )
115 {
116 mLookupTable[myIterator] = mContrastEnhancementFunction->enhance( static_cast< double >( myIterator ) - mLookupTableOffset );
117 }
118
119 return true;
120}
121
123{
124 if ( mContrastEnhancementFunction )
125 {
126 return mContrastEnhancementFunction->isValueInDisplayableRange( value );
127 }
128
129 return false;
130}
131
133{
134 switch ( algorithm )
135 {
137 mContrastEnhancementFunction.reset( new QgsLinearMinMaxEnhancement( mRasterDataType, mMinimumValue, mMaximumValue ) );
138 break;
140 mContrastEnhancementFunction.reset( new QgsLinearMinMaxEnhancementWithClip( mRasterDataType, mMinimumValue, mMaximumValue ) );
141 break;
143 mContrastEnhancementFunction.reset( new QgsClipToMinMaxEnhancement( mRasterDataType, mMinimumValue, mMaximumValue ) );
144 break;
146 //Do nothing
147 break;
148 default:
149 mContrastEnhancementFunction.reset( new QgsContrastEnhancementFunction( mRasterDataType, mMinimumValue, mMaximumValue ) );
150 break;
151 }
152
153 mEnhancementDirty = true;
154 mContrastEnhancementAlgorithm = algorithm;
155
156 if ( generateTable )
157 {
158 generateLookupTable();
159 }
160}
161
163{
164 QgsDebugMsgLevel( QStringLiteral( "called" ), 4 );
165
166 if ( function )
167 {
168 mContrastEnhancementFunction.reset( function );
169 mContrastEnhancementAlgorithm = UserDefinedEnhancement;
170 generateLookupTable();
171 }
172}
173
174void QgsContrastEnhancement::setMaximumValue( double value, bool generateTable )
175{
176 QgsDebugMsgLevel( "called value: " + QString::number( value ) + " generate lookup table: " + QString::number( static_cast< int >( generateTable ) ), 4 );
177
178 if ( value > maximumValuePossible( mRasterDataType ) )
179 {
180 mMaximumValue = maximumValuePossible( mRasterDataType );
181 }
182 else
183 {
184 mMaximumValue = value;
185 }
186
187 if ( mContrastEnhancementFunction )
188 {
189 mContrastEnhancementFunction->setMaximumValue( value );
190 }
191
192 mEnhancementDirty = true;
193
194 if ( generateTable )
195 {
196 generateLookupTable();
197 }
198}
199
200void QgsContrastEnhancement::setMinimumValue( double value, bool generateTable )
201{
202 QgsDebugMsgLevel( "called value: " + QString::number( value ) + " generate lookup table: " + QString::number( static_cast< int >( generateTable ) ), 4 );
203
204 if ( value < minimumValuePossible( mRasterDataType ) )
205 {
206 mMinimumValue = minimumValuePossible( mRasterDataType );
207 }
208 else
209 {
210 mMinimumValue = value;
211 }
212
213 if ( mContrastEnhancementFunction )
214 {
215 mContrastEnhancementFunction->setMinimumValue( value );
216 }
217
218 mEnhancementDirty = true;
219
220 if ( generateTable )
221 {
222 generateLookupTable();
223 }
224}
225
226void QgsContrastEnhancement::writeXml( QDomDocument &doc, QDomElement &parentElem ) const
227{
228 //minimum value
229 QDomElement minElem = doc.createElement( QStringLiteral( "minValue" ) );
230 const QDomText minText = doc.createTextNode( QgsRasterBlock::printValue( mMinimumValue ) );
231 minElem.appendChild( minText );
232 parentElem.appendChild( minElem );
233
234 //maximum value
235 QDomElement maxElem = doc.createElement( QStringLiteral( "maxValue" ) );
236 const QDomText maxText = doc.createTextNode( QgsRasterBlock::printValue( mMaximumValue ) );
237 maxElem.appendChild( maxText );
238 parentElem.appendChild( maxElem );
239
240 //algorithm
241 QDomElement algorithmElem = doc.createElement( QStringLiteral( "algorithm" ) );
242 const QDomText algorithmText = doc.createTextNode( contrastEnhancementAlgorithmString( mContrastEnhancementAlgorithm ) );
243 algorithmElem.appendChild( algorithmText );
244 parentElem.appendChild( algorithmElem );
245}
246
247void QgsContrastEnhancement::readXml( const QDomElement &elem )
248{
249 const QDomElement minValueElem = elem.firstChildElement( QStringLiteral( "minValue" ) );
250 if ( !minValueElem.isNull() )
251 {
252 mMinimumValue = minValueElem.text().toDouble();
253 }
254 const QDomElement maxValueElem = elem.firstChildElement( QStringLiteral( "maxValue" ) );
255 if ( !maxValueElem.isNull() )
256 {
257 mMaximumValue = maxValueElem.text().toDouble();
258 }
259 const QDomElement algorithmElem = elem.firstChildElement( QStringLiteral( "algorithm" ) );
260 if ( !algorithmElem.isNull() )
261 {
262 const QString algorithmString = algorithmElem.text();
264 // old version ( < 19 Apr 2013) was using enum directly -> for backward compatibility
265 if ( algorithmString == QLatin1String( "0" ) )
266 {
268 }
269 else if ( algorithmString == QLatin1String( "1" ) )
270 {
272 }
273 else if ( algorithmString == QLatin1String( "2" ) )
274 {
276 }
277 else if ( algorithmString == QLatin1String( "3" ) )
278 {
280 }
281 else if ( algorithmString == QLatin1String( "4" ) )
282 {
284 }
285 else
286 {
288 }
289
291 }
292}
293
294void QgsContrastEnhancement::toSld( QDomDocument &doc, QDomElement &element ) const
295{
296 if ( doc.isNull() || element.isNull() )
297 return;
298
299 QString algName;
301 {
303 algName = QStringLiteral( "StretchToMinimumMaximum" );
304 break;
305 /* TODO: check if ClipToZero => StretchAndClipToMinimumMaximum
306 * because value outside min/max ar considered as NoData instead of 0 */
308 algName = QStringLiteral( "ClipToMinimumMaximum" );
309 break;
311 algName = QStringLiteral( "ClipToMinimumMaximum" );
312 break;
313 case NoEnhancement:
314 return;
317 QgsDebugMsg( QObject::tr( "No SLD1.0 conversion yet for stretch algorithm %1" ).arg( algName ) );
318 return;
319 }
320
321 // Only <Normalize> is supported
322 // minValue and maxValue are that values as set depending on "Min /Max value settings"
323 // parameters
324 QDomElement normalizeElem = doc.createElement( QStringLiteral( "sld:Normalize" ) );
325 element.appendChild( normalizeElem );
326
327 QDomElement vendorOptionAlgorithmElem = doc.createElement( QStringLiteral( "sld:VendorOption" ) );
328 vendorOptionAlgorithmElem.setAttribute( QStringLiteral( "name" ), QStringLiteral( "algorithm" ) );
329 vendorOptionAlgorithmElem.appendChild( doc.createTextNode( algName ) );
330 normalizeElem.appendChild( vendorOptionAlgorithmElem );
331
332 QDomElement vendorOptionMinValueElem = doc.createElement( QStringLiteral( "sld:VendorOption" ) );
333 vendorOptionMinValueElem.setAttribute( QStringLiteral( "name" ), QStringLiteral( "minValue" ) );
334 vendorOptionMinValueElem.appendChild( doc.createTextNode( QString::number( minimumValue() ) ) );
335 normalizeElem.appendChild( vendorOptionMinValueElem );
336
337 QDomElement vendorOptionMaxValueElem = doc.createElement( QStringLiteral( "sld:VendorOption" ) );
338 vendorOptionMaxValueElem.setAttribute( QStringLiteral( "name" ), QStringLiteral( "maxValue" ) );
339 vendorOptionMaxValueElem.appendChild( doc.createTextNode( QString::number( maximumValue() ) ) );
340 normalizeElem.appendChild( vendorOptionMaxValueElem );
341}
342
344{
345 switch ( algorithm )
346 {
347 case NoEnhancement:
348 return QStringLiteral( "NoEnhancement" );
350 return QStringLiteral( "StretchToMinimumMaximum" );
352 return QStringLiteral( "StretchAndClipToMinimumMaximum" );
354 return QStringLiteral( "ClipToMinimumMaximum" );
356 return QStringLiteral( "UserDefinedEnhancement" );
357 }
358 return QStringLiteral( "NoEnhancement" );
359}
360
362{
363 if ( contrastEnhancementString == QLatin1String( "StretchToMinimumMaximum" ) )
364 {
366 }
367 else if ( contrastEnhancementString == QLatin1String( "StretchAndClipToMinimumMaximum" ) )
368 {
370 }
371 else if ( contrastEnhancementString == QLatin1String( "ClipToMinimumMaximum" ) )
372 {
374 }
375 else if ( contrastEnhancementString == QLatin1String( "UserDefinedEnhancement" ) )
376 {
378 }
379 else
380 {
381 return NoEnhancement;
382 }
383}
DataType
Raster data types.
Definition: qgis.h:129
@ Int16
Sixteen bit signed integer (qint16)
@ UInt16
Sixteen bit unsigned integer (quint16)
@ Byte
Eight bit unsigned integer (quint8)
A raster contrast enhancement that will clip a value to the specified min/max range.
A contrast enhancement function is the base class for all raster contrast enhancements.
Manipulates raster or point cloud pixel values so that they enhanceContrast or clip into a specified ...
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.
A linear enhanceContrast enhancement that first clips to min max and then enhanceContrastes linearly ...
A color enhancement function that performs a linear enhanceContrast between min and max.
static QString printValue(double value)
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:39
#define QgsDebugMsg(str)
Definition: qgslogger.h:38