QGIS API Documentation  2.11.0-Master
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 : ersts@amnh.org
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 <QDomDocument>
29 #include <QDomElement>
30 
32 {
33  mLookupTable = 0;
34  mContrastEnhancementFunction = 0;
35  mEnhancementDirty = false;
36  mContrastEnhancementAlgorithm = NoEnhancement;
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 {
57  mLookupTable = 0;
58  mContrastEnhancementFunction = 0;
59  mEnhancementDirty = true;
60  mRasterDataType = ce.mRasterDataType;
61 
62  mMinimumValue = ce.mMinimumValue;
63  mMaximumValue = ce.mMaximumValue;
64  mRasterDataTypeRange = ce.mRasterDataTypeRange;
65 
66  mLookupTableOffset = minimumValuePossible( mRasterDataType ) * -1;
67 
68  // setContrastEnhancementAlgorithm sets also QgsContrastEnhancementFunction
69  setContrastEnhancementAlgorithm( ce.mContrastEnhancementAlgorithm, false );
70 
71  //If the data type is larger than 16-bit do not generate a lookup table
72  if ( mRasterDataTypeRange <= 65535.0 )
73  {
74  mLookupTable = new int[static_cast <int>( mRasterDataTypeRange+1 )];
75  }
76 }
77 
79 {
80  delete [] mLookupTable;
81  delete mContrastEnhancementFunction;
82 }
83 /*
84  *
85  * Static methods
86  *
87  */
88 
93 {
94  switch ( theDataType )
95  {
96  case QGis::Byte:
98  break;
99  case QGis::UInt16:
101  break;
102  case QGis::Int16:
104  break;
105  case QGis::UInt32:
107  break;
108  case QGis::Int32:
110  break;
111  case QGis::Float32:
113  break;
114  case QGis::Float64:
116  break;
117  case QGis::CInt16:
119  break;
120  case QGis::CInt32:
122  break;
123  case QGis::CFloat32:
125  break;
126  case QGis::CFloat64:
128  break;
129  case QGis::ARGB32:
132  // XXX - mloskot: not handled?
133  break;
134  }
135 
137 }
142 {
143  switch ( theDataType )
144  {
145  case QGis::Byte:
147  break;
148  case QGis::UInt16:
150  break;
151  case QGis::Int16:
153  break;
154  case QGis::UInt32:
156  break;
157  case QGis::Int32:
159  break;
160  case QGis::Float32:
161  return std::numeric_limits<float>::max() * -1.0;
162  break;
163  case QGis::Float64:
164  return std::numeric_limits<double>::max() * -1.0;
165  break;
166  case QGis::CInt16:
168  break;
169  case QGis::CInt32:
171  break;
172  case QGis::CFloat32:
173  return std::numeric_limits<float>::max() * -1.0;
174  break;
175  case QGis::CFloat64:
176  return std::numeric_limits<double>::max() * -1.0;
177  break;
178  case QGis::ARGB32:
181  // XXX - mloskot: not handled?
182  break;
183  }
184 
185  return std::numeric_limits<double>::max() * -1.0;
186 }
187 
188 /*
189  *
190  * Non-Static methods
191  *
192  */
199 {
200  if ( mEnhancementDirty )
201  {
202  generateLookupTable();
203  }
204 
205  if ( mLookupTable && NoEnhancement != mContrastEnhancementAlgorithm )
206  {
207  return mLookupTable[static_cast <int>( theValue + mLookupTableOffset )];
208  }
209  else
210  {
211  // Even if the contrast enhancement algorithms is set to NoEnhancement
212  // The input values will still have to be scaled for all data types
213  // greater than 1 byte.
214  return mContrastEnhancementFunction->enhance( theValue );
215  }
216 }
217 
221 bool QgsContrastEnhancement::generateLookupTable()
222 {
223  mEnhancementDirty = false;
224 
225  if ( !mContrastEnhancementFunction )
226  return false;
227  if ( NoEnhancement == mContrastEnhancementAlgorithm )
228  return false;
229  if ( QGis::Byte != mRasterDataType && QGis::UInt16 != mRasterDataType && QGis::Int16 != mRasterDataType )
230  return false;
231  if ( !mLookupTable )
232  return false;
233 
234  QgsDebugMsg( "building lookup table" );
235  QgsDebugMsg( "***MinimumValue : " + QString::number( mMinimumValue ) );
236  QgsDebugMsg( "***MaximumValue : " + QString::number( mMaximumValue ) );
237  QgsDebugMsg( "***mLookupTableOffset : " + QString::number( mLookupTableOffset ) );
238  QgsDebugMsg( "***mRasterDataTypeRange : " + QString::number( mRasterDataTypeRange ) );
239 
240  for ( int myIterator = 0; myIterator <= mRasterDataTypeRange; myIterator++ )
241  {
242  mLookupTable[myIterator] = mContrastEnhancementFunction->enhance(( double )myIterator - mLookupTableOffset );
243  }
244 
245  return true;
246 }
247 
254 {
255 
256  if ( 0 != mContrastEnhancementFunction )
257  {
258  return mContrastEnhancementFunction->isValueInDisplayableRange( theValue );
259  }
260 
261  return false;
262 }
263 
271 {
272  QgsDebugMsg( "called algorithm: " + QString::number(( int )theAlgorithm ) + " generate lookup table: " + QString::number(( int )generateTable ) );
273 
274  if ( theAlgorithm != mContrastEnhancementAlgorithm )
275  {
276  switch ( theAlgorithm )
277  {
279  delete mContrastEnhancementFunction;
280  mContrastEnhancementFunction = new QgsLinearMinMaxEnhancement( mRasterDataType, mMinimumValue, mMaximumValue );
281  break;
283  delete mContrastEnhancementFunction;
284  mContrastEnhancementFunction = new QgsLinearMinMaxEnhancementWithClip( mRasterDataType, mMinimumValue, mMaximumValue );
285  break;
286  case ClipToMinimumMaximum :
287  delete mContrastEnhancementFunction;
288  mContrastEnhancementFunction = new QgsClipToMinMaxEnhancement( mRasterDataType, mMinimumValue, mMaximumValue );
289  break;
291  //Do nothing
292  break;
293  default:
294  delete mContrastEnhancementFunction;
295  mContrastEnhancementFunction = new QgsContrastEnhancementFunction( mRasterDataType, mMinimumValue, mMaximumValue );
296  break;
297  }
298 
299  mEnhancementDirty = true;
300  mContrastEnhancementAlgorithm = theAlgorithm;
301 
302  if ( generateTable )
303  {
304  generateLookupTable();
305  }
306  }
307 }
308 
315 {
316  QgsDebugMsg( "called" );
317 
318  if ( 0 != theFunction )
319  {
320  delete mContrastEnhancementFunction;
321  mContrastEnhancementFunction = theFunction;
322  mContrastEnhancementAlgorithm = UserDefinedEnhancement;
323  generateLookupTable();
324  }
325 }
326 
333 void QgsContrastEnhancement::setMaximumValue( double theValue, bool generateTable )
334 {
335  QgsDebugMsg( "called value: " + QString::number( theValue ) + " generate lookup table: " + QString::number(( int )generateTable ) );
336 
337  if ( theValue > maximumValuePossible( mRasterDataType ) )
338  {
339  mMaximumValue = maximumValuePossible( mRasterDataType );
340  }
341  else
342  {
343  mMaximumValue = theValue;
344  }
345 
346  if ( 0 != mContrastEnhancementFunction )
347  {
348  mContrastEnhancementFunction->setMaximumValue( theValue );
349  }
350 
351  mEnhancementDirty = true;
352 
353  if ( generateTable )
354  {
355  generateLookupTable();
356  }
357 }
358 
365 void QgsContrastEnhancement::setMinimumValue( double theValue, bool generateTable )
366 {
367  QgsDebugMsg( "called value: " + QString::number( theValue ) + " generate lookup table: " + QString::number(( int )generateTable ) );
368 
369  if ( theValue < minimumValuePossible( mRasterDataType ) )
370  {
371  mMinimumValue = minimumValuePossible( mRasterDataType );
372  }
373  else
374  {
375  mMinimumValue = theValue;
376  }
377 
378  if ( 0 != mContrastEnhancementFunction )
379  {
380  mContrastEnhancementFunction->setMinimumValue( theValue );
381  }
382 
383  mEnhancementDirty = true;
384 
385  if ( generateTable )
386  {
387  generateLookupTable();
388  }
389 }
390 
392 {
393  //minimum value
394  QDomElement minElem = doc.createElement( "minValue" );
395  QDomText minText = doc.createTextNode( QString::number( mMinimumValue ) );
396  minElem.appendChild( minText );
397  parentElem.appendChild( minElem );
398 
399  //maximum value
400  QDomElement maxElem = doc.createElement( "maxValue" );
401  QDomText maxText = doc.createTextNode( QString::number( mMaximumValue ) );
402  maxElem.appendChild( maxText );
403  parentElem.appendChild( maxElem );
404 
405  //algorithm
406  QDomElement algorithmElem = doc.createElement( "algorithm" );
407  QDomText algorithmText = doc.createTextNode( contrastEnhancementAlgorithmString( mContrastEnhancementAlgorithm ) );
408  algorithmElem.appendChild( algorithmText );
409  parentElem.appendChild( algorithmElem );
410 }
411 
413 {
414  QDomElement minValueElem = elem.firstChildElement( "minValue" );
415  if ( !minValueElem.isNull() )
416  {
417  mMinimumValue = minValueElem.text().toDouble();
418  }
419  QDomElement maxValueElem = elem.firstChildElement( "maxValue" );
420  if ( !maxValueElem.isNull() )
421  {
422  mMaximumValue = maxValueElem.text().toDouble();
423  }
424  QDomElement algorithmElem = elem.firstChildElement( "algorithm" );
425  if ( !algorithmElem.isNull() )
426  {
427  QString algorithmString = algorithmElem.text();
429  // old version ( < 19 Apr 2013) was using enum directly -> for backward compatibility
430  if ( algorithmString == "0" )
431  {
432  algorithm = NoEnhancement;
433  }
434  else if ( algorithmString == "1" )
435  {
436  algorithm = StretchToMinimumMaximum;
437  }
438  else if ( algorithmString == "2" )
439  {
440  algorithm = StretchAndClipToMinimumMaximum;
441  }
442  else if ( algorithmString == "3" )
443  {
444  algorithm = ClipToMinimumMaximum;
445  }
446  else if ( algorithmString == "4" )
447  {
448  algorithm = UserDefinedEnhancement;
449  }
450  else
451  {
452  algorithm = contrastEnhancementAlgorithmFromString( algorithmString );
453  }
454 
455  setContrastEnhancementAlgorithm( algorithm );
456  }
457 }
458 
460 {
461  switch ( algorithm )
462  {
463  case NoEnhancement:
464  return "NoEnhancement";
466  return "StretchToMinimumMaximum";
468  return "StretchAndClipToMinimumMaximum";
470  return "ClipToMinimumMaximum";
472  return "UserDefinedEnhancement";
473  }
474  return "NoEnhancement";
475 }
476 
478 {
479  if ( contrastEnhancementString == "StretchToMinimumMaximum" )
480  {
482  }
483  else if ( contrastEnhancementString == "StretchAndClipToMinimumMaximum" )
484  {
486  }
487  else if ( contrastEnhancementString == "ClipToMinimumMaximum" )
488  {
489  return ClipToMinimumMaximum;
490  }
491  else if ( contrastEnhancementString == "UserDefinedEnhancement" )
492  {
493  return UserDefinedEnhancement;
494  }
495  else
496  {
497  return NoEnhancement;
498  }
499 }
Sixty four bit floating point (double)
Definition: qgis.h:213
void setContrastEnhancementAlgorithm(ContrastEnhancementAlgorithm, bool generateTable=true)
Set the contrast enhancement algorithm.
void writeXML(QDomDocument &doc, QDomElement &parentElem) const
Sixteen bit signed integer (qint16)
Definition: qgis.h:209
Complex Float64.
Definition: qgis.h:217
void readXML(const QDomElement &elem)
QDomNode appendChild(const QDomNode &newChild)
Eight bit unsigned integer (quint8)
Definition: qgis.h:207
Sixteen bit unsigned integer (quint16)
Definition: qgis.h:208
#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)
static double maximumValuePossible(QGis::DataType)
Helper function that returns the maximum possible value for a GDAL data type.
double toDouble(bool *ok) const
ContrastEnhancementAlgorithm
This enumerator describes the types of contrast enhancement algorithms that can be used...
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.
Thirty two bit floating point (float)
Definition: qgis.h:212
QString text() const
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.
static QString contrastEnhancementAlgorithmString(ContrastEnhancementAlgorithm algorithm)
A contrast enhancement funcion is the base class for all raster contrast enhancements.
DataType
Raster data types.
Definition: qgis.h:204
A color enhancement function that performs a linear enhanceContrast between min and max...
QDomText createTextNode(const QString &value)
QgsContrastEnhancement(QGis::DataType theDatatype=QGis::Byte)
static ContrastEnhancementAlgorithm contrastEnhancementAlgorithmFromString(const QString &contrastEnhancementString)
Complex Int16.
Definition: qgis.h:214
bool isNull() const
A raster contrast enhancement that will clip a value to the specified min/max range.
Thirty two bit signed integer (qint32)
Definition: qgis.h:211
int enhanceContrast(double)
Apply the contrast enhancement to a value.
Unknown or unspecified type.
Definition: qgis.h:206
QDomElement firstChildElement(const QString &tagName) const
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...
Complex Int32.
Definition: qgis.h:215
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)
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32.
Definition: qgis.h:219
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32_Premultiplied.
Definition: qgis.h:221
void setMaximumValue(double, bool generateTable=true)
Set the maximum value for the contrast enhancement range.
Thirty two bit unsigned integer (quint32)
Definition: qgis.h:210
void setMaximumValue(double)
Mustator for the maximum value.
Complex Float32.
Definition: qgis.h:216