]> Creatis software - gdcm.git/blob - vtk/vtkImageMapToWindowLevelColors2.cxx
Fix mistypings
[gdcm.git] / vtk / vtkImageMapToWindowLevelColors2.cxx
1 /*=========================================================================
2
3   Program:   Visualization Toolkit
4   Module:    $RCSfile: vtkImageMapToWindowLevelColors2.cxx,v $
5
6   Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7   All rights reserved.
8   See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9
10      This software is distributed WITHOUT ANY WARRANTY; without even
11      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12      PURPOSE.  See the above copyright notice for more information.
13
14 =========================================================================*/
15 #include "vtkImageMapToWindowLevelColors2.h"
16
17 #include "vtkDataArray.h"
18 #include "vtkImageData.h"
19 #include "vtkInformation.h"
20 #include "vtkInformationVector.h"
21 #include "vtkObjectFactory.h"
22 #include "vtkScalarsToColors.h"
23 #include "vtkPointData.h"
24
25 vtkCxxRevisionMacro(vtkImageMapToWindowLevelColors2, "$Revision: 1.3 $")
26 vtkStandardNewMacro(vtkImageMapToWindowLevelColors2)
27
28 // Constructor sets default values
29 vtkImageMapToWindowLevelColors2::vtkImageMapToWindowLevelColors2()
30 {
31   this->Window = 255;
32   this->Level  = 127.5;
33 }
34
35 vtkImageMapToWindowLevelColors2::~vtkImageMapToWindowLevelColors2()
36 {
37 }
38
39 //----------------------------------------------------------------------------
40 // This method checks to see if we can simply reference the input data
41 int vtkImageMapToWindowLevelColors2::RequestData(
42   vtkInformation *request,
43   vtkInformationVector **inputVector,
44   vtkInformationVector *outputVector)
45 {
46   vtkInformation *outInfo = outputVector->GetInformationObject(0);
47   vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
48
49   vtkImageData *outData = vtkImageData::SafeDownCast(
50     outInfo->Get(vtkDataObject::DATA_OBJECT()));
51   vtkImageData *inData = vtkImageData::SafeDownCast(
52     inInfo->Get(vtkDataObject::DATA_OBJECT()));
53  
54   // If LookupTable is null and window / level produces no change,
55   // then just pass the data
56   if (this->LookupTable == NULL &&
57       (inData->GetScalarType() == VTK_UNSIGNED_CHAR &&
58        this->Window == 255 && this->Level == 127.5))
59     {
60     vtkDebugMacro("ExecuteData: LookupTable not set, "\
61                   "Window / Level at default, "\
62                   "passing input to output.");
63
64     outData->SetExtent(inData->GetExtent());
65     outData->GetPointData()->PassData(inData->GetPointData());
66     this->DataWasPassed = 1;
67     }
68   else
69     // normal behaviour - skip up a level since we don't want to
70     // call the superclasses ExecuteData - it would pass the data if there
71     // is no lookup table even if there is a window / level - wrong
72     // behavior.
73     {
74     if (this->DataWasPassed)
75       {
76       outData->GetPointData()->SetScalars(NULL);
77       this->DataWasPassed = 0;
78       }
79
80     return this->vtkThreadedImageAlgorithm::RequestData(request, inputVector,
81                                                         outputVector);
82     }
83
84   return 1;
85 }
86
87 //----------------------------------------------------------------------------
88 int vtkImageMapToWindowLevelColors2::RequestInformation (
89   vtkInformation *vtkNotUsed(request),
90   vtkInformationVector **inputVector,
91   vtkInformationVector *outputVector)
92 {
93   vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
94   vtkInformation *outInfo = outputVector->GetInformationObject(0);
95
96   vtkInformation *inScalarInfo = 
97     vtkDataObject::GetActiveFieldInformation(inInfo, 
98     vtkDataObject::FIELD_ASSOCIATION_POINTS, vtkDataSetAttributes::SCALARS);
99   if (!inScalarInfo)
100     {
101     vtkErrorMacro("Missing scalar field on input information!");
102     return 0;
103     }
104
105   // If LookupTable is null and window / level produces no change,
106   // then the data will be passed
107   if ( this->LookupTable == NULL &&
108        (inScalarInfo->Get(vtkDataObject::FIELD_ARRAY_TYPE()) == 
109         VTK_UNSIGNED_CHAR &&
110         this->Window == 255 && this->Level == 127.5) )
111     {
112     if (inScalarInfo->Get(vtkDataObject::FIELD_ARRAY_TYPE()) != 
113         VTK_UNSIGNED_CHAR)
114       {
115       vtkErrorMacro("ExecuteInformation: No LookupTable was set and input data is not VTK_UNSIGNED_CHAR!");
116       }
117     else
118       {
119       // no lookup table, pass the input if it was UNSIGNED_CHAR 
120       vtkDataObject::SetPointDataActiveScalarInfo
121         (outInfo, VTK_UNSIGNED_CHAR, 
122          inScalarInfo->Get(vtkDataObject::FIELD_NUMBER_OF_COMPONENTS()));
123       }
124     }
125   else  // the lookup table was set or window / level produces a change
126     {
127     int numComponents = 4;
128     switch (this->OutputFormat)
129       {
130       case VTK_RGBA:
131         numComponents = 4;
132         break;
133       case VTK_RGB:
134         numComponents = 3;
135         break;
136       case VTK_LUMINANCE_ALPHA:
137         numComponents = 2;
138         break;
139       case VTK_LUMINANCE:
140         numComponents = 1;
141         break;
142       default:
143         vtkErrorMacro("ExecuteInformation: Unrecognized color format.");
144         break;
145       }
146     vtkDataObject::SetPointDataActiveScalarInfo(outInfo, VTK_UNSIGNED_CHAR, numComponents);
147     }
148
149   return 1;
150 }
151
152 /* 
153  * This templated routine calculates effective lower and upper limits 
154  * for a window of values of type T, lower and upper. 
155  */
156 template <class T>
157 void vtkImageMapToWindowLevelClamps ( vtkImageData *data, double w, 
158                                       double l, T& lower, T& upper, 
159                                       unsigned char &lower_val, 
160                                       unsigned char &upper_val)
161 {
162   double f_lower, f_upper, f_lower_val, f_upper_val;
163   double adjustedLower, adjustedUpper;
164   double range[2];
165
166   data->GetPointData()->GetScalars()->GetDataTypeRange( range );
167
168   f_lower = l - fabs(w) / 2.0;
169   f_upper = f_lower + fabs(w);
170
171   // Set the correct lower value
172   if ( f_lower <= range[1])
173     {
174     if (f_lower >= range[0])
175       {
176       lower = (T) f_lower;
177       adjustedLower = f_lower;
178       }
179     else
180       {
181       lower = (T) range[0];
182       adjustedLower = range[0];
183       }
184     }
185   else
186     {
187     lower = (T) range[1];
188     adjustedLower = range[1];
189     }
190   
191   // Set the correct upper value
192   if ( f_upper >= range[0])
193     {
194     if (f_upper <= range[1])
195       {
196       upper = (T) f_upper;
197       adjustedUpper = f_upper;
198       }
199     else
200       {
201       upper = (T) range[1];
202       adjustedUpper = range[1];
203       }
204     }
205   else
206     {
207     upper = (T) range [0];
208     adjustedUpper = range [0];
209     }
210   
211   // now compute the lower and upper values
212   if (w >= 0)
213     {
214     f_lower_val = 255.0*(adjustedLower - f_lower)/w;
215     f_upper_val = 255.0*(adjustedUpper - f_lower)/w;
216     }
217   else
218     {
219     f_lower_val = 255.0 + 255.0*(adjustedLower - f_lower)/w;
220     f_upper_val = 255.0 + 255.0*(adjustedUpper - f_lower)/w;
221     }
222   
223   if (f_upper_val > 255) 
224     {
225     upper_val = 255;
226     }
227   else if (f_upper_val < 0)
228     {
229     upper_val = 0;
230     }
231   else
232     {
233     upper_val = (unsigned char)(f_upper_val);
234     }
235   
236   if (f_lower_val > 255) 
237     {
238     lower_val = 255;
239     }
240   else if (f_lower_val < 0)
241     {
242     lower_val = 0;
243     }
244   else
245     {
246     lower_val = (unsigned char)(f_lower_val);
247     }  
248 }
249
250 //----------------------------------------------------------------------------
251 // Small helper to do the clamp:
252 template <typename T>
253 void vtkClampHelper1(T* iptr, unsigned char *optr,
254   T lower, T upper,
255   unsigned char lower_val, unsigned char upper_val, 
256   double shift, double scale)
257 {
258   unsigned short ushort_val;
259   if (*iptr <= lower) 
260     {
261     ushort_val = lower_val;
262     }
263   else if (*iptr >= upper)
264     {
265     ushort_val = upper_val;
266     }
267   else
268     {
269     ushort_val = (unsigned char) ((*iptr + shift)*scale);
270     }
271   *optr = (unsigned char)((*optr * ushort_val) >> 8);
272 }
273
274 //----------------------------------------------------------------------------
275 template <typename T>
276 void vtkClampHelper2(T* iptr, unsigned char *optr,
277   T lower, T upper,
278   unsigned char lower_val, unsigned char upper_val, 
279   double shift, double scale)
280 {
281   unsigned char result_val;
282   if (*iptr <= lower) 
283     {
284     result_val = lower_val;
285     }
286   else if (*iptr >= upper)
287     {
288     result_val = upper_val;
289     }
290   else
291     {
292     result_val = (unsigned char) ((*iptr + shift)*scale);
293     }
294   *optr = result_val;
295 }
296
297 //----------------------------------------------------------------------------
298 // This non-templated function executes the filter for any type of data.
299 template <class T>
300 void vtkImageMapToWindowLevelColors2Execute(
301   vtkImageMapToWindowLevelColors2 *self, 
302   vtkImageData *inData, T *inPtr,
303   vtkImageData *outData, 
304   unsigned char *outPtr,
305   int outExt[6], int id)
306 {
307   int idxX, idxY, idxZ;
308   int extX, extY, extZ;
309   vtkIdType inIncX, inIncY, inIncZ;
310   vtkIdType outIncX, outIncY, outIncZ;
311   unsigned long count = 0;
312   unsigned long target;
313   int dataType = inData->GetScalarType();
314   int numberOfComponents,numberOfOutputComponents,outputFormat;
315   int rowLength;
316   vtkScalarsToColors *lookupTable = self->GetLookupTable();
317   unsigned char *outPtr1;
318   T *inPtr1;
319   unsigned char *optr;
320   T    *iptr;
321   double shift =  self->GetWindow() / 2.0 - self->GetLevel();
322   double scale = 255.0 / self->GetWindow();
323
324   T   lower, upper;
325   unsigned char lower_val, upper_val;
326   vtkImageMapToWindowLevelClamps( inData, self->GetWindow(), 
327                                   self->GetLevel(), 
328                                   lower, upper, lower_val, upper_val );
329   
330   // find the region to loop over
331   extX = outExt[1] - outExt[0] + 1;
332   extY = outExt[3] - outExt[2] + 1; 
333   extZ = outExt[5] - outExt[4] + 1;
334
335   target = (unsigned long)(extZ*extY/50.0);
336   target++;
337   
338   // Get increments to march through data 
339   inData->GetContinuousIncrements(outExt, inIncX, inIncY, inIncZ);
340
341   outData->GetContinuousIncrements(outExt, outIncX, outIncY, outIncZ);
342   numberOfComponents = inData->GetNumberOfScalarComponents();
343   numberOfOutputComponents = outData->GetNumberOfScalarComponents();
344   outputFormat = self->GetOutputFormat();
345   
346   rowLength = extX*numberOfComponents;
347
348   // Loop through output pixels
349   outPtr1 = outPtr;
350   inPtr1 = inPtr;
351   for (idxZ = 0; idxZ < extZ; idxZ++)
352     {
353     for (idxY = 0; !self->AbortExecute && idxY < extY; idxY++)
354       {
355       if (!id) 
356         {
357         if (!(count%target))
358           {
359           self->UpdateProgress(count/(50.0*target));
360           }
361         count++;
362         }
363       
364       iptr = inPtr1;
365       optr = outPtr1;
366       
367       if ( lookupTable )
368         {
369         lookupTable->MapScalarsThroughTable2(inPtr1,(unsigned char *)outPtr1,
370                                              dataType,extX,numberOfComponents,
371                                              outputFormat);
372       
373         for (idxX = 0; idxX < extX; idxX++)
374           {
375           vtkClampHelper1<T>(iptr,optr,lower,upper,lower_val,upper_val,shift,scale);
376           switch (outputFormat)
377             {
378             case VTK_RGBA:
379               vtkClampHelper1<T>(iptr+(1%numberOfComponents),optr+1,lower,upper,lower_val,upper_val,shift,scale);
380               vtkClampHelper1<T>(iptr+(2%numberOfComponents),optr+2,lower,upper,lower_val,upper_val,shift,scale);
381               *(optr+3) = 255;
382               break;
383             case VTK_RGB:
384               vtkClampHelper1<T>(iptr+(1%numberOfComponents),optr+1,lower,upper,lower_val,upper_val,shift,scale);
385               vtkClampHelper1<T>(iptr+(2%numberOfComponents),optr+2,lower,upper,lower_val,upper_val,shift,scale);
386               break;
387             case VTK_LUMINANCE_ALPHA:
388               *(optr+1) = 255;
389               break;
390             }
391           iptr += numberOfComponents;
392           optr += numberOfOutputComponents;
393           }
394         }
395       else
396         {
397         for (idxX = 0; idxX < extX; idxX++)
398           {
399           // We want to shift to the right position depending on the numberOfComponents from input
400           // if grayscale we should stay at the same position, otherwise need to shift to r,g,b
401           // (0%numberOfComponents) == 0 ...
402           // (1%numberOfComponents) == 0 or 1
403           vtkClampHelper2<T>(iptr,optr,lower,upper,lower_val,upper_val,shift,scale);
404           switch (outputFormat)
405             {
406             case VTK_RGBA:
407               vtkClampHelper2<T>(iptr+(1%numberOfComponents),optr+1,lower,upper,lower_val,upper_val,shift,scale);
408               vtkClampHelper2<T>(iptr+(2%numberOfComponents),optr+2,lower,upper,lower_val,upper_val,shift,scale);
409               *(optr+3) = 255;
410               break;
411             case VTK_RGB:
412               vtkClampHelper2<T>(iptr+(1%numberOfComponents),optr+1,lower,upper,lower_val,upper_val,shift,scale);
413               vtkClampHelper2<T>(iptr+(2%numberOfComponents),optr+2,lower,upper,lower_val,upper_val,shift,scale);
414               break;
415             case VTK_LUMINANCE_ALPHA:
416               *(optr+1) = 255;
417               break;
418             }
419           iptr += numberOfComponents;
420           optr += numberOfOutputComponents;
421           }
422         }      
423       outPtr1 += outIncY + extX*numberOfOutputComponents;
424       inPtr1 += inIncY + rowLength;
425       }
426     outPtr1 += outIncZ;
427     inPtr1 += inIncZ;
428     }
429 }
430
431 //----------------------------------------------------------------------------
432 // This method is passed a input and output data, and executes the filter
433 // algorithm to fill the output from the input.
434
435 void vtkImageMapToWindowLevelColors2::ThreadedRequestData(
436   vtkInformation *vtkNotUsed(request),
437   vtkInformationVector **vtkNotUsed(inputVector),
438   vtkInformationVector *vtkNotUsed(outputVector),
439   vtkImageData ***inData,
440   vtkImageData **outData,
441   int outExt[6], int id)
442 {
443   void *inPtr = inData[0][0]->GetScalarPointerForExtent(outExt);
444   void *outPtr = outData[0]->GetScalarPointerForExtent(outExt);
445   
446   switch (inData[0][0]->GetScalarType())
447     {
448     vtkTemplateMacro(
449       vtkImageMapToWindowLevelColors2Execute( this, 
450                                              inData[0][0], 
451                                              (VTK_TT *)(inPtr), 
452                                              outData[0], 
453                                              (unsigned char *)(outPtr), 
454                                              outExt, 
455                                              id));
456     default:
457       vtkErrorMacro(<< "Execute: Unknown ScalarType");
458       return;
459     }
460 }
461
462 //----------------------------------------------------------------------------
463 void vtkImageMapToWindowLevelColors2::PrintSelf(ostream& os, vtkIndent indent)
464 {
465   this->Superclass::PrintSelf(os,indent);
466
467   os << indent << "Window: " << this->Window << endl;
468   os << indent << "Level: " << this->Level << endl;
469 }