QGIS API Documentation  master-3f58142
src/core/raster/qgscontrastenhancement.cpp
Go to the documentation of this file.
00001 /* **************************************************************************
00002                 qgscontrastenhancement.cpp -  description
00003                        -------------------
00004 begin                : Mon Oct 22 2007
00005 copyright            : (C) 2007 by Peter J. Ersts
00006 email                : ersts@amnh.org
00007 
00008 This class contains code that was originally part of the larger QgsRasterLayer
00009 class originally created circa 2004 by T.Sutton, Gary E.Sherman, Steve Halasz
00010 ****************************************************************************/
00011 
00012 /* **************************************************************************
00013  *                                                                         *
00014  *   This program is free software; you can redistribute it and/or modify  *
00015  *   it under the terms of the GNU General Public License as published by  *
00016  *   the Free Software Foundation; either version 2 of the License, or     *
00017  *   (at your option) any later version.                                   *
00018  *                                                                         *
00019  ***************************************************************************/
00020 
00021 #include "qgslogger.h"
00022 
00023 #include "qgscontrastenhancement.h"
00024 #include "qgscontrastenhancementfunction.h"
00025 #include "qgslinearminmaxenhancement.h"
00026 #include "qgslinearminmaxenhancementwithclip.h"
00027 #include "qgscliptominmaxenhancement.h"
00028 #include <QDomDocument>
00029 #include <QDomElement>
00030 
00031 QgsContrastEnhancement::QgsContrastEnhancement( QGis::DataType theDataType )
00032 {
00033   mLookupTable = 0;
00034   mContrastEnhancementFunction = 0;
00035   mEnhancementDirty = false;
00036   mContrastEnhancementAlgorithm = NoEnhancement;
00037   mRasterDataType = theDataType;
00038 
00039   mMinimumValue = minimumValuePossible( mRasterDataType );
00040   mMaximumValue = maximumValuePossible( mRasterDataType );
00041   mRasterDataTypeRange = mMaximumValue - mMinimumValue;
00042 
00043   mLookupTableOffset = mMinimumValue * -1;
00044 
00045   mContrastEnhancementFunction = new QgsContrastEnhancementFunction( mRasterDataType, mMinimumValue, mMaximumValue );
00046 
00047   //If the data type is larger than 16-bit do not generate a lookup table
00048   if ( mRasterDataTypeRange <= 65535.0 )
00049   {
00050     mLookupTable = new int[static_cast <int>( mRasterDataTypeRange+1 )];
00051   }
00052 
00053 }
00054 
00055 QgsContrastEnhancement::QgsContrastEnhancement( const QgsContrastEnhancement& ce )
00056 {
00057   mLookupTable = 0;
00058   mContrastEnhancementFunction = 0;
00059   mEnhancementDirty = true;
00060   mRasterDataType = ce.mRasterDataType;
00061 
00062   mMinimumValue = ce.mMinimumValue;
00063   mMaximumValue = ce.mMaximumValue;
00064   mRasterDataTypeRange = ce.mRasterDataTypeRange;
00065 
00066   mLookupTableOffset = mMinimumValue * -1;
00067 
00068   // setContrastEnhancementAlgorithm sets also QgsContrastEnhancementFunction
00069   setContrastEnhancementAlgorithm( ce.mContrastEnhancementAlgorithm, false );
00070 
00071   //If the data type is larger than 16-bit do not generate a lookup table
00072   if ( mRasterDataTypeRange <= 65535.0 )
00073   {
00074     mLookupTable = new int[static_cast <int>( mRasterDataTypeRange+1 )];
00075   }
00076 }
00077 
00078 QgsContrastEnhancement::~QgsContrastEnhancement()
00079 {
00080   delete [] mLookupTable;
00081   delete mContrastEnhancementFunction;
00082 }
00083 /*
00084  *
00085  * Static methods
00086  *
00087  */
00088 
00092 double QgsContrastEnhancement::maximumValuePossible( QGis::DataType theDataType )
00093 {
00094   switch ( theDataType )
00095   {
00096     case QGis::Byte:
00097       return std::numeric_limits<unsigned char>::max();
00098       break;
00099     case QGis::UInt16:
00100       return std::numeric_limits<unsigned short>::max();
00101       break;
00102     case QGis::Int16:
00103       return std::numeric_limits<short>::max();
00104       break;
00105     case QGis::UInt32:
00106       return std::numeric_limits<unsigned int>::max();
00107       break;
00108     case QGis::Int32:
00109       return std::numeric_limits<int>::max();
00110       break;
00111     case QGis::Float32:
00112       return std::numeric_limits<float>::max();
00113       break;
00114     case QGis::Float64:
00115       return std::numeric_limits<double>::max();
00116       break;
00117     case QGis::CInt16:
00118       return std::numeric_limits<short>::max();
00119       break;
00120     case QGis::CInt32:
00121       return std::numeric_limits<int>::max();
00122       break;
00123     case QGis::CFloat32:
00124       return std::numeric_limits<float>::max();
00125       break;
00126     case QGis::CFloat64:
00127       return std::numeric_limits<double>::max();
00128       break;
00129     case QGis::ARGB32:
00130     case QGis::ARGB32_Premultiplied:
00131     case QGis::UnknownDataType:
00132       // XXX - mloskot: not handled?
00133       break;
00134   }
00135 
00136   return std::numeric_limits<double>::max();
00137 }
00141 double QgsContrastEnhancement::minimumValuePossible( QGis::DataType theDataType )
00142 {
00143   switch ( theDataType )
00144   {
00145     case QGis::Byte:
00146       return std::numeric_limits<unsigned char>::min();
00147       break;
00148     case QGis::UInt16:
00149       return std::numeric_limits<unsigned short>::min();
00150       break;
00151     case QGis::Int16:
00152       return std::numeric_limits<short>::min();
00153       break;
00154     case QGis::UInt32:
00155       return std::numeric_limits<unsigned int>::min();
00156       break;
00157     case QGis::Int32:
00158       return std::numeric_limits<int>::min();
00159       break;
00160     case QGis::Float32:
00161       return std::numeric_limits<float>::max() * -1.0;
00162       break;
00163     case QGis::Float64:
00164       return std::numeric_limits<double>::max() * -1.0;
00165       break;
00166     case QGis::CInt16:
00167       return std::numeric_limits<short>::min();
00168       break;
00169     case QGis::CInt32:
00170       return std::numeric_limits<int>::min();
00171       break;
00172     case QGis::CFloat32:
00173       return std::numeric_limits<float>::max() * -1.0;
00174       break;
00175     case QGis::CFloat64:
00176       return std::numeric_limits<double>::max() * -1.0;
00177       break;
00178     case QGis::ARGB32:
00179     case QGis::ARGB32_Premultiplied:
00180     case QGis::UnknownDataType:
00181       // XXX - mloskot: not handled?
00182       break;
00183   }
00184 
00185   return std::numeric_limits<double>::max() * -1.0;
00186 }
00187 
00188 /*
00189  *
00190  * Non-Static methods
00191  *
00192  */
00198 int QgsContrastEnhancement::enhanceContrast( double theValue )
00199 {
00200   if ( mEnhancementDirty )
00201   {
00202     generateLookupTable();
00203   }
00204 
00205   if ( mLookupTable && NoEnhancement != mContrastEnhancementAlgorithm )
00206   {
00207     return mLookupTable[static_cast <int>( theValue + mLookupTableOffset )];
00208   }
00209   else
00210   {
00211     // Even if the contrast enhancement algorithms is set to NoEnhancement
00212     // The input values will still have to be scaled for all data types
00213     // greater than 1 byte.
00214     return mContrastEnhancementFunction->enhance( theValue );
00215   }
00216 }
00217 
00221 bool QgsContrastEnhancement::generateLookupTable()
00222 {
00223   mEnhancementDirty = false;
00224 
00225   if ( !mContrastEnhancementFunction )
00226     return false;
00227   if ( NoEnhancement == mContrastEnhancementAlgorithm )
00228     return false;
00229   if ( QGis::Byte != mRasterDataType && QGis::UInt16 != mRasterDataType && QGis::Int16 != mRasterDataType )
00230     return false;
00231   if ( !mLookupTable )
00232     return false;
00233 
00234   QgsDebugMsg( "building lookup table" );
00235   QgsDebugMsg( "***MinimumValue : " + QString::number( mMinimumValue ) );
00236   QgsDebugMsg( "***MaximumValue : " + QString::number( mMaximumValue ) );
00237   QgsDebugMsg( "***mLookupTableOffset : " + QString::number( mLookupTableOffset ) );
00238   QgsDebugMsg( "***mRasterDataTypeRange : " + QString::number( mRasterDataTypeRange ) );
00239 
00240   for ( int myIterator = 0; myIterator <= mRasterDataTypeRange; myIterator++ )
00241   {
00242     mLookupTable[myIterator] = mContrastEnhancementFunction->enhance(( double )myIterator - mLookupTableOffset );
00243   }
00244 
00245   return true;
00246 }
00247 
00253 bool QgsContrastEnhancement::isValueInDisplayableRange( double theValue )
00254 {
00255 
00256   if ( 0 != mContrastEnhancementFunction )
00257   {
00258     return mContrastEnhancementFunction->isValueInDisplayableRange( theValue );
00259   }
00260 
00261   return false;
00262 }
00263 
00270 void QgsContrastEnhancement::setContrastEnhancementAlgorithm( ContrastEnhancementAlgorithm theAlgorithm, bool generateTable )
00271 {
00272   QgsDebugMsg( "called algorithm: " + QString::number(( int )theAlgorithm ) + " generate lookup table: " + QString::number(( int )generateTable ) );
00273 
00274   if ( theAlgorithm != mContrastEnhancementAlgorithm )
00275   {
00276     switch ( theAlgorithm )
00277     {
00278       case StretchToMinimumMaximum :
00279         mContrastEnhancementFunction = new QgsLinearMinMaxEnhancement( mRasterDataType, mMinimumValue, mMaximumValue );
00280         break;
00281       case StretchAndClipToMinimumMaximum :
00282         mContrastEnhancementFunction = new QgsLinearMinMaxEnhancementWithClip( mRasterDataType, mMinimumValue, mMaximumValue );
00283         break;
00284       case ClipToMinimumMaximum :
00285         mContrastEnhancementFunction = new QgsClipToMinMaxEnhancement( mRasterDataType, mMinimumValue, mMaximumValue );
00286         break;
00287       case UserDefinedEnhancement :
00288         //Do nothing
00289         break;
00290       default:
00291         mContrastEnhancementFunction = new QgsContrastEnhancementFunction( mRasterDataType, mMinimumValue, mMaximumValue );
00292         break;
00293     }
00294 
00295     mEnhancementDirty = true;
00296     mContrastEnhancementAlgorithm = theAlgorithm;
00297 
00298     if ( generateTable )
00299     {
00300       generateLookupTable();
00301     }
00302   }
00303 }
00304 
00310 void QgsContrastEnhancement::setContrastEnhancementFunction( QgsContrastEnhancementFunction* theFunction )
00311 {
00312   QgsDebugMsg( "called" );
00313 
00314   if ( 0 != theFunction )
00315   {
00316     mContrastEnhancementFunction = theFunction;
00317     mContrastEnhancementAlgorithm = UserDefinedEnhancement;
00318     generateLookupTable();
00319   }
00320 }
00321 
00328 void QgsContrastEnhancement::setMaximumValue( double theValue, bool generateTable )
00329 {
00330   QgsDebugMsg( "called value: " + QString::number( theValue ) + " generate lookup table: " + QString::number(( int )generateTable ) );
00331 
00332   if ( theValue > maximumValuePossible( mRasterDataType ) )
00333   {
00334     mMaximumValue = maximumValuePossible( mRasterDataType );
00335   }
00336   else
00337   {
00338     mMaximumValue = theValue;
00339   }
00340 
00341   if ( 0 != mContrastEnhancementFunction )
00342   {
00343     mContrastEnhancementFunction->setMaximumValue( theValue );
00344   }
00345 
00346   mEnhancementDirty = true;
00347 
00348   if ( generateTable )
00349   {
00350     generateLookupTable();
00351   }
00352 }
00353 
00360 void QgsContrastEnhancement::setMinimumValue( double theValue, bool generateTable )
00361 {
00362   QgsDebugMsg( "called value: " + QString::number( theValue ) + " generate lookup table: " + QString::number(( int )generateTable ) );
00363 
00364   if ( theValue < minimumValuePossible( mRasterDataType ) )
00365   {
00366     mMinimumValue = minimumValuePossible( mRasterDataType );
00367   }
00368   else
00369   {
00370     mMinimumValue = theValue;
00371   }
00372 
00373   if ( 0 != mContrastEnhancementFunction )
00374   {
00375     mContrastEnhancementFunction->setMinimumValue( theValue );
00376   }
00377 
00378   mEnhancementDirty = true;
00379 
00380   if ( generateTable )
00381   {
00382     generateLookupTable();
00383   }
00384 }
00385 
00386 void QgsContrastEnhancement::writeXML( QDomDocument& doc, QDomElement& parentElem ) const
00387 {
00388   //minimum value
00389   QDomElement minElem = doc.createElement( "minValue" );
00390   QDomText minText = doc.createTextNode( QString::number( mMinimumValue ) );
00391   minElem.appendChild( minText );
00392   parentElem.appendChild( minElem );
00393 
00394   //maximum value
00395   QDomElement maxElem = doc.createElement( "maxValue" );
00396   QDomText maxText = doc.createTextNode( QString::number( mMaximumValue ) );
00397   maxElem.appendChild( maxText );
00398   parentElem.appendChild( maxElem );
00399 
00400   //algorithm
00401   QDomElement algorithmElem = doc.createElement( "algorithm" );
00402   QDomText algorithmText = doc.createTextNode( contrastEnhancementAlgorithmString( mContrastEnhancementAlgorithm ) );
00403   algorithmElem.appendChild( algorithmText );
00404   parentElem.appendChild( algorithmElem );
00405 }
00406 
00407 void QgsContrastEnhancement::readXML( const QDomElement& elem )
00408 {
00409   QDomElement minValueElem = elem.firstChildElement( "minValue" );
00410   if ( !minValueElem.isNull() )
00411   {
00412     mMinimumValue = minValueElem.text().toDouble();
00413   }
00414   QDomElement maxValueElem = elem.firstChildElement( "maxValue" );
00415   if ( !maxValueElem.isNull() )
00416   {
00417     mMaximumValue = maxValueElem.text().toDouble();
00418   }
00419   QDomElement algorithmElem = elem.firstChildElement( "algorithm" );
00420   if ( !algorithmElem.isNull() )
00421   {
00422     QString algorithmString = algorithmElem.text();
00423     ContrastEnhancementAlgorithm algorithm = NoEnhancement;
00424     // old version ( < 19 Apr 2013) was using enum directly -> for backward compatibility
00425     if ( algorithmString == "0" )
00426     {
00427       algorithm = NoEnhancement;
00428     }
00429     else if ( algorithmString == "1" )
00430     {
00431       algorithm = StretchToMinimumMaximum;
00432     }
00433     else if ( algorithmString == "2" )
00434     {
00435       algorithm = StretchAndClipToMinimumMaximum;
00436     }
00437     else if ( algorithmString == "3" )
00438     {
00439       algorithm = ClipToMinimumMaximum;
00440     }
00441     else if ( algorithmString == "4" )
00442     {
00443       algorithm = UserDefinedEnhancement;
00444     }
00445     else
00446     {
00447       algorithm = contrastEnhancementAlgorithmFromString( algorithmString );
00448     }
00449 
00450     setContrastEnhancementAlgorithm( algorithm );
00451   }
00452 }
00453 
00454 QString QgsContrastEnhancement::contrastEnhancementAlgorithmString( ContrastEnhancementAlgorithm algorithm )
00455 {
00456   switch ( algorithm )
00457   {
00458     case NoEnhancement:
00459       return "NoEnhancement";
00460     case StretchToMinimumMaximum:
00461       return "StretchToMinimumMaximum";
00462     case StretchAndClipToMinimumMaximum:
00463       return "StretchAndClipToMinimumMaximum";
00464     case ClipToMinimumMaximum:
00465       return "ClipToMinimumMaximum";
00466     case UserDefinedEnhancement:
00467       return "UserDefinedEnhancement";
00468   }
00469   return "NoEnhancement";
00470 }
00471 
00472 QgsContrastEnhancement::ContrastEnhancementAlgorithm QgsContrastEnhancement::contrastEnhancementAlgorithmFromString( const QString& contrastEnhancementString )
00473 {
00474   if ( contrastEnhancementString == "StretchToMinimumMaximum" )
00475   {
00476     return StretchToMinimumMaximum;
00477   }
00478   else if ( contrastEnhancementString == "StretchAndClipToMinimumMaximum" )
00479   {
00480     return StretchAndClipToMinimumMaximum;
00481   }
00482   else if ( contrastEnhancementString == "ClipToMinimumMaximum" )
00483   {
00484     return ClipToMinimumMaximum;
00485   }
00486   else if ( contrastEnhancementString == "UserDefinedEnhancement" )
00487   {
00488     return UserDefinedEnhancement;
00489   }
00490   else
00491   {
00492     return NoEnhancement;
00493   }
00494 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines