00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
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
00080 if ( study->GetHaveUserColorMap() )
00081 {
00082 LabelColorMap = study->GetUserLabelMap();
00083 }
00084
00085
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
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
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
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
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
00382 if (H >= 0.0 && H <= third)
00383 {
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 {
00391 B = (H - third)/third;
00392 G = 1.0 - B;
00393 R = 0.0;
00394 }
00395 else
00396 {
00397 R = (H - 2.0 * third)/third;
00398 B = 1.0 - R;
00399 G = 0.0;
00400 }
00401
00402
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
00410
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 }