QGIS API Documentation  2.99.0-Master (9fdd060)
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  : mRasterDataType( dataType )
34 {
35  mMinimumValue = minimumValuePossible( mRasterDataType );
36  mMaximumValue = maximumValuePossible( mRasterDataType );
37  mRasterDataTypeRange = mMaximumValue - mMinimumValue;
38 
39  mLookupTableOffset = mMinimumValue * -1;
40 
41  mContrastEnhancementFunction.reset( new QgsContrastEnhancementFunction( mRasterDataType, mMinimumValue, mMaximumValue ) );
42 
43  //If the data type is larger than 16-bit do not generate a lookup table
44  if ( mRasterDataTypeRange <= 65535.0 )
45  {
46  mLookupTable = new int[static_cast <int>( mRasterDataTypeRange + 1 )];
47  }
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 = new int[static_cast <int>( mRasterDataTypeRange + 1 )];
67  }
68 }
69 
71 {
72  delete [] mLookupTable;
73 }
74 /*
75  *
76  * Static methods
77  *
78  */
79 
84 {
85  switch ( dataType )
86  {
87  case Qgis::Byte:
88  return std::numeric_limits<unsigned char>::max();
89  case Qgis::UInt16:
90  return std::numeric_limits<unsigned short>::max();
91  case Qgis::Int16:
92  return std::numeric_limits<short>::max();
93  case Qgis::UInt32:
94  return std::numeric_limits<unsigned int>::max();
95  case Qgis::Int32:
96  return std::numeric_limits<int>::max();
97  case Qgis::Float32:
98  return std::numeric_limits<float>::max();
99  case Qgis::Float64:
100  return std::numeric_limits<double>::max();
101  case Qgis::CInt16:
102  return std::numeric_limits<short>::max();
103  case Qgis::CInt32:
104  return std::numeric_limits<int>::max();
105  case Qgis::CFloat32:
106  return std::numeric_limits<float>::max();
107  case Qgis::CFloat64:
108  return std::numeric_limits<double>::max();
109  case Qgis::ARGB32:
112  // XXX - mloskot: not handled?
113  break;
114  }
115 
116  return std::numeric_limits<double>::max();
117 }
118 
123 {
124  switch ( dataType )
125  {
126  case Qgis::Byte:
127  return std::numeric_limits<unsigned char>::min();
128  case Qgis::UInt16:
129  return std::numeric_limits<unsigned short>::min();
130  case Qgis::Int16:
131  return std::numeric_limits<short>::min();
132  case Qgis::UInt32:
133  return std::numeric_limits<unsigned int>::min();
134  case Qgis::Int32:
135  return std::numeric_limits<int>::min();
136  case Qgis::Float32:
137  return std::numeric_limits<float>::max() * -1.0;
138  case Qgis::Float64:
139  return std::numeric_limits<double>::max() * -1.0;
140  case Qgis::CInt16:
141  return std::numeric_limits<short>::min();
142  case Qgis::CInt32:
143  return std::numeric_limits<int>::min();
144  case Qgis::CFloat32:
145  return std::numeric_limits<float>::max() * -1.0;
146  case Qgis::CFloat64:
147  return std::numeric_limits<double>::max() * -1.0;
148  case Qgis::ARGB32:
151  // XXX - mloskot: not handled?
152  break;
153  }
154 
155  return std::numeric_limits<double>::max() * -1.0;
156 }
157 
158 /*
159  *
160  * Non-Static methods
161  *
162  */
163 
170 {
171  if ( mEnhancementDirty )
172  {
173  generateLookupTable();
174  }
175 
176  if ( mLookupTable && NoEnhancement != mContrastEnhancementAlgorithm )
177  {
178  return mLookupTable[static_cast <int>( value + mLookupTableOffset )];
179  }
180  else
181  {
182  // Even if the contrast enhancement algorithms is set to NoEnhancement
183  // The input values will still have to be scaled for all data types
184  // greater than 1 byte.
185  return mContrastEnhancementFunction->enhance( value );
186  }
187 }
188 
192 bool QgsContrastEnhancement::generateLookupTable()
193 {
194  mEnhancementDirty = false;
195 
196  if ( !mContrastEnhancementFunction )
197  return false;
198  if ( NoEnhancement == mContrastEnhancementAlgorithm )
199  return false;
200  if ( Qgis::Byte != mRasterDataType && Qgis::UInt16 != mRasterDataType && Qgis::Int16 != mRasterDataType )
201  return false;
202  if ( !mLookupTable )
203  return false;
204 
205  QgsDebugMsg( "building lookup table" );
206  QgsDebugMsg( "***MinimumValue : " + QString::number( mMinimumValue ) );
207  QgsDebugMsg( "***MaximumValue : " + QString::number( mMaximumValue ) );
208  QgsDebugMsg( "***mLookupTableOffset : " + QString::number( mLookupTableOffset ) );
209  QgsDebugMsg( "***mRasterDataTypeRange : " + QString::number( mRasterDataTypeRange ) );
210 
211  for ( int myIterator = 0; myIterator <= mRasterDataTypeRange; myIterator++ )
212  {
213  mLookupTable[myIterator] = mContrastEnhancementFunction->enhance( static_cast< double >( myIterator ) - mLookupTableOffset );
214  }
215 
216  return true;
217 }
218 
225 {
226  if ( mContrastEnhancementFunction )
227  {
228  return mContrastEnhancementFunction->isValueInDisplayableRange( value );
229  }
230 
231  return false;
232 }
233 
241 {
242  switch ( algorithm )
243  {
245  mContrastEnhancementFunction.reset( new QgsLinearMinMaxEnhancement( mRasterDataType, mMinimumValue, mMaximumValue ) );
246  break;
248  mContrastEnhancementFunction.reset( new QgsLinearMinMaxEnhancementWithClip( mRasterDataType, mMinimumValue, mMaximumValue ) );
249  break;
250  case ClipToMinimumMaximum :
251  mContrastEnhancementFunction.reset( new QgsClipToMinMaxEnhancement( mRasterDataType, mMinimumValue, mMaximumValue ) );
252  break;
254  //Do nothing
255  break;
256  default:
257  mContrastEnhancementFunction.reset( new QgsContrastEnhancementFunction( mRasterDataType, mMinimumValue, mMaximumValue ) );
258  break;
259  }
260 
261  mEnhancementDirty = true;
262  mContrastEnhancementAlgorithm = algorithm;
263 
264  if ( generateTable )
265  {
266  generateLookupTable();
267  }
268 }
269 
276 {
277  QgsDebugMsgLevel( "called", 4 );
278 
279  if ( function )
280  {
281  mContrastEnhancementFunction.reset( function );
282  mContrastEnhancementAlgorithm = UserDefinedEnhancement;
283  generateLookupTable();
284  }
285 }
286 
293 void QgsContrastEnhancement::setMaximumValue( double value, bool generateTable )
294 {
295  QgsDebugMsgLevel( "called value: " + QString::number( value ) + " generate lookup table: " + QString::number( static_cast< int >( generateTable ) ), 4 );
296 
297  if ( value > maximumValuePossible( mRasterDataType ) )
298  {
299  mMaximumValue = maximumValuePossible( mRasterDataType );
300  }
301  else
302  {
303  mMaximumValue = value;
304  }
305 
306  if ( mContrastEnhancementFunction )
307  {
308  mContrastEnhancementFunction->setMaximumValue( value );
309  }
310 
311  mEnhancementDirty = true;
312 
313  if ( generateTable )
314  {
315  generateLookupTable();
316  }
317 }
318 
325 void QgsContrastEnhancement::setMinimumValue( double value, bool generateTable )
326 {
327  QgsDebugMsgLevel( "called value: " + QString::number( value ) + " generate lookup table: " + QString::number( static_cast< int >( generateTable ) ), 4 );
328 
329  if ( value < minimumValuePossible( mRasterDataType ) )
330  {
331  mMinimumValue = minimumValuePossible( mRasterDataType );
332  }
333  else
334  {
335  mMinimumValue = value;
336  }
337 
338  if ( mContrastEnhancementFunction )
339  {
340  mContrastEnhancementFunction->setMinimumValue( value );
341  }
342 
343  mEnhancementDirty = true;
344 
345  if ( generateTable )
346  {
347  generateLookupTable();
348  }
349 }
350 
351 void QgsContrastEnhancement::writeXml( QDomDocument &doc, QDomElement &parentElem ) const
352 {
353  //minimum value
354  QDomElement minElem = doc.createElement( QStringLiteral( "minValue" ) );
355  QDomText minText = doc.createTextNode( QgsRasterBlock::printValue( mMinimumValue ) );
356  minElem.appendChild( minText );
357  parentElem.appendChild( minElem );
358 
359  //maximum value
360  QDomElement maxElem = doc.createElement( QStringLiteral( "maxValue" ) );
361  QDomText maxText = doc.createTextNode( QgsRasterBlock::printValue( mMaximumValue ) );
362  maxElem.appendChild( maxText );
363  parentElem.appendChild( maxElem );
364 
365  //algorithm
366  QDomElement algorithmElem = doc.createElement( QStringLiteral( "algorithm" ) );
367  QDomText algorithmText = doc.createTextNode( contrastEnhancementAlgorithmString( mContrastEnhancementAlgorithm ) );
368  algorithmElem.appendChild( algorithmText );
369  parentElem.appendChild( algorithmElem );
370 }
371 
372 void QgsContrastEnhancement::readXml( const QDomElement &elem )
373 {
374  QDomElement minValueElem = elem.firstChildElement( QStringLiteral( "minValue" ) );
375  if ( !minValueElem.isNull() )
376  {
377  mMinimumValue = minValueElem.text().toDouble();
378  }
379  QDomElement maxValueElem = elem.firstChildElement( QStringLiteral( "maxValue" ) );
380  if ( !maxValueElem.isNull() )
381  {
382  mMaximumValue = maxValueElem.text().toDouble();
383  }
384  QDomElement algorithmElem = elem.firstChildElement( QStringLiteral( "algorithm" ) );
385  if ( !algorithmElem.isNull() )
386  {
387  QString algorithmString = algorithmElem.text();
389  // old version ( < 19 Apr 2013) was using enum directly -> for backward compatibility
390  if ( algorithmString == QLatin1String( "0" ) )
391  {
392  algorithm = NoEnhancement;
393  }
394  else if ( algorithmString == QLatin1String( "1" ) )
395  {
396  algorithm = StretchToMinimumMaximum;
397  }
398  else if ( algorithmString == QLatin1String( "2" ) )
399  {
400  algorithm = StretchAndClipToMinimumMaximum;
401  }
402  else if ( algorithmString == QLatin1String( "3" ) )
403  {
404  algorithm = ClipToMinimumMaximum;
405  }
406  else if ( algorithmString == QLatin1String( "4" ) )
407  {
408  algorithm = UserDefinedEnhancement;
409  }
410  else
411  {
412  algorithm = contrastEnhancementAlgorithmFromString( algorithmString );
413  }
414 
415  setContrastEnhancementAlgorithm( algorithm );
416  }
417 }
418 
420 {
421  switch ( algorithm )
422  {
423  case NoEnhancement:
424  return QStringLiteral( "NoEnhancement" );
426  return QStringLiteral( "StretchToMinimumMaximum" );
428  return QStringLiteral( "StretchAndClipToMinimumMaximum" );
430  return QStringLiteral( "ClipToMinimumMaximum" );
432  return QStringLiteral( "UserDefinedEnhancement" );
433  }
434  return QStringLiteral( "NoEnhancement" );
435 }
436 
438 {
439  if ( contrastEnhancementString == QLatin1String( "StretchToMinimumMaximum" ) )
440  {
442  }
443  else if ( contrastEnhancementString == QLatin1String( "StretchAndClipToMinimumMaximum" ) )
444  {
446  }
447  else if ( contrastEnhancementString == QLatin1String( "ClipToMinimumMaximum" ) )
448  {
449  return ClipToMinimumMaximum;
450  }
451  else if ( contrastEnhancementString == QLatin1String( "UserDefinedEnhancement" ) )
452  {
453  return UserDefinedEnhancement;
454  }
455  else
456  {
457  return NoEnhancement;
458  }
459 }
void setContrastEnhancementAlgorithm(ContrastEnhancementAlgorithm, bool generateTable=true)
Set the contrast enhancement algorithm.
Thirty two bit signed integer (qint32)
Definition: qgis.h:85
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:37
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:84
DataType
Raster data types.
Definition: qgis.h:78
Thirty two bit floating point (float)
Definition: qgis.h:86
Sixteen bit signed integer (qint16)
Definition: qgis.h:83
Complex Int16.
Definition: qgis.h:88
Sixty four bit floating point (double)
Definition: qgis.h:87
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:93
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:38
A linear enhanceContrast enhancement that first clips to min max and then enhanceContrastes linearly ...
Complex Float32.
Definition: qgis.h:90
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:80
Complex Int32.
Definition: qgis.h:89
A contrast enhancement function is the base class for all raster contrast enhancements.
Sixteen bit unsigned integer (quint16)
Definition: qgis.h:82
A color enhancement function that performs a linear enhanceContrast between min and max...
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:91
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:81
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32.
Definition: qgis.h:92