|
QGIS API Documentation
master-3f58142
|
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 }