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