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