QGIS API Documentation  2.18.21-Las Palmas (9fba24a)
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  , mContrastEnhancementFunction( nullptr )
35  , mEnhancementDirty( false )
36  , mLookupTable( nullptr )
37  , mRasterDataType( theDataType )
38 {
39  mMinimumValue = minimumValuePossible( mRasterDataType );
40  mMaximumValue = maximumValuePossible( mRasterDataType );
41  mRasterDataTypeRange = mMaximumValue - mMinimumValue;
42 
43  mLookupTableOffset = mMinimumValue * -1;
44 
45  mContrastEnhancementFunction = new 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 = new int[static_cast <int>( mRasterDataTypeRange+1 )];
51  }
52 
53 }
54 
56  : mContrastEnhancementFunction( nullptr )
57  , mEnhancementDirty( true )
58  , mLookupTable( nullptr )
59  , mMinimumValue( ce.mMinimumValue )
60  , mMaximumValue( ce.mMaximumValue )
61  , mRasterDataType( ce.mRasterDataType )
62  , mRasterDataTypeRange( ce.mRasterDataTypeRange )
63 {
64  mLookupTableOffset = minimumValuePossible( mRasterDataType ) * -1;
65 
66  // setContrastEnhancementAlgorithm sets also QgsContrastEnhancementFunction
67  setContrastEnhancementAlgorithm( ce.mContrastEnhancementAlgorithm, false );
68 
69  //If the data type is larger than 16-bit do not generate a lookup table
70  if ( mRasterDataTypeRange <= 65535.0 )
71  {
72  mLookupTable = new int[static_cast <int>( mRasterDataTypeRange+1 )];
73  }
74 }
75 
77 {
78  delete [] mLookupTable;
79  delete mContrastEnhancementFunction;
80 }
81 /*
82  *
83  * Static methods
84  *
85  */
86 
91 {
92  switch ( theDataType )
93  {
94  case QGis::Byte:
96  case QGis::UInt16:
98  case QGis::Int16:
100  case QGis::UInt32:
102  case QGis::Int32:
104  case QGis::Float32:
106  case QGis::Float64:
108  case QGis::CInt16:
110  case QGis::CInt32:
112  case QGis::CFloat32:
114  case QGis::CFloat64:
116  case QGis::ARGB32:
119  // XXX - mloskot: not handled?
120  break;
121  }
122 
124 }
129 {
130  switch ( theDataType )
131  {
132  case QGis::Byte:
134  case QGis::UInt16:
136  case QGis::Int16:
138  case QGis::UInt32:
140  case QGis::Int32:
142  case QGis::Float32:
143  return std::numeric_limits<float>::max() * -1.0;
144  case QGis::Float64:
145  return std::numeric_limits<double>::max() * -1.0;
146  case QGis::CInt16:
148  case QGis::CInt32:
150  case QGis::CFloat32:
151  return std::numeric_limits<float>::max() * -1.0;
152  case QGis::CFloat64:
153  return std::numeric_limits<double>::max() * -1.0;
154  case QGis::ARGB32:
157  // XXX - mloskot: not handled?
158  break;
159  }
160 
161  return std::numeric_limits<double>::max() * -1.0;
162 }
163 
164 /*
165  *
166  * Non-Static methods
167  *
168  */
175 {
176  if ( mEnhancementDirty )
177  {
178  generateLookupTable();
179  }
180 
181  if ( mLookupTable && NoEnhancement != mContrastEnhancementAlgorithm )
182  {
183  double shiftedValue = theValue + mLookupTableOffset;
184  if ( shiftedValue >= 0 && shiftedValue < mRasterDataTypeRange + 1 )
185  return mLookupTable[static_cast <int>( shiftedValue )];
186  return 0;
187  }
188  else
189  {
190  // Even if the contrast enhancement algorithms is set to NoEnhancement
191  // The input values will still have to be scaled for all data types
192  // greater than 1 byte.
193  return mContrastEnhancementFunction->enhance( theValue );
194  }
195 }
196 
200 bool QgsContrastEnhancement::generateLookupTable()
201 {
202  mEnhancementDirty = false;
203 
204  if ( !mContrastEnhancementFunction )
205  return false;
206  if ( NoEnhancement == mContrastEnhancementAlgorithm )
207  return false;
208  if ( QGis::Byte != mRasterDataType && QGis::UInt16 != mRasterDataType && QGis::Int16 != mRasterDataType )
209  return false;
210  if ( !mLookupTable )
211  return false;
212 
213  QgsDebugMsg( "building lookup table" );
214  QgsDebugMsg( "***MinimumValue : " + QString::number( mMinimumValue ) );
215  QgsDebugMsg( "***MaximumValue : " + QString::number( mMaximumValue ) );
216  QgsDebugMsg( "***mLookupTableOffset : " + QString::number( mLookupTableOffset ) );
217  QgsDebugMsg( "***mRasterDataTypeRange : " + QString::number( mRasterDataTypeRange ) );
218 
219  for ( int myIterator = 0; myIterator <= mRasterDataTypeRange; myIterator++ )
220  {
221  mLookupTable[myIterator] = mContrastEnhancementFunction->enhance( static_cast< double >( myIterator ) - mLookupTableOffset );
222  }
223 
224  return true;
225 }
226 
233 {
234  if ( mContrastEnhancementFunction )
235  {
236  return mContrastEnhancementFunction->isValueInDisplayableRange( theValue );
237  }
238 
239  return false;
240 }
241 
249 {
250  switch ( theAlgorithm )
251  {
253  delete mContrastEnhancementFunction;
254  mContrastEnhancementFunction = new QgsLinearMinMaxEnhancement( mRasterDataType, mMinimumValue, mMaximumValue );
255  break;
257  delete mContrastEnhancementFunction;
258  mContrastEnhancementFunction = new QgsLinearMinMaxEnhancementWithClip( mRasterDataType, mMinimumValue, mMaximumValue );
259  break;
260  case ClipToMinimumMaximum :
261  delete mContrastEnhancementFunction;
262  mContrastEnhancementFunction = new QgsClipToMinMaxEnhancement( mRasterDataType, mMinimumValue, mMaximumValue );
263  break;
265  //Do nothing
266  break;
267  default:
268  delete mContrastEnhancementFunction;
269  mContrastEnhancementFunction = new QgsContrastEnhancementFunction( mRasterDataType, mMinimumValue, mMaximumValue );
270  break;
271  }
272 
273  mEnhancementDirty = true;
274  mContrastEnhancementAlgorithm = theAlgorithm;
275 
276  if ( generateTable )
277  {
278  generateLookupTable();
279  }
280 }
281 
288 {
289  QgsDebugMsgLevel( "called", 4 );
290 
291  if ( theFunction )
292  {
293  delete mContrastEnhancementFunction;
294  mContrastEnhancementFunction = theFunction;
295  mContrastEnhancementAlgorithm = UserDefinedEnhancement;
296  generateLookupTable();
297  }
298 }
299 
306 void QgsContrastEnhancement::setMaximumValue( double theValue, bool generateTable )
307 {
308  QgsDebugMsgLevel( "called value: " + QString::number( theValue ) + " generate lookup table: " + QString::number( static_cast< int >( generateTable ) ), 4 );
309 
310  if ( theValue > maximumValuePossible( mRasterDataType ) )
311  {
312  mMaximumValue = maximumValuePossible( mRasterDataType );
313  }
314  else
315  {
316  mMaximumValue = theValue;
317  }
318 
319  if ( mContrastEnhancementFunction )
320  {
321  mContrastEnhancementFunction->setMaximumValue( theValue );
322  }
323 
324  mEnhancementDirty = true;
325 
326  if ( generateTable )
327  {
328  generateLookupTable();
329  }
330 }
331 
338 void QgsContrastEnhancement::setMinimumValue( double theValue, bool generateTable )
339 {
340  QgsDebugMsgLevel( "called value: " + QString::number( theValue ) + " generate lookup table: " + QString::number( static_cast< int >( generateTable ) ), 4 );
341 
342  if ( theValue < minimumValuePossible( mRasterDataType ) )
343  {
344  mMinimumValue = minimumValuePossible( mRasterDataType );
345  }
346  else
347  {
348  mMinimumValue = theValue;
349  }
350 
351  if ( mContrastEnhancementFunction )
352  {
353  mContrastEnhancementFunction->setMinimumValue( theValue );
354  }
355 
356  mEnhancementDirty = true;
357 
358  if ( generateTable )
359  {
360  generateLookupTable();
361  }
362 }
363 
365 {
366  //minimum value
367  QDomElement minElem = doc.createElement( "minValue" );
368  QDomText minText = doc.createTextNode( QgsRasterBlock::printValue( mMinimumValue ) );
369  minElem.appendChild( minText );
370  parentElem.appendChild( minElem );
371 
372  //maximum value
373  QDomElement maxElem = doc.createElement( "maxValue" );
374  QDomText maxText = doc.createTextNode( QgsRasterBlock::printValue( mMaximumValue ) );
375  maxElem.appendChild( maxText );
376  parentElem.appendChild( maxElem );
377 
378  //algorithm
379  QDomElement algorithmElem = doc.createElement( "algorithm" );
380  QDomText algorithmText = doc.createTextNode( contrastEnhancementAlgorithmString( mContrastEnhancementAlgorithm ) );
381  algorithmElem.appendChild( algorithmText );
382  parentElem.appendChild( algorithmElem );
383 }
384 
386 {
387  QDomElement minValueElem = elem.firstChildElement( "minValue" );
388  if ( !minValueElem.isNull() )
389  {
390  mMinimumValue = minValueElem.text().toDouble();
391  }
392  QDomElement maxValueElem = elem.firstChildElement( "maxValue" );
393  if ( !maxValueElem.isNull() )
394  {
395  mMaximumValue = maxValueElem.text().toDouble();
396  }
397  QDomElement algorithmElem = elem.firstChildElement( "algorithm" );
398  if ( !algorithmElem.isNull() )
399  {
400  QString algorithmString = algorithmElem.text();
402  // old version ( < 19 Apr 2013) was using enum directly -> for backward compatibility
403  if ( algorithmString == "0" )
404  {
405  algorithm = NoEnhancement;
406  }
407  else if ( algorithmString == "1" )
408  {
409  algorithm = StretchToMinimumMaximum;
410  }
411  else if ( algorithmString == "2" )
412  {
413  algorithm = StretchAndClipToMinimumMaximum;
414  }
415  else if ( algorithmString == "3" )
416  {
417  algorithm = ClipToMinimumMaximum;
418  }
419  else if ( algorithmString == "4" )
420  {
421  algorithm = UserDefinedEnhancement;
422  }
423  else
424  {
425  algorithm = contrastEnhancementAlgorithmFromString( algorithmString );
426  }
427 
428  setContrastEnhancementAlgorithm( algorithm );
429  }
430 }
431 
433 {
434  switch ( algorithm )
435  {
436  case NoEnhancement:
437  return "NoEnhancement";
439  return "StretchToMinimumMaximum";
441  return "StretchAndClipToMinimumMaximum";
443  return "ClipToMinimumMaximum";
445  return "UserDefinedEnhancement";
446  }
447  return "NoEnhancement";
448 }
449 
451 {
452  if ( contrastEnhancementString == "StretchToMinimumMaximum" )
453  {
455  }
456  else if ( contrastEnhancementString == "StretchAndClipToMinimumMaximum" )
457  {
459  }
460  else if ( contrastEnhancementString == "ClipToMinimumMaximum" )
461  {
462  return ClipToMinimumMaximum;
463  }
464  else if ( contrastEnhancementString == "UserDefinedEnhancement" )
465  {
466  return UserDefinedEnhancement;
467  }
468  else
469  {
470  return NoEnhancement;
471  }
472 }
Eight bit unsigned integer (quint8)
Definition: qgis.h:136
void setContrastEnhancementAlgorithm(ContrastEnhancementAlgorithm, bool generateTable=true)
Set the contrast enhancement algorithm.
void writeXML(QDomDocument &doc, QDomElement &parentElem) const
static QString printValue(double value)
Print double value with all necessary significant digits.
Unknown or unspecified type.
Definition: qgis.h:135
void readXML(const QDomElement &elem)
Complex Float32.
Definition: qgis.h:145
QDomNode appendChild(const QDomNode &newChild)
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
bool isValueInDisplayableRange(double)
Return true if pixel is in stretable range, false if pixel is outside of range (i.e., clipped)
Complex Int32.
Definition: qgis.h:144
Thirty two bit floating point (float)
Definition: qgis.h:141
static double maximumValuePossible(QGis::DataType)
Helper function that returns the maximum possible value for a GDAL data type.
double toDouble(bool *ok) const
double ANALYSIS_EXPORT max(double x, double y)
Returns the maximum of two doubles or the first argument if both are equal.
void setContrastEnhancementFunction(QgsContrastEnhancementFunction *)
A public method that allows the user to set their own custom contrast enhancment function.
void setMinimumValue(double)
Mutator for the minimum value.
QString number(int n, int base)
static double minimumValuePossible(QGis::DataType)
Helper function that returns the minimum possible value for a GDAL data type.
Sixteen bit unsigned integer (quint16)
Definition: qgis.h:137
Sixty four bit floating point (double)
Definition: qgis.h:142
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32_Premultiplied.
Definition: qgis.h:150
QString text() const
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:34
Thirty two bit signed integer (qint32)
Definition: qgis.h:140
A linear enhanceContrast enhancement that first clips to min max and then enhanceContrastes linearly ...
void setMinimumValue(double, bool generateTable=true)
Return the minimum value for the contrast enhancement range.
Thirty two bit unsigned integer (quint32)
Definition: qgis.h:139
static QString contrastEnhancementAlgorithmString(ContrastEnhancementAlgorithm algorithm)
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32.
Definition: qgis.h:148
A contrast enhancement funcion is the base class for all raster contrast enhancements.
A color enhancement function that performs a linear enhanceContrast between min and max...
Sixteen bit signed integer (qint16)
Definition: qgis.h:138
QDomText createTextNode(const QString &value)
QgsContrastEnhancement(QGis::DataType theDatatype=QGis::Byte)
static ContrastEnhancementAlgorithm contrastEnhancementAlgorithmFromString(const QString &contrastEnhancementString)
bool isNull() const
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.
QDomElement firstChildElement(const QString &tagName) const
DataType
Raster data types.
Definition: qgis.h:133
virtual int enhance(double)
A customizable method that takes in a double and returns a int between 0 and 255. ...
virtual bool isValueInDisplayableRange(double)
A customicable method to indicate if the pixels is displayable.
Manipulates raster pixel values so that they enhanceContrast or clip into a specified numerical range...
double ANALYSIS_EXPORT min(double x, double y)
Returns the minimum of two doubles or the first argument if both are equal.
QDomElement createElement(const QString &tagName)
Complex Int16.
Definition: qgis.h:143
void setMaximumValue(double, bool generateTable=true)
Set the maximum value for the contrast enhancement range.
void setMaximumValue(double)
Mustator for the maximum value.
Complex Float64.
Definition: qgis.h:146