QGIS API Documentation  2.14.0-Essen
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 <QDomDocument>
29 #include <QDomElement>
30 
32  : mContrastEnhancementAlgorithm( NoEnhancement )
33  , mContrastEnhancementFunction( nullptr )
34  , mEnhancementDirty( false )
35  , mLookupTable( nullptr )
36  , mRasterDataType( theDataType )
37 {
38  mMinimumValue = minimumValuePossible( mRasterDataType );
39  mMaximumValue = maximumValuePossible( mRasterDataType );
40  mRasterDataTypeRange = mMaximumValue - mMinimumValue;
41 
42  mLookupTableOffset = mMinimumValue * -1;
43 
44  mContrastEnhancementFunction = 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  : mContrastEnhancementFunction( nullptr )
56  , mEnhancementDirty( true )
57  , mLookupTable( nullptr )
58  , mMinimumValue( ce.mMinimumValue )
59  , mMaximumValue( ce.mMaximumValue )
60  , mRasterDataType( ce.mRasterDataType )
61  , mRasterDataTypeRange( ce.mRasterDataTypeRange )
62 {
63  mLookupTableOffset = minimumValuePossible( mRasterDataType ) * -1;
64 
65  // setContrastEnhancementAlgorithm sets also QgsContrastEnhancementFunction
66  setContrastEnhancementAlgorithm( ce.mContrastEnhancementAlgorithm, false );
67 
68  //If the data type is larger than 16-bit do not generate a lookup table
69  if ( mRasterDataTypeRange <= 65535.0 )
70  {
71  mLookupTable = new int[static_cast <int>( mRasterDataTypeRange+1 )];
72  }
73 }
74 
76 {
77  delete [] mLookupTable;
78  delete mContrastEnhancementFunction;
79 }
80 /*
81  *
82  * Static methods
83  *
84  */
85 
90 {
91  switch ( theDataType )
92  {
93  case QGis::Byte:
95  case QGis::UInt16:
97  case QGis::Int16:
99  case QGis::UInt32:
101  case QGis::Int32:
103  case QGis::Float32:
105  case QGis::Float64:
107  case QGis::CInt16:
109  case QGis::CInt32:
111  case QGis::CFloat32:
113  case QGis::CFloat64:
115  case QGis::ARGB32:
118  // XXX - mloskot: not handled?
119  break;
120  }
121 
123 }
128 {
129  switch ( theDataType )
130  {
131  case QGis::Byte:
133  case QGis::UInt16:
135  case QGis::Int16:
137  case QGis::UInt32:
139  case QGis::Int32:
141  case QGis::Float32:
142  return std::numeric_limits<float>::max() * -1.0;
143  case QGis::Float64:
144  return std::numeric_limits<double>::max() * -1.0;
145  case QGis::CInt16:
147  case QGis::CInt32:
149  case QGis::CFloat32:
150  return std::numeric_limits<float>::max() * -1.0;
151  case QGis::CFloat64:
152  return std::numeric_limits<double>::max() * -1.0;
153  case QGis::ARGB32:
156  // XXX - mloskot: not handled?
157  break;
158  }
159 
160  return std::numeric_limits<double>::max() * -1.0;
161 }
162 
163 /*
164  *
165  * Non-Static methods
166  *
167  */
174 {
175  if ( mEnhancementDirty )
176  {
177  generateLookupTable();
178  }
179 
180  if ( mLookupTable && NoEnhancement != mContrastEnhancementAlgorithm )
181  {
182  return mLookupTable[static_cast <int>( theValue + 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( theValue );
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( theValue );
233  }
234 
235  return false;
236 }
237 
245 {
246  switch ( theAlgorithm )
247  {
249  delete mContrastEnhancementFunction;
250  mContrastEnhancementFunction = new QgsLinearMinMaxEnhancement( mRasterDataType, mMinimumValue, mMaximumValue );
251  break;
253  delete mContrastEnhancementFunction;
254  mContrastEnhancementFunction = new QgsLinearMinMaxEnhancementWithClip( mRasterDataType, mMinimumValue, mMaximumValue );
255  break;
256  case ClipToMinimumMaximum :
257  delete mContrastEnhancementFunction;
258  mContrastEnhancementFunction = new QgsClipToMinMaxEnhancement( mRasterDataType, mMinimumValue, mMaximumValue );
259  break;
261  //Do nothing
262  break;
263  default:
264  delete mContrastEnhancementFunction;
265  mContrastEnhancementFunction = new QgsContrastEnhancementFunction( mRasterDataType, mMinimumValue, mMaximumValue );
266  break;
267  }
268 
269  mEnhancementDirty = true;
270  mContrastEnhancementAlgorithm = theAlgorithm;
271 
272  if ( generateTable )
273  {
274  generateLookupTable();
275  }
276 }
277 
284 {
285  QgsDebugMsgLevel( "called", 4 );
286 
287  if ( theFunction )
288  {
289  delete mContrastEnhancementFunction;
290  mContrastEnhancementFunction = theFunction;
291  mContrastEnhancementAlgorithm = UserDefinedEnhancement;
292  generateLookupTable();
293  }
294 }
295 
302 void QgsContrastEnhancement::setMaximumValue( double theValue, bool generateTable )
303 {
304  QgsDebugMsgLevel( "called value: " + QString::number( theValue ) + " generate lookup table: " + QString::number( static_cast< int >( generateTable ) ), 4 );
305 
306  if ( theValue > maximumValuePossible( mRasterDataType ) )
307  {
308  mMaximumValue = maximumValuePossible( mRasterDataType );
309  }
310  else
311  {
312  mMaximumValue = theValue;
313  }
314 
315  if ( mContrastEnhancementFunction )
316  {
317  mContrastEnhancementFunction->setMaximumValue( theValue );
318  }
319 
320  mEnhancementDirty = true;
321 
322  if ( generateTable )
323  {
324  generateLookupTable();
325  }
326 }
327 
334 void QgsContrastEnhancement::setMinimumValue( double theValue, bool generateTable )
335 {
336  QgsDebugMsgLevel( "called value: " + QString::number( theValue ) + " generate lookup table: " + QString::number( static_cast< int >( generateTable ) ), 4 );
337 
338  if ( theValue < minimumValuePossible( mRasterDataType ) )
339  {
340  mMinimumValue = minimumValuePossible( mRasterDataType );
341  }
342  else
343  {
344  mMinimumValue = theValue;
345  }
346 
347  if ( mContrastEnhancementFunction )
348  {
349  mContrastEnhancementFunction->setMinimumValue( theValue );
350  }
351 
352  mEnhancementDirty = true;
353 
354  if ( generateTable )
355  {
356  generateLookupTable();
357  }
358 }
359 
361 {
362  //minimum value
363  QDomElement minElem = doc.createElement( "minValue" );
364  QDomText minText = doc.createTextNode( QString::number( mMinimumValue ) );
365  minElem.appendChild( minText );
366  parentElem.appendChild( minElem );
367 
368  //maximum value
369  QDomElement maxElem = doc.createElement( "maxValue" );
370  QDomText maxText = doc.createTextNode( QString::number( mMaximumValue ) );
371  maxElem.appendChild( maxText );
372  parentElem.appendChild( maxElem );
373 
374  //algorithm
375  QDomElement algorithmElem = doc.createElement( "algorithm" );
376  QDomText algorithmText = doc.createTextNode( contrastEnhancementAlgorithmString( mContrastEnhancementAlgorithm ) );
377  algorithmElem.appendChild( algorithmText );
378  parentElem.appendChild( algorithmElem );
379 }
380 
382 {
383  QDomElement minValueElem = elem.firstChildElement( "minValue" );
384  if ( !minValueElem.isNull() )
385  {
386  mMinimumValue = minValueElem.text().toDouble();
387  }
388  QDomElement maxValueElem = elem.firstChildElement( "maxValue" );
389  if ( !maxValueElem.isNull() )
390  {
391  mMaximumValue = maxValueElem.text().toDouble();
392  }
393  QDomElement algorithmElem = elem.firstChildElement( "algorithm" );
394  if ( !algorithmElem.isNull() )
395  {
396  QString algorithmString = algorithmElem.text();
398  // old version ( < 19 Apr 2013) was using enum directly -> for backward compatibility
399  if ( algorithmString == "0" )
400  {
401  algorithm = NoEnhancement;
402  }
403  else if ( algorithmString == "1" )
404  {
405  algorithm = StretchToMinimumMaximum;
406  }
407  else if ( algorithmString == "2" )
408  {
409  algorithm = StretchAndClipToMinimumMaximum;
410  }
411  else if ( algorithmString == "3" )
412  {
413  algorithm = ClipToMinimumMaximum;
414  }
415  else if ( algorithmString == "4" )
416  {
417  algorithm = UserDefinedEnhancement;
418  }
419  else
420  {
421  algorithm = contrastEnhancementAlgorithmFromString( algorithmString );
422  }
423 
424  setContrastEnhancementAlgorithm( algorithm );
425  }
426 }
427 
429 {
430  switch ( algorithm )
431  {
432  case NoEnhancement:
433  return "NoEnhancement";
435  return "StretchToMinimumMaximum";
437  return "StretchAndClipToMinimumMaximum";
439  return "ClipToMinimumMaximum";
441  return "UserDefinedEnhancement";
442  }
443  return "NoEnhancement";
444 }
445 
447 {
448  if ( contrastEnhancementString == "StretchToMinimumMaximum" )
449  {
451  }
452  else if ( contrastEnhancementString == "StretchAndClipToMinimumMaximum" )
453  {
455  }
456  else if ( contrastEnhancementString == "ClipToMinimumMaximum" )
457  {
458  return ClipToMinimumMaximum;
459  }
460  else if ( contrastEnhancementString == "UserDefinedEnhancement" )
461  {
462  return UserDefinedEnhancement;
463  }
464  else
465  {
466  return NoEnhancement;
467  }
468 }
Eight bit unsigned integer (quint8)
Definition: qgis.h:132
void setContrastEnhancementAlgorithm(ContrastEnhancementAlgorithm, bool generateTable=true)
Set the contrast enhancement algorithm.
void writeXML(QDomDocument &doc, QDomElement &parentElem) const
Unknown or unspecified type.
Definition: qgis.h:131
void readXML(const QDomElement &elem)
Complex Float32.
Definition: qgis.h:141
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:140
Thirty two bit floating point (float)
Definition: qgis.h:137
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:133
Sixty four bit floating point (double)
Definition: qgis.h:138
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32_Premultiplied.
Definition: qgis.h:146
QString text() const
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:34
Thirty two bit signed integer (qint32)
Definition: qgis.h:136
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:135
static QString contrastEnhancementAlgorithmString(ContrastEnhancementAlgorithm algorithm)
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32.
Definition: qgis.h:144
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:134
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:129
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:139
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:142