QGIS API Documentation  2.99.0-Master (314842d)
qgscontrastenhancement.cpp
Go to the documentation of this file.
1 /* **************************************************************************
2  qgscontrastenhancement.cpp - description
3  -------------------
4 begin : Mon Oct 22 2007
5 copyright : (C) 2007 by Peter J. Ersts
6 email : [email protected]
7 
8 This class contains code that was originally part of the larger QgsRasterLayer
9 class 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 
23 #include "qgscontrastenhancement.h"
28 #include "qgsrasterblock.h"
29 #include <QDomDocument>
30 #include <QDomElement>
31 
33  : mContrastEnhancementAlgorithm( NoEnhancement )
34  , mEnhancementDirty( false )
35  , mLookupTable( nullptr )
36  , mRasterDataType( dataType )
37 {
38  mMinimumValue = minimumValuePossible( mRasterDataType );
39  mMaximumValue = maximumValuePossible( mRasterDataType );
40  mRasterDataTypeRange = mMaximumValue - mMinimumValue;
41 
42  mLookupTableOffset = mMinimumValue * -1;
43 
44  mContrastEnhancementFunction.reset( new QgsContrastEnhancementFunction( mRasterDataType, mMinimumValue, mMaximumValue ) );
45 
46  //If the data type is larger than 16-bit do not generate a lookup table
47  if ( mRasterDataTypeRange <= 65535.0 )
48  {
49  mLookupTable = new int[static_cast <int>( mRasterDataTypeRange + 1 )];
50  }
51 
52 }
53 
55  : mEnhancementDirty( true )
56  , mLookupTable( nullptr )
57  , mMinimumValue( ce.mMinimumValue )
58  , mMaximumValue( ce.mMaximumValue )
59  , mRasterDataType( ce.mRasterDataType )
60  , mRasterDataTypeRange( ce.mRasterDataTypeRange )
61 {
62  mLookupTableOffset = minimumValuePossible( mRasterDataType ) * -1;
63 
64  // setContrastEnhancementAlgorithm sets also QgsContrastEnhancementFunction
65  setContrastEnhancementAlgorithm( ce.mContrastEnhancementAlgorithm, false );
66 
67  //If the data type is larger than 16-bit do not generate a lookup table
68  if ( mRasterDataTypeRange <= 65535.0 )
69  {
70  mLookupTable = new int[static_cast <int>( mRasterDataTypeRange + 1 )];
71  }
72 }
73 
75 {
76  delete [] mLookupTable;
77 }
78 /*
79  *
80  * Static methods
81  *
82  */
83 
88 {
89  switch ( dataType )
90  {
91  case Qgis::Byte:
93  case Qgis::UInt16:
95  case Qgis::Int16:
97  case Qgis::UInt32:
99  case Qgis::Int32:
101  case Qgis::Float32:
103  case Qgis::Float64:
105  case Qgis::CInt16:
107  case Qgis::CInt32:
109  case Qgis::CFloat32:
111  case Qgis::CFloat64:
113  case Qgis::ARGB32:
116  // XXX - mloskot: not handled?
117  break;
118  }
119 
121 }
122 
127 {
128  switch ( dataType )
129  {
130  case Qgis::Byte:
132  case Qgis::UInt16:
134  case Qgis::Int16:
136  case Qgis::UInt32:
138  case Qgis::Int32:
140  case Qgis::Float32:
141  return std::numeric_limits<float>::max() * -1.0;
142  case Qgis::Float64:
143  return std::numeric_limits<double>::max() * -1.0;
144  case Qgis::CInt16:
146  case Qgis::CInt32:
148  case Qgis::CFloat32:
149  return std::numeric_limits<float>::max() * -1.0;
150  case Qgis::CFloat64:
151  return std::numeric_limits<double>::max() * -1.0;
152  case Qgis::ARGB32:
155  // XXX - mloskot: not handled?
156  break;
157  }
158 
159  return std::numeric_limits<double>::max() * -1.0;
160 }
161 
162 /*
163  *
164  * Non-Static methods
165  *
166  */
167 
174 {
175  if ( mEnhancementDirty )
176  {
177  generateLookupTable();
178  }
179 
180  if ( mLookupTable && NoEnhancement != mContrastEnhancementAlgorithm )
181  {
182  return mLookupTable[static_cast <int>( value + mLookupTableOffset )];
183  }
184  else
185  {
186  // Even if the contrast enhancement algorithms is set to NoEnhancement
187  // The input values will still have to be scaled for all data types
188  // greater than 1 byte.
189  return mContrastEnhancementFunction->enhance( value );
190  }
191 }
192 
196 bool QgsContrastEnhancement::generateLookupTable()
197 {
198  mEnhancementDirty = false;
199 
200  if ( !mContrastEnhancementFunction )
201  return false;
202  if ( NoEnhancement == mContrastEnhancementAlgorithm )
203  return false;
204  if ( Qgis::Byte != mRasterDataType && Qgis::UInt16 != mRasterDataType && Qgis::Int16 != mRasterDataType )
205  return false;
206  if ( !mLookupTable )
207  return false;
208 
209  QgsDebugMsg( "building lookup table" );
210  QgsDebugMsg( "***MinimumValue : " + QString::number( mMinimumValue ) );
211  QgsDebugMsg( "***MaximumValue : " + QString::number( mMaximumValue ) );
212  QgsDebugMsg( "***mLookupTableOffset : " + QString::number( mLookupTableOffset ) );
213  QgsDebugMsg( "***mRasterDataTypeRange : " + QString::number( mRasterDataTypeRange ) );
214 
215  for ( int myIterator = 0; myIterator <= mRasterDataTypeRange; myIterator++ )
216  {
217  mLookupTable[myIterator] = mContrastEnhancementFunction->enhance( static_cast< double >( myIterator ) - mLookupTableOffset );
218  }
219 
220  return true;
221 }
222 
229 {
230  if ( mContrastEnhancementFunction )
231  {
232  return mContrastEnhancementFunction->isValueInDisplayableRange( value );
233  }
234 
235  return false;
236 }
237 
245 {
246  switch ( algorithm )
247  {
249  mContrastEnhancementFunction.reset( new QgsLinearMinMaxEnhancement( mRasterDataType, mMinimumValue, mMaximumValue ) );
250  break;
252  mContrastEnhancementFunction.reset( new QgsLinearMinMaxEnhancementWithClip( mRasterDataType, mMinimumValue, mMaximumValue ) );
253  break;
254  case ClipToMinimumMaximum :
255  mContrastEnhancementFunction.reset( new QgsClipToMinMaxEnhancement( mRasterDataType, mMinimumValue, mMaximumValue ) );
256  break;
258  //Do nothing
259  break;
260  default:
261  mContrastEnhancementFunction.reset( new QgsContrastEnhancementFunction( mRasterDataType, mMinimumValue, mMaximumValue ) );
262  break;
263  }
264 
265  mEnhancementDirty = true;
266  mContrastEnhancementAlgorithm = algorithm;
267 
268  if ( generateTable )
269  {
270  generateLookupTable();
271  }
272 }
273 
280 {
281  QgsDebugMsgLevel( "called", 4 );
282 
283  if ( function )
284  {
285  mContrastEnhancementFunction.reset( function );
286  mContrastEnhancementAlgorithm = UserDefinedEnhancement;
287  generateLookupTable();
288  }
289 }
290 
297 void QgsContrastEnhancement::setMaximumValue( double value, bool generateTable )
298 {
299  QgsDebugMsgLevel( "called value: " + QString::number( value ) + " generate lookup table: " + QString::number( static_cast< int >( generateTable ) ), 4 );
300 
301  if ( value > maximumValuePossible( mRasterDataType ) )
302  {
303  mMaximumValue = maximumValuePossible( mRasterDataType );
304  }
305  else
306  {
307  mMaximumValue = value;
308  }
309 
310  if ( mContrastEnhancementFunction )
311  {
312  mContrastEnhancementFunction->setMaximumValue( value );
313  }
314 
315  mEnhancementDirty = true;
316 
317  if ( generateTable )
318  {
319  generateLookupTable();
320  }
321 }
322 
329 void QgsContrastEnhancement::setMinimumValue( double value, bool generateTable )
330 {
331  QgsDebugMsgLevel( "called value: " + QString::number( value ) + " generate lookup table: " + QString::number( static_cast< int >( generateTable ) ), 4 );
332 
333  if ( value < minimumValuePossible( mRasterDataType ) )
334  {
335  mMinimumValue = minimumValuePossible( mRasterDataType );
336  }
337  else
338  {
339  mMinimumValue = value;
340  }
341 
342  if ( mContrastEnhancementFunction )
343  {
344  mContrastEnhancementFunction->setMinimumValue( value );
345  }
346 
347  mEnhancementDirty = true;
348 
349  if ( generateTable )
350  {
351  generateLookupTable();
352  }
353 }
354 
355 void QgsContrastEnhancement::writeXml( QDomDocument &doc, QDomElement &parentElem ) const
356 {
357  //minimum value
358  QDomElement minElem = doc.createElement( QStringLiteral( "minValue" ) );
359  QDomText minText = doc.createTextNode( QgsRasterBlock::printValue( mMinimumValue ) );
360  minElem.appendChild( minText );
361  parentElem.appendChild( minElem );
362 
363  //maximum value
364  QDomElement maxElem = doc.createElement( QStringLiteral( "maxValue" ) );
365  QDomText maxText = doc.createTextNode( QgsRasterBlock::printValue( mMaximumValue ) );
366  maxElem.appendChild( maxText );
367  parentElem.appendChild( maxElem );
368 
369  //algorithm
370  QDomElement algorithmElem = doc.createElement( QStringLiteral( "algorithm" ) );
371  QDomText algorithmText = doc.createTextNode( contrastEnhancementAlgorithmString( mContrastEnhancementAlgorithm ) );
372  algorithmElem.appendChild( algorithmText );
373  parentElem.appendChild( algorithmElem );
374 }
375 
376 void QgsContrastEnhancement::readXml( const QDomElement &elem )
377 {
378  QDomElement minValueElem = elem.firstChildElement( QStringLiteral( "minValue" ) );
379  if ( !minValueElem.isNull() )
380  {
381  mMinimumValue = minValueElem.text().toDouble();
382  }
383  QDomElement maxValueElem = elem.firstChildElement( QStringLiteral( "maxValue" ) );
384  if ( !maxValueElem.isNull() )
385  {
386  mMaximumValue = maxValueElem.text().toDouble();
387  }
388  QDomElement algorithmElem = elem.firstChildElement( QStringLiteral( "algorithm" ) );
389  if ( !algorithmElem.isNull() )
390  {
391  QString algorithmString = algorithmElem.text();
393  // old version ( < 19 Apr 2013) was using enum directly -> for backward compatibility
394  if ( algorithmString == QLatin1String( "0" ) )
395  {
396  algorithm = NoEnhancement;
397  }
398  else if ( algorithmString == QLatin1String( "1" ) )
399  {
400  algorithm = StretchToMinimumMaximum;
401  }
402  else if ( algorithmString == QLatin1String( "2" ) )
403  {
404  algorithm = StretchAndClipToMinimumMaximum;
405  }
406  else if ( algorithmString == QLatin1String( "3" ) )
407  {
408  algorithm = ClipToMinimumMaximum;
409  }
410  else if ( algorithmString == QLatin1String( "4" ) )
411  {
412  algorithm = UserDefinedEnhancement;
413  }
414  else
415  {
416  algorithm = contrastEnhancementAlgorithmFromString( algorithmString );
417  }
418 
419  setContrastEnhancementAlgorithm( algorithm );
420  }
421 }
422 
424 {
425  switch ( algorithm )
426  {
427  case NoEnhancement:
428  return QStringLiteral( "NoEnhancement" );
430  return QStringLiteral( "StretchToMinimumMaximum" );
432  return QStringLiteral( "StretchAndClipToMinimumMaximum" );
434  return QStringLiteral( "ClipToMinimumMaximum" );
436  return QStringLiteral( "UserDefinedEnhancement" );
437  }
438  return QStringLiteral( "NoEnhancement" );
439 }
440 
442 {
443  if ( contrastEnhancementString == QLatin1String( "StretchToMinimumMaximum" ) )
444  {
446  }
447  else if ( contrastEnhancementString == QLatin1String( "StretchAndClipToMinimumMaximum" ) )
448  {
450  }
451  else if ( contrastEnhancementString == QLatin1String( "ClipToMinimumMaximum" ) )
452  {
453  return ClipToMinimumMaximum;
454  }
455  else if ( contrastEnhancementString == QLatin1String( "UserDefinedEnhancement" ) )
456  {
457  return UserDefinedEnhancement;
458  }
459  else
460  {
461  return NoEnhancement;
462  }
463 }
void setContrastEnhancementAlgorithm(ContrastEnhancementAlgorithm, bool generateTable=true)
Set the contrast enhancement algorithm.
Thirty two bit signed integer (qint32)
Definition: qgis.h:68
static QString printValue(double value)
Print double value with all necessary significant digits.
static double minimumValuePossible(Qgis::DataType)
Helper function that returns the minimum possible value for a GDAL data type.
#define QgsDebugMsg(str)
Definition: qgslogger.h:36
bool isValueInDisplayableRange(double)
Return true if pixel is in stretable range, false if pixel is outside of range (i.e., clipped)
Thirty two bit unsigned integer (quint32)
Definition: qgis.h:67
DataType
Raster data types.
Definition: qgis.h:61
Thirty two bit floating point (float)
Definition: qgis.h:69
Sixteen bit signed integer (qint16)
Definition: qgis.h:66
Complex Int16.
Definition: qgis.h:71
Sixty four bit floating point (double)
Definition: qgis.h:70
void setContrastEnhancementFunction(QgsContrastEnhancementFunction *)
A public method that allows the user to set their own custom contrast enhancement function...
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32_Premultiplied.
Definition: qgis.h:76
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:37
A linear enhanceContrast enhancement that first clips to min max and then enhanceContrastes linearly ...
Complex Float32.
Definition: qgis.h:73
void setMinimumValue(double, bool generateTable=true)
Return the minimum value for the contrast enhancement range.
static QString contrastEnhancementAlgorithmString(ContrastEnhancementAlgorithm algorithm)
Return a string to serialize ContrastEnhancementAlgorithm.
void readXml(const QDomElement &elem)
Unknown or unspecified type.
Definition: qgis.h:63
Complex Int32.
Definition: qgis.h:72
A contrast enhancement function is the base class for all raster contrast enhancements.
Sixteen bit unsigned integer (quint16)
Definition: qgis.h:65
A color enhancement function that performs a linear enhanceContrast between min and max...
double ANALYSIS_EXPORT min(double x, double y)
Returns the minimum of two doubles or the first argument if both are equal.
Definition: MathUtils.cc:452
double ANALYSIS_EXPORT max(double x, double y)
Returns the maximum of two doubles or the first argument if both are equal.
Definition: MathUtils.cc:437
static ContrastEnhancementAlgorithm contrastEnhancementAlgorithmFromString(const QString &contrastEnhancementString)
Deserialize ContrastEnhancementAlgorithm.
ContrastEnhancementAlgorithm
This enumerator describes the types of contrast enhancement algorithms that can be used...
A raster contrast enhancement that will clip a value to the specified min/max range.
int enhanceContrast(double)
Apply the contrast enhancement to a value. Return values are 0 - 254, -1 means the pixel was clipped ...
static double maximumValuePossible(Qgis::DataType)
Helper function that returns the maximum possible value for a GDAL data type.
void writeXml(QDomDocument &doc, QDomElement &parentElem) const
Manipulates raster pixel values so that they enhanceContrast or clip into a specified numerical range...
Complex Float64.
Definition: qgis.h:74
QgsContrastEnhancement(Qgis::DataType datatype=Qgis::Byte)
void setMaximumValue(double, bool generateTable=true)
Set the maximum value for the contrast enhancement range.
Eight bit unsigned integer (quint8)
Definition: qgis.h:64
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32.
Definition: qgis.h:75