cmtkColormap.cxx

Go to the documentation of this file.
00001 /*
00002 //
00003 //  Copyright 1997-2009 Torsten Rohlfing
00004 //
00005 //  Copyright 2004-2011 SRI International
00006 //
00007 //  This file is part of the Computational Morphometry Toolkit.
00008 //
00009 //  http://www.nitrc.org/projects/cmtk/
00010 //
00011 //  The Computational Morphometry Toolkit is free software: you can
00012 //  redistribute it and/or modify it under the terms of the GNU General Public
00013 //  License as published by the Free Software Foundation, either version 3 of
00014 //  the License, or (at your option) any later version.
00015 //
00016 //  The Computational Morphometry Toolkit is distributed in the hope that it
00017 //  will be useful, but WITHOUT ANY WARRANTY; without even the implied
00018 //  warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019 //  GNU General Public License for more details.
00020 //
00021 //  You should have received a copy of the GNU General Public License along
00022 //  with the Computational Morphometry Toolkit.  If not, see
00023 //  <http://www.gnu.org/licenses/>.
00024 //
00025 //  $Revision: 2745 $
00026 //
00027 //  $LastChangedDate: 2011-01-14 14:22:47 -0800 (Fri, 14 Jan 2011) $
00028 //
00029 //  $LastChangedBy: torstenrohlfing $
00030 //
00031 */
00032 
00033 #include "cmtkColormap.h"
00034 
00035 #include <math.h>
00036 
00037 #ifdef HAVE_IEEEFP_H
00038 #  include <ieeefp.h>
00039 #endif
00040 
00041 #include <Base/cmtkTypedArray.h>
00042 #include <Base/cmtkSegmentationLabel.h>
00043 
00044 namespace
00045 cmtk
00046 {
00047 
00050 
00051 const char *Colormap::StandardColormaps[] = 
00052 {
00053   "Gray", "Red", "Green", "Blue", "Rainbow", "Labels", NULL
00054 };
00055 
00056 Colormap::Colormap()
00057 {
00058   TableEntries = 256;
00059   SetStandardColormap( PALETTE_GRAY );
00060   DataRange[0] = 0;
00061   DataRange[1] = 4095;
00062   HueRange[0] = 0;
00063   HueRange[1] = 4095;
00064   ValueRange[0] = 0;
00065   ValueRange[1] = 4095;
00066   SaturationRange[0] = 0;
00067   SaturationRange[1] = 4095;
00068   Gamma = 0;
00069   Reverse = false;
00070 
00071   CreateSystemLabelColorMap( this->LabelColorMap );
00072 }
00073 
00074 void 
00075 Colormap::SetFromStudy( const Study* study )
00076 {
00077   if ( ! study ) return;
00078 
00079   // if there is a user-defined map, use that.
00080   if ( study->GetHaveUserColorMap() ) 
00081     {
00082     LabelColorMap = study->GetUserLabelMap();
00083     }
00084   
00085   // copy all other settings anyway, just in case.
00086   this->SetStandardColormap( study->GetStandardColormap() );
00087   this->SetReverse( study->GetReverseColormap() );
00088   this->SetDataRange( study->GetBlack(), study->GetWhite() );
00089   this->SetGamma( study->GetGamma() );
00090 }
00091 
00092 void
00093 Colormap::SetStandardColormap( const int index )
00094 {
00095   HaveUserMap = false;
00096   SetGamma( 0 );
00097   switch ( index ) 
00098     {
00099     case PALETTE_GRAY : 
00100       SetHueRange( 0, 0 );
00101       SetSaturationRange( 0, 0 );
00102       SetValueRange( 0, 1 );
00103       break;
00104     case PALETTE_RED : 
00105       SetHueRange( 0, 0 );
00106       SetSaturationRange( 1, 1 );
00107       SetValueRange( 0, 1 );
00108       break;
00109     case PALETTE_GREEN : 
00110       SetHueRange( 0.33, 0.33 );
00111       SetSaturationRange( 1, 1 );
00112       SetValueRange( 0, 1 );
00113       break;
00114     case PALETTE_BLUE : 
00115       SetHueRange( 0.66, 0.66 );
00116       SetSaturationRange( 1, 1 );
00117       SetValueRange( 0, 1 );
00118       break;
00119     case PALETTE_RAINBOW : 
00120       SetHueRange( 0.66, 0 );
00121       SetSaturationRange( 1, 1 );
00122       SetValueRange( 1, 1 );
00123       break;
00124     case PALETTE_LABELS:
00125     default:
00126       HaveUserMap = true;
00127       // nothing to do for user map; hopefully, there is one ;)
00128       break;
00129     }
00130 }
00131 
00132 void
00133 Colormap::Apply( void *const outPtr, const TypedArray* inPtr, const bool generateAlpha )
00134 {
00135   if ( ( outPtr == NULL ) || (inPtr == NULL) ) return;
00136 
00137   if ( (LookupTable.empty()) || (!TableEntries) ) 
00138     {
00139     memset( outPtr, 0, 3 * inPtr->GetDataSize() );
00140     return;
00141     }
00142   
00143   int size = inPtr->GetDataSize();
00144   if ( generateAlpha ) 
00145     {
00146     switch ( inPtr->GetType() ) 
00147       {
00148       case TYPE_BYTE:
00149         ApplyPrimitive<unsigned char>( (RGBA*) outPtr, (unsigned char*)inPtr->GetDataPtr(), size, inPtr->GetPaddingFlag(), *((unsigned char*)inPtr->GetPaddingPtr()) );
00150         break;
00151       case TYPE_CHAR:
00152         ApplyPrimitive<char>( (RGBA*) outPtr, (char*)inPtr->GetDataPtr(), size, inPtr->GetPaddingFlag(), *((char*)inPtr->GetPaddingPtr()) );
00153         break;
00154       case TYPE_SHORT:
00155         ApplyPrimitive<short>( (RGBA*) outPtr, (short*)inPtr->GetDataPtr(), size, inPtr->GetPaddingFlag(), *((short*)inPtr->GetPaddingPtr()) );
00156         break;
00157       case TYPE_USHORT:
00158         ApplyPrimitive<unsigned short>( (RGBA*) outPtr, (unsigned short*)inPtr->GetDataPtr(), size, inPtr->GetPaddingFlag(), *((unsigned short*)inPtr->GetPaddingPtr()) );
00159         break;
00160       case TYPE_INT:
00161         ApplyPrimitive<int>( (RGBA*) outPtr, (int*)inPtr->GetDataPtr(), size, inPtr->GetPaddingFlag(), *((int*)inPtr->GetPaddingPtr()) );
00162         break;
00163       case TYPE_UINT:
00164         ApplyPrimitive<unsigned int>( (RGBA*) outPtr, (unsigned int*)inPtr->GetDataPtr(), size, inPtr->GetPaddingFlag(), *((unsigned int*)inPtr->GetPaddingPtr()) );
00165         break;
00166       case TYPE_FLOAT:
00167         ApplyPrimitive<float>( (RGBA*) outPtr, (float*)inPtr->GetDataPtr(), size, inPtr->GetPaddingFlag(), *((float*)inPtr->GetPaddingPtr()) );
00168         break;
00169       case TYPE_DOUBLE:
00170         ApplyPrimitive<double>( (RGBA*) outPtr, (double*)inPtr->GetDataPtr(), size, inPtr->GetPaddingFlag(), *((double*)inPtr->GetPaddingPtr()) );
00171         break;
00172       case TYPE_NONE:
00173         break;
00174       }
00175     }
00176   else
00177     {
00178     switch ( inPtr->GetType() ) 
00179       {
00180       case TYPE_BYTE:
00181         ApplyPrimitive<unsigned char>( (RGB*) outPtr, (unsigned char*)inPtr->GetDataPtr(), size, inPtr->GetPaddingFlag(), *((unsigned char*)inPtr->GetPaddingPtr()) );
00182         break;
00183       case TYPE_CHAR:
00184         ApplyPrimitive<char>( (RGB*) outPtr, (char*)inPtr->GetDataPtr(), size, inPtr->GetPaddingFlag(), *((char*)inPtr->GetPaddingPtr()) );
00185         break;
00186       case TYPE_SHORT:
00187         ApplyPrimitive<short>( (RGB*) outPtr, (short*)inPtr->GetDataPtr(), size, inPtr->GetPaddingFlag(), *((short*)inPtr->GetPaddingPtr()) );
00188         break;
00189       case TYPE_USHORT: 
00190         ApplyPrimitive<unsigned short>( (RGB*) outPtr, (unsigned short*)inPtr->GetDataPtr(), size, inPtr->GetPaddingFlag(), *((unsigned short*)inPtr->GetPaddingPtr()) );
00191         break;
00192       case TYPE_INT:
00193         ApplyPrimitive<int>( (RGB*) outPtr, (int*)inPtr->GetDataPtr(), size, inPtr->GetPaddingFlag(), *((int*)inPtr->GetPaddingPtr()) );
00194         break;
00195       case TYPE_UINT:
00196         ApplyPrimitive<unsigned int>( (RGB*) outPtr, (unsigned int*)inPtr->GetDataPtr(), size, inPtr->GetPaddingFlag(), *((unsigned int*)inPtr->GetPaddingPtr()) );
00197         break;
00198       case TYPE_FLOAT:
00199         ApplyPrimitive<float>( (RGB*) outPtr, (float*)inPtr->GetDataPtr(), size, inPtr->GetPaddingFlag(), *((float*)inPtr->GetPaddingPtr()) );
00200         break;
00201       case TYPE_DOUBLE:
00202         ApplyPrimitive<double>( (RGB*) outPtr, (double*)inPtr->GetDataPtr(), size, inPtr->GetPaddingFlag(), *((double*)inPtr->GetPaddingPtr()) );
00203         break;
00204       case TYPE_NONE:
00205         break;
00206       }
00207     }
00208 }
00209 
00210 template<class T>
00211 void Colormap::ApplyPrimitive
00212 ( RGB *const outPtr, const T* inPtr, const unsigned int count, const bool paddingFlag, const T paddingData ) const
00213 {
00214   if ( Reverse ) 
00215     {
00216     for ( unsigned int index = 0; index < count; ++index ) 
00217       {
00218       T data = inPtr[index];
00219       if ( (paddingFlag && (data == paddingData)) || !finite( data ) ) 
00220         data = 0;
00221       
00222       if ( data <= DataRange[0] ) 
00223         outPtr[index] = LookupTable[LookupTable.size()-1];
00224       else if ( data >= DataRange[1] ) 
00225         outPtr[index] = LookupTable[0];
00226       else
00227         outPtr[index] = LookupTable[ LookupTable.size() - 1 - (int)( (data - DataRange[0]) * InvDataRangeWidth ) ];
00228       }
00229     } 
00230   else
00231     {
00232     for ( unsigned int index = 0; index < count; ++index ) 
00233       {
00234       T data = inPtr[index];
00235       if ( (paddingFlag && (data == paddingData)) || !finite( data ) ) 
00236         data = 0;
00237 
00238       if ( data <= DataRange[0] ) 
00239         outPtr[index] = LookupTable[0];
00240       else if ( data >= DataRange[1] ) 
00241         outPtr[index] = LookupTable[LookupTable.size()-1];
00242       else
00243         outPtr[index] = LookupTable[ (int)( (data - DataRange[0]) * InvDataRangeWidth ) ];
00244       }
00245     }
00246 }
00247 
00248 template<class T>
00249 void Colormap::ApplyPrimitive
00250 ( RGBA *const outPtr, const T* inPtr, const unsigned int count, const bool paddingFlag, const T paddingData ) const
00251 {
00252   if ( Reverse ) 
00253     {
00254     for ( unsigned int index = 0; index < count; ++index ) 
00255       {
00256       T data = inPtr[index];
00257       if ( (paddingFlag && (data == paddingData)) || !finite( data ) ) 
00258         data = 0;
00259       
00260       if ( data <= DataRange[0] ) 
00261         outPtr[index] = LookupTable[LookupTable.size()-1];
00262       else if ( inPtr[index] >= DataRange[1] ) 
00263         outPtr[index] = LookupTable[0];
00264       else
00265         outPtr[index] = LookupTable[ LookupTable.size() - 1 - (int)( (data - DataRange[0]) * InvDataRangeWidth ) ];
00266       outPtr[index].Alpha = 255;
00267       }
00268     } 
00269   else
00270     {
00271     for ( unsigned int index = 0; index < count; ++index ) 
00272       {
00273       T data = inPtr[index];
00274       if ( (paddingFlag && (data == paddingData)) || !finite( data ) ) 
00275         data = 0;
00276 
00277       if ( data <= DataRange[0] ) 
00278         outPtr[index] = LookupTable[0];
00279       else if ( data >= DataRange[1] ) 
00280         outPtr[index] = LookupTable[LookupTable.size()-1];
00281       else
00282         outPtr[index] = LookupTable[ (int)( (data - DataRange[0]) * InvDataRangeWidth ) ];
00283       
00284       outPtr[index].Alpha = 255;
00285       }
00286     }
00287 }
00288 
00289 void Colormap::Execute ()
00290 {
00291   if ( HaveUserMap ) 
00292     {
00293     // if user map exists, set table entry count to number of table entries.
00294     SegmentationLabelMap::const_iterator it = LabelColorMap.begin();
00295     int rangeFrom = it->first, rangeTo = it->first;
00296     while ( it != LabelColorMap.end() ) 
00297       {
00298       rangeFrom = std::min( rangeFrom, it->first );
00299       rangeTo = std::max( rangeTo, it->first );
00300       ++it;
00301       }
00302 
00303     TableEntries = (rangeTo - rangeFrom + 1);
00304     DataRange[0] = rangeFrom;
00305     DataRange[1] = rangeTo;
00306     } 
00307   else
00308     {
00309     TableEntries = 256;
00310     }
00311   
00312   LookupTable.resize( TableEntries );
00313   
00314   if ( DataRange[0] != DataRange[1] )
00315     InvDataRangeWidth = (1.0 * (TableEntries - 1)) / (DataRange[1] - DataRange[0]);
00316   else
00317     InvDataRangeWidth = 0;
00318   
00319   if ( HaveUserMap ) 
00320     {
00321     // if user map exists, build table.
00322     for ( size_t index = 0; index < LookupTable.size(); ++index ) 
00323       {
00324       SegmentationLabelMap::const_iterator it = LabelColorMap.find( index );
00325       if ( it != LabelColorMap.end() ) 
00326         {
00327         const byte* rgb = it->second.GetRGB();
00328         LookupTable[index].R = rgb[0];
00329         LookupTable[index].G = rgb[1];
00330         LookupTable[index].B = rgb[2];
00331         } 
00332       else
00333         {
00334         LookupTable[index].R = LookupTable[index].G = LookupTable[index].B = 0;
00335         }
00336       }
00337     } 
00338   else 
00339     {
00340     // if no user-defined map, create map from HSV ramps.
00341     Types::DataItem H = HueRange[0];
00342     const Types::DataItem Hstep = (HueRange[1] - HueRange[0]) / (LookupTable.size() - 1);
00343     
00344     Types::DataItem S = SaturationRange[0];
00345     const Types::DataItem Sstep = (SaturationRange[1] - SaturationRange[0]) / (LookupTable.size() - 1);
00346     
00347     Types::DataItem V = ValueRange[0];
00348     const Types::DataItem Vstep = (ValueRange[1] - ValueRange[0]) / (LookupTable.size() - 1);
00349     
00350     if ( Gamma > 0 ) 
00351       {
00352       for ( size_t index = 0; index < LookupTable.size(); ++index, H += Hstep, S += Sstep, V += Vstep ) 
00353         {
00354         if ( V > 0 ) 
00355           {
00356           Types::DataItem Vgamma = exp( log(V) * (1/Gamma) );
00357           HSV2RGB( LookupTable[index], H, S, Vgamma );
00358           } 
00359         else
00360           {
00361           HSV2RGB( LookupTable[index], H, S, V );
00362           }
00363         }
00364       } 
00365     else
00366       {
00367       for ( size_t index = 0; index < LookupTable.size(); ++index, H += Hstep, S += Sstep, V += Vstep ) 
00368         {
00369         HSV2RGB( LookupTable[index], H, S, V );
00370         }
00371       }
00372     }
00373 }
00374 
00375 void Colormap::HSV2RGB( RGB& rgb, Types::DataItem H, Types::DataItem S, Types::DataItem V )
00376 {
00377   const Types::DataItem max = 1.0;
00378   const Types::DataItem third = 1.0 / 3.0;
00379 
00380   Types::DataItem R, G, B;
00381   // compute rgb assuming S = 1.0;
00382   if (H >= 0.0 && H <= third) 
00383     { // red -> green
00384     G = H/third;
00385     R = 1.0 - G;
00386     B = 0.0;
00387     } 
00388   else
00389     if (H >= third && H <= 2.0*third) 
00390       { // green -> blue
00391       B = (H - third)/third;
00392       G = 1.0 - B;
00393       R = 0.0;
00394       } 
00395     else
00396       { // blue -> red
00397       R = (H - 2.0 * third)/third;
00398       B = 1.0 - R;
00399       G = 0.0;
00400       }
00401   
00402   // add Saturation to the equation.
00403   S = S / max;
00404   
00405   (R *= S) += (1.0 - S);
00406   (G *= S) += (1.0 - S);
00407   (B *= S) += (1.0 - S);
00408   
00409   // Use value to get actual RGB 
00410   // normalize RGB first then apply value
00411   V = 3 * V / (R + G + B);
00412   R *= V;
00413   G *= V;
00414   B *= V;
00415   
00416   if (R > max) R = max;
00417   if (G > max) G = max;
00418   if (B > max) B = max;
00419 
00420   rgb.R = static_cast<unsigned char>( floor(255 * R) );
00421   rgb.G = static_cast<unsigned char>( floor(255 * G) );
00422   rgb.B = static_cast<unsigned char>( floor(255 * B) );
00423 }
00424 
00425 } // namespace cmtk
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines