1 /*=========================================================================
2  *
3  *  Copyright Insight Software Consortium
4  *
5  *  Licensed under the Apache License, Version 2.0 (the "License");
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at
8  *
9  *         http://www.apache.org/licenses/LICENSE-2.0.txt
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  *
17  *=========================================================================*/
18 #ifndef itkColorTable_hxx
19 #define itkColorTable_hxx
20 
21 #include "itkColorTable.h"
22 #include "itkNumericTraits.h"
23 #include "vnl/vnl_sample.h"
24 
25 #include <sstream>
26 #include <iomanip>
27 
28 namespace itk
29 {
30 
31 template< typename TPixel >
32 void
33 ColorTable< TPixel >
DeleteColors()34 ::DeleteColors()
35 {
36   m_Color.resize(0);
37   m_ColorName.resize(0);
38 }
39 
40 template< typename TPixel >
41 void
42 ColorTable< TPixel >
UseDiscreteColors()43 ::UseDiscreteColors()
44 {
45   this->DeleteColors();
46 
47   m_NumberOfColors = 8;
48   m_Color.resize(m_NumberOfColors);
49   m_ColorName.resize(m_NumberOfColors);
50 
51   typename NumericTraits< TPixel >::RealType scale;
52   typename NumericTraits< TPixel >::RealType shift;
53   if (NumericTraits<TPixel>::is_integer)
54     {
55     scale =
56       static_cast< typename NumericTraits< TPixel >::RealType>(NumericTraits< TPixel >::max()) -
57       static_cast<  typename NumericTraits< TPixel >::RealType>(NumericTraits< TPixel >::NonpositiveMin());
58     shift =
59       static_cast<  typename NumericTraits< TPixel >::RealType>(NumericTraits< TPixel >::NonpositiveMin());
60     }
61   else
62     {
63     scale = NumericTraits< TPixel >::OneValue();
64     shift = NumericTraits< TPixel >::ZeroValue();
65     }
66 
67   m_Color[0].Set((TPixel)(0.9 * scale + shift),
68                  (TPixel)(              shift),
69                  (TPixel)(              shift) );
70   m_ColorName[0] = "Red";
71 
72   m_Color[1].Set((TPixel)(0.8 * scale + shift),
73                  (TPixel)(              shift),
74                  (TPixel)(0.8 * scale + shift));
75   m_ColorName[1] = "Purple";
76 
77   m_Color[2].Set((TPixel)(              shift),
78                  (TPixel)(0.8 * scale + shift),
79                  (TPixel)(0.8 * scale + shift));
80   m_ColorName[2] = "Aqua";
81 
82   m_Color[3].Set((TPixel)(0.8 * scale + shift),
83                  (TPixel)(0.8 * scale + shift),
84                  (TPixel)(              shift));
85   m_ColorName[3] = "Yellow";
86 
87   m_Color[4].Set((TPixel)(              shift),
88                  (TPixel)(0.9 * scale + shift),
89                  (TPixel)(              shift));
90   m_ColorName[4] = "Green";
91 
92   m_Color[5].Set((TPixel)(              shift),
93                  (TPixel)(              shift),
94                  (TPixel)(0.9 * scale + shift));
95   m_ColorName[5] = "Blue";
96 
97   m_Color[6].Set((TPixel)(0.7 * scale + shift),
98                  (TPixel)(0.7 * scale + shift),
99                  (TPixel)(0.7 * scale + shift));
100   m_ColorName[6] = "Grey0.70";
101   //
102   // to avoid numeric exception, need to make
103   // sure that the value assigned is clamped at
104   // max for TPixel.  Exceptions were happening
105   // on this assignment, even if realMax was
106   // set to NumericTraits<TPixel>::max().
107   typename NumericTraits< TPixel >::RealType
108     realMax(1.0 * scale + shift);
109   TPixel pixelMax(NumericTraits< TPixel >::max());
110   if(realMax < NumericTraits< TPixel >::max())
111     {
112     pixelMax = static_cast< TPixel >(realMax);
113     }
114   m_Color[7].Set(pixelMax,pixelMax,pixelMax);
115   m_ColorName[7] = "White";
116 }
117 
118 template< typename TPixel >
119 void
120 ColorTable< TPixel >
UseGrayColors(unsigned int n)121 ::UseGrayColors(unsigned int n)
122 {
123   unsigned int i;
124 
125   this->DeleteColors();
126 
127   m_NumberOfColors = n;
128   m_Color.resize(m_NumberOfColors);
129   m_ColorName.resize(m_NumberOfColors);
130 
131   typename NumericTraits< TPixel >::RealType range;
132   typename NumericTraits< TPixel >::RealType minimum;
133   if (NumericTraits<TPixel>::is_integer)
134     {
135     range =
136       static_cast< typename NumericTraits< TPixel >::RealType>(NumericTraits< TPixel >::max()) -
137       static_cast<  typename NumericTraits< TPixel >::RealType>(NumericTraits< TPixel >::NonpositiveMin());
138     minimum = NumericTraits< TPixel >::NonpositiveMin();
139     }
140   else
141     {
142     range = NumericTraits< TPixel >::OneValue();
143     minimum = NumericTraits< TPixel >::ZeroValue();
144     }
145   typename NumericTraits< TPixel >::RealType delta;
146   if (m_NumberOfColors > 1)
147     {
148     delta = range / ( m_NumberOfColors - 1 );
149     }
150   else
151     {
152     delta = 0.0;
153     }
154 
155   for ( i = 0; i < m_NumberOfColors; i++ )
156     {
157     typename NumericTraits< TPixel >::RealType
158       realGray( minimum + i * delta );
159 
160     TPixel gray = NumericTraits< TPixel >::max();
161     if( realGray < NumericTraits< TPixel >::max() )
162       {
163       gray = static_cast< TPixel >(realGray);
164       }
165 
166     m_Color[i].Set(gray, gray, gray);
167     std::ostringstream name;
168     name << "Gray" << std::fixed << std::setprecision(2)
169          << static_cast<float>(gray);
170     m_ColorName[i] = name.str();
171     }
172 }
173 
174 template< typename TPixel >
175 void
176 ColorTable< TPixel >
UseHeatColors(unsigned int n)177 ::UseHeatColors(unsigned int n)
178 {
179   unsigned int i;
180 
181   this->DeleteColors();
182 
183   m_NumberOfColors = n;
184   m_Color.resize(m_NumberOfColors);
185   m_ColorName.resize(m_NumberOfColors);
186 
187   typename NumericTraits< TPixel >::RealType scale;
188   typename NumericTraits< TPixel >::RealType shift;
189   if (NumericTraits<TPixel>::is_integer)
190     {
191     scale =
192       static_cast< typename NumericTraits< TPixel >::RealType>(NumericTraits< TPixel >::max()) -
193       static_cast<  typename NumericTraits< TPixel >::RealType>(NumericTraits< TPixel >::NonpositiveMin());
194     shift =
195       static_cast<  typename NumericTraits< TPixel >::RealType>(NumericTraits< TPixel >::NonpositiveMin());
196     }
197   else
198     {
199     scale = NumericTraits< TPixel >::OneValue();
200     shift = NumericTraits< TPixel >::ZeroValue();
201     }
202   for ( i = 0; i < n / 2.0; i++ )
203     {
204     //
205     // avoid overflow
206     typename NumericTraits < TPixel >::RealType
207       realR((( i + 1 ) / ( n / 2.0 + 1 ) ) * scale + shift);
208     TPixel r(NumericTraits< TPixel >::max());
209     if(realR < NumericTraits< TPixel >::max())
210       {
211       r = static_cast< TPixel >(realR);
212       }
213     auto g(static_cast<TPixel>( shift));
214     auto b(static_cast<TPixel>( shift));
215     m_Color[i].Set(r,g,b);
216     std::ostringstream name;
217     name << "Heat" << std::fixed << std::setprecision(2)
218          << i / static_cast<float>(n);
219     m_ColorName[i] = name.str();
220     }
221 
222   for ( i = 0; i < n / 2; i++ )
223     {
224     typename NumericTraits< TPixel >::RealType
225       rdouble(1.0 * scale + shift);
226     TPixel r(NumericTraits<TPixel>::max());
227     if( rdouble < NumericTraits<TPixel>::max() )
228       {
229       r = static_cast<TPixel>(rdouble);
230       }
231     auto g = static_cast<TPixel>((( i + 1 ) / ( n / 2.0 + 1 )) * scale + shift);
232     auto b = static_cast<TPixel>((( i + 1 ) / ( n / 2.0 + 1 )) * scale + shift);
233     m_Color[(size_t)(i + n / 2.0 )].Set(r,g,b);
234     std::ostringstream name;
235     name << "Heat" << std::fixed << std::setprecision(2)
236          << ( i + n / 2.0 ) / (float)n;
237     m_ColorName[static_cast<size_t>(( i + n / 2.0 ))] = name.str();
238     }
239 }
240 
241 template< typename TPixel >
242 void
243 ColorTable< TPixel >
UseRandomColors(unsigned int n)244 ::UseRandomColors(unsigned int n)
245 {
246   unsigned int i;
247 
248   this->DeleteColors();
249 
250   m_NumberOfColors = n;
251   m_Color.resize(m_NumberOfColors);
252   m_ColorName.resize(m_NumberOfColors);
253   TPixel r, g, b;
254   TPixel minimum, maximum;
255   if (NumericTraits<TPixel>::is_integer)
256     {
257     minimum = NumericTraits< TPixel >::NonpositiveMin();
258     maximum = NumericTraits< TPixel >::max();
259     }
260   else
261     {
262     minimum = NumericTraits< TPixel >::ZeroValue();
263     maximum  = NumericTraits< TPixel >::OneValue();
264     }
265   for ( i = 0; i < n; i++ )
266     {
267       r = static_cast< TPixel >( vnl_sample_uniform( minimum, maximum));
268     m_Color[i][0] = r;
269     g = static_cast< TPixel >( vnl_sample_uniform( minimum, maximum));
270     m_Color[i][1] = g;
271     b = static_cast< TPixel >( vnl_sample_uniform( minimum, maximum));
272     m_Color[i][2] = b;
273     std::ostringstream name;
274     name << "Random(" << std::fixed << std::setprecision(2)
275          << static_cast< float >( r ) << ","
276          << static_cast< float >( g ) << ","
277          << static_cast< float >( b ) << ")";
278     m_ColorName[i] = name.str();
279     }
280 }
281 
282 template< typename TPixel >
283 bool
284 ColorTable< TPixel >
SetColor(unsigned int c,RGBPixel<TPixel> pixel,const char * name)285 ::SetColor(unsigned int c, RGBPixel<TPixel> pixel, const char *name)
286 {
287   return this->SetColor(c, pixel[0], pixel[1], pixel[2], name);
288 }
289 
290 template< typename TPixel >
291 bool
292 ColorTable< TPixel >
SetColor(unsigned int c,TPixel r,TPixel g,TPixel b,const char * name)293 ::SetColor(unsigned int c, TPixel r, TPixel g, TPixel b, const char *name)
294 {
295   if ( c < m_NumberOfColors )
296     {
297     m_Color[c][0] = r;
298     m_Color[c][1] = g;
299     m_Color[c][2] = b;
300     m_ColorName[c] = name;
301     return true;
302     }
303   return false;
304 }
305 
306 template< typename TPixel >
307 RGBPixel< TPixel >
308 ColorTable< TPixel >
GetColor(unsigned int c)309 ::GetColor(unsigned int c)
310 {
311   if ( c < m_NumberOfColors )
312     {
313     return m_Color[c];
314     }
315   else
316     {
317     RGBPixel<TPixel> pixel;
318     pixel.Set(0, 0, 0);
319     return pixel;
320     }
321 }
322 
323 template< typename TPixel >
324 TPixel
325 ColorTable< TPixel >
GetColorComponent(unsigned int c,char rgb)326 ::GetColorComponent(unsigned int c, char rgb)
327 {
328   if ( c < m_NumberOfColors )
329     {
330     switch ( rgb )
331       {
332       case 'r':
333         {
334         return m_Color[c][0];
335         }
336       case 'g':
337         {
338         return m_Color[c][1];
339         }
340       case 'b':
341         {
342         return m_Color[c][2];
343         }
344       default:
345         {
346         return 0;
347         }
348       }
349     }
350   else
351     {
352     return 0;
353     }
354 }
355 
356 template< typename TPixel >
357 std::string
358 ColorTable< TPixel >
GetColorName(unsigned int c)359 ::GetColorName(unsigned int c)
360 {
361   if ( c < m_NumberOfColors )
362     {
363     return m_ColorName[c];
364     }
365   else
366     {
367     return "";
368     }
369 }
370 
371 template< typename TPixel >
372 unsigned int
373 ColorTable< TPixel >
GetClosestColorTableId(TPixel r,TPixel g,TPixel b)374 ::GetClosestColorTableId(TPixel r, TPixel g, TPixel b)
375 {
376   double       bestMatch = 0.0;
377   unsigned int bestMatchColor = 0;
378 
379   for ( unsigned int i = 0; i < m_NumberOfColors; i++ )
380     {
381     double match;
382     match = ( r - (double)m_Color[i].GetRed() )
383             * ( r - (double)m_Color[i].GetRed() );
384     match += ( g - (double)m_Color[i].GetGreen() )
385              * ( g - (double)m_Color[i].GetGreen() );
386     match += ( b - (double)m_Color[i].GetGreen() )
387              * ( b - (double)m_Color[i].GetBlue() );
388     if ( i == 0 || match < bestMatch )
389       {
390       bestMatch = match;
391       bestMatchColor = i;
392       }
393     }
394   return bestMatchColor;
395 }
396 
397 template< typename TPixel >
398 void
399 ColorTable< TPixel >
PrintSelf(std::ostream & os,Indent indent) const400 ::PrintSelf(std::ostream & os, Indent indent) const
401 {
402   Superclass::PrintSelf(os, indent);
403 
404   os << indent << "NumberOfColors = " << m_NumberOfColors << std::endl;
405   for ( unsigned int i = 0; i < m_NumberOfColors; i++ )
406     {
407     os << indent
408        << "ColorName[" << i << "] = " << m_ColorName[i] << ", "
409        << "Color[" << i << "] = " << m_Color[i] << std::endl;
410     }
411 }
412 } // namespace itk
413 
414 #endif
415