1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkImageQuantizeRGBToIndex.cxx
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 "vtkImageQuantizeRGBToIndex.h"
16 
17 #include "vtkImageData.h"
18 #include "vtkInformation.h"
19 #include "vtkInformationVector.h"
20 #include "vtkLookupTable.h"
21 #include "vtkObjectFactory.h"
22 #include "vtkStreamingDemandDrivenPipeline.h"
23 #include "vtkTimerLog.h"
24 
25 #include "vtkExtractVOI.h"
26 #include "vtkImageLuminance.h"
27 #include "vtkSmartPointer.h"
28 
29 #include <cmath>
30 
31 vtkStandardNewMacro(vtkImageQuantizeRGBToIndex);
32 
33 class vtkColorQuantizeNode
34 {
35 public:
vtkColorQuantizeNode()36   vtkColorQuantizeNode()
37   {
38     this->Axis = -1;
39     this->SplitPoint = -1;
40     this->Index = -1;
41     this->Child1 = nullptr;
42     this->Child2 = nullptr;
43     this->StdDev[0] = this->StdDev[1] = this->StdDev[2] = 0.0;
44     this->Histogram[0] = this->Histogram[1] = this->Histogram[2] = nullptr;
45     this->Image = nullptr;
46     this->Bounds[0] = 0;
47     this->Bounds[1] = 256;
48     this->Bounds[2] = 0;
49     this->Bounds[3] = 256;
50     this->Bounds[4] = 0;
51     this->Bounds[5] = 256;
52   }
53 
~vtkColorQuantizeNode()54   ~vtkColorQuantizeNode()
55   {
56     delete[] this->Histogram[0];
57     delete[] this->Histogram[1];
58     delete[] this->Histogram[2];
59     delete this->Child1;
60     delete this->Child2;
61   }
62 
SetImageExtent(int v[6])63   void SetImageExtent(int v[6]) { memcpy(this->ImageExtent, v, 6 * sizeof(int)); }
64 
SetImageIncrement(vtkIdType v[3])65   void SetImageIncrement(vtkIdType v[3]) { memcpy(this->ImageIncrement, v, 3 * sizeof(vtkIdType)); }
66 
SetImageType(double type)67   void SetImageType(double type) { this->ImageType = static_cast<int>(type); }
68 
SetImage(void * image)69   void SetImage(void* image) { this->Image = image; }
70 
SetAxis(int v)71   void SetAxis(int v) { this->Axis = v; }
GetAxis()72   int GetAxis() { return this->Axis; }
73 
SetSplitPoint(int v)74   void SetSplitPoint(int v) { this->SplitPoint = v; }
GetSplitPoint()75   int GetSplitPoint() { return this->SplitPoint; }
76 
GetBounds()77   int* GetBounds() { return this->Bounds; }
SetBounds(int v[6])78   void SetBounds(int v[6]) { memcpy(this->Bounds, v, 6 * sizeof(int)); }
79 
SetIndex(int v)80   void SetIndex(int v) { this->Index = v; }
GetIndex()81   int GetIndex() { return this->Index; }
82 
GetStdDev(int axis)83   double GetStdDev(int axis) { return this->StdDev[axis]; }
84   void ComputeStdDev();
85 
GetCount()86   int GetCount() { return this->Count; }
87 
GetMean(int axis)88   double GetMean(int axis) { return this->Mean[axis]; }
GetMean(double c[3])89   void GetMean(double c[3])
90   {
91     c[0] = this->Mean[0];
92     c[1] = this->Mean[1];
93     c[2] = this->Mean[2];
94   }
95 
96   void Divide(int axis, int nextIndex);
97 
SetChild1(vtkColorQuantizeNode * n)98   void SetChild1(vtkColorQuantizeNode* n) { this->Child1 = n; }
GetChild1()99   vtkColorQuantizeNode* GetChild1() { return this->Child1; }
100 
SetChild2(vtkColorQuantizeNode * n)101   void SetChild2(vtkColorQuantizeNode* n) { this->Child2 = n; }
GetChild2()102   vtkColorQuantizeNode* GetChild2() { return this->Child2; }
103 
GetIndex(int c[3])104   int GetIndex(int c[3])
105   {
106     if (this->Index >= 0)
107     {
108       return this->Index;
109     }
110     if (c[this->Axis] > this->SplitPoint)
111     {
112       return this->Child2->GetIndex(c);
113     }
114     return this->Child1->GetIndex(c);
115   }
116 
GetAverageColor(int c[3])117   void GetAverageColor(int c[3])
118   {
119     if (this->AverageCount)
120     {
121       c[0] = static_cast<int>(this->AverageColor[0] / this->AverageCount);
122       c[1] = static_cast<int>(this->AverageColor[1] / this->AverageCount);
123       c[2] = static_cast<int>(this->AverageColor[2] / this->AverageCount);
124     }
125   }
126 
StartColorAveraging()127   void StartColorAveraging()
128   {
129     if (this->Child1)
130     {
131       this->Child1->StartColorAveraging();
132       this->Child2->StartColorAveraging();
133     }
134     else
135     {
136       this->AverageCount = 0;
137       this->AverageColor[0] = 0.0;
138       this->AverageColor[1] = 0.0;
139       this->AverageColor[2] = 0.0;
140     }
141   }
142 
AddColor(int c[3])143   void AddColor(int c[3])
144   {
145     this->AverageCount++;
146     this->AverageColor[0] += c[0];
147     this->AverageColor[1] += c[1];
148     this->AverageColor[2] += c[2];
149   }
150 
151 protected:
152   int Axis;
153   int SplitPoint;
154   int Bounds[6];
155   int Index;
156   double StdDev[3];
157   double Median[3];
158   double Mean[3];
159   int Count;
160   int AverageCount;
161   double AverageColor[3];
162   vtkIdType ImageIncrement[3];
163   int ImageExtent[6];
164   int ImageType;
165   void* Image;
166   int* Histogram[3];
167   vtkColorQuantizeNode *Child1, *Child2;
168 };
169 
170 template <class T>
vtkImageQuantizeRGBToIndexHistogram(T * inPtr,int extent[6],vtkIdType inIncrement[3],int type,int bounds[6],int * histogram[3])171 void vtkImageQuantizeRGBToIndexHistogram(
172   T* inPtr, int extent[6], vtkIdType inIncrement[3], int type, int bounds[6], int* histogram[3])
173 {
174   T *rgbPtr, v[3];
175   int x, y, z, c;
176   int value[3];
177   int max[3];
178 
179   max[0] = bounds[1] - bounds[0] + 1;
180   max[1] = bounds[3] - bounds[2] + 1;
181   max[2] = bounds[5] - bounds[4] + 1;
182 
183   for (c = 0; c < 3; c++)
184   {
185     for (x = 0; x < max[c]; x++)
186     {
187       histogram[c][x] = 0;
188     }
189   }
190 
191   // Generate the histogram
192   rgbPtr = inPtr;
193   for (z = extent[4]; z <= extent[5]; z++)
194   {
195     for (y = extent[2]; y <= extent[3]; y++)
196     {
197       for (x = extent[0]; x <= extent[1]; x++)
198       {
199         if (type == VTK_UNSIGNED_CHAR)
200         {
201           v[0] = *(rgbPtr++) - bounds[0];
202           v[1] = *(rgbPtr++) - bounds[2];
203           v[2] = *(rgbPtr++) - bounds[4];
204           if (static_cast<int>(v[0]) < max[0] && static_cast<int>(v[1]) < max[1] &&
205             static_cast<int>(v[2]) < max[2])
206           {
207             histogram[0][static_cast<unsigned char>(v[0])]++;
208             histogram[1][static_cast<unsigned char>(v[1])]++;
209             histogram[2][static_cast<unsigned char>(v[2])]++;
210           }
211         }
212         else if (type == VTK_UNSIGNED_SHORT)
213         {
214           v[0] = ((static_cast<unsigned short>(*(rgbPtr++))) >> 8) - bounds[0];
215           v[1] = ((static_cast<unsigned short>(*(rgbPtr++))) >> 8) - bounds[2];
216           v[2] = ((static_cast<unsigned short>(*(rgbPtr++))) >> 8) - bounds[4];
217           if (static_cast<int>(v[0]) < max[0] && static_cast<int>(v[1]) < max[1] &&
218             static_cast<int>(v[2]) < max[2])
219           {
220             histogram[0][static_cast<unsigned short>(v[0])]++;
221             histogram[1][static_cast<unsigned short>(v[1])]++;
222             histogram[2][static_cast<unsigned short>(v[2])]++;
223           }
224         }
225         else
226         {
227           value[0] = static_cast<int>(*(rgbPtr++) * 255.5) - bounds[0];
228           value[1] = static_cast<int>(*(rgbPtr++) * 255.5) - bounds[2];
229           value[2] = static_cast<int>(*(rgbPtr++) * 255.5) - bounds[4];
230           if (static_cast<int>(value[0]) < max[0] && static_cast<int>(value[1]) < max[1] &&
231             static_cast<int>(value[2]) < max[2])
232           {
233             histogram[0][value[0]]++;
234             histogram[1][value[1]]++;
235             histogram[2][value[2]]++;
236           }
237         }
238         rgbPtr += inIncrement[0];
239       }
240       rgbPtr += inIncrement[1];
241     }
242     rgbPtr += inIncrement[2];
243   }
244 }
245 
246 // This templated function executes the filter for supported types of data.
247 template <class T>
vtkImageQuantizeRGBToIndexExecute(vtkImageQuantizeRGBToIndex * self,vtkImageData * inData,vtkImageData * outData)248 void vtkImageQuantizeRGBToIndexExecute(
249   vtkImageQuantizeRGBToIndex* self, vtkImageData* inData, vtkImageData* outData)
250 {
251   int extent[6];
252   vtkIdType inIncrement[3], outIncrement[3];
253   T* rgbPtr;
254   unsigned short* indexPtr;
255   int x, y, z, c;
256   int type;
257   vtkColorQuantizeNode *root, *tmp;
258   vtkColorQuantizeNode* leafNodes[65536];
259   int numLeafNodes;
260   int maxdevAxis = 0, maxdevLeafNode = 0;
261   double maxdev, dev;
262   int leaf, axis;
263   int cannotDivideFurther;
264   vtkLookupTable* lut;
265   double color[4];
266   int rgb[3];
267   vtkTimerLog* timer;
268   vtkIdType totalCount;
269   double weight;
270 
271   timer = vtkTimerLog::New();
272   timer->StartTimer();
273   type = self->GetInputType();
274 
275   // need extent to get increments.
276   // in and out extents are the same
277   inData->GetExtent(extent);
278 
279   inData->GetContinuousIncrements(extent, inIncrement[0], inIncrement[1], inIncrement[2]);
280   outData->GetContinuousIncrements(extent, outIncrement[0], outIncrement[1], outIncrement[2]);
281 
282   timer->StopTimer();
283 
284   self->SetInitializeExecuteTime(timer->GetElapsedTime());
285   timer->StartTimer();
286 
287   vtkImageData* image_sample = inData;
288   auto sampler =
289     vtkSmartPointer<vtkExtractVOI>::New(); // outside of scope to keep samples image alive
290   if (self->GetSamplingRate()[0] > 1 || self->GetSamplingRate()[1] > 1 ||
291     self->GetSamplingRate()[2] > 1)
292   {
293     // The idea behind this sampling is to build the octree
294     // with mean colors using a subset of the image data, potentially
295     // allowing a significant speedup.
296     sampler->SetInputData(inData);
297     sampler->SetVOI(inData->GetExtent());
298     sampler->SetSampleRate(self->GetSamplingRate());
299     sampler->Update();
300     image_sample = sampler->GetOutput();
301   }
302 
303   auto inPtrSampled = static_cast<T*>(image_sample->GetScalarPointer());
304   auto inPtr = static_cast<T*>(inData->GetScalarPointer());
305   auto outPtr = static_cast<unsigned short*>(outData->GetScalarPointer());
306 
307   int extentSampled[6];
308   vtkIdType incSampled[3];
309   image_sample->GetExtent(extentSampled);
310   image_sample->GetContinuousIncrements(extentSampled, incSampled[0], incSampled[1], incSampled[2]);
311 
312   // Build the tree
313   // Create the root node - it is our only leaf node
314   root = new vtkColorQuantizeNode;
315   root->SetIndex(0);
316   root->SetImageExtent(extentSampled);
317   root->SetImageIncrement(incSampled);
318   root->SetImageType(type);
319   root->SetImage(inPtrSampled);
320   root->ComputeStdDev();
321   leafNodes[0] = root;
322   numLeafNodes = 1;
323 
324   cannotDivideFurther = 0;
325 
326   totalCount = extentSampled[1] - extentSampled[0] + 1;
327   totalCount *= extentSampled[3] - extentSampled[2] + 1;
328   totalCount *= extentSampled[5] - extentSampled[4] + 1;
329 
330   // Loop until we've added enough leaf nodes or we can't add any more
331   // Here we are using sampled image (VOI).
332   while (numLeafNodes < self->GetNumberOfColors() && !cannotDivideFurther)
333   {
334     // Find leaf node / axis with maximum deviation
335     maxdev = 0.0;
336     for (leaf = 0; leaf < numLeafNodes; leaf++)
337     {
338       for (axis = 0; axis < 3; axis++)
339       {
340         dev = leafNodes[leaf]->GetStdDev(axis);
341         weight = static_cast<double>(leafNodes[leaf]->GetCount()) / static_cast<double>(totalCount);
342         dev *= weight;
343         if (dev > maxdev)
344         {
345           maxdevAxis = axis;
346           maxdevLeafNode = leaf;
347           maxdev = dev;
348         }
349       }
350     }
351     if (maxdev == 0.0)
352     {
353       cannotDivideFurther = 1;
354     }
355     else
356     {
357       leafNodes[maxdevLeafNode]->Divide(maxdevAxis, numLeafNodes);
358       leafNodes[numLeafNodes] = leafNodes[maxdevLeafNode]->GetChild1();
359       leafNodes[maxdevLeafNode] = leafNodes[maxdevLeafNode]->GetChild2();
360       numLeafNodes++;
361     }
362 
363     self->UpdateProgress(0.6667 * numLeafNodes / self->GetNumberOfColors());
364   }
365 
366   timer->StopTimer();
367   self->SetBuildTreeExecuteTime(timer->GetElapsedTime());
368   timer->StartTimer();
369 
370   root->StartColorAveraging();
371 
372   // Sort color indices by luminance
373   // The "index-image" viewed as a greyscale image, is usually quite
374   // arbitrary, accentuating contrast where none can be perceived in
375   // the original color image.
376   // To make the index image more meaningful, we sort the mean colors
377   // by luminance (mapping the indices accordingly).
378   if (self->GetSortIndexByLuminance())
379   {
380     std::vector<std::pair<double, int>> luminance_index_map;
381     double RGB[3];
382     for (leaf = 0; leaf < numLeafNodes; leaf++)
383     {
384       leafNodes[leaf]->GetMean(RGB);
385       double luminance = 0.30 * RGB[0] + 0.59 * RGB[1] + 0.11 * RGB[2];
386       int index = leafNodes[leaf]->GetIndex();
387       luminance_index_map.emplace_back(luminance, index);
388     }
389     std::sort(luminance_index_map.begin(), luminance_index_map.end());
390     std::vector<int> index_map(luminance_index_map.size());
391     for (size_t i = 0; i < luminance_index_map.size(); ++i)
392     {
393       index_map.at(luminance_index_map[i].second) = static_cast<int>(i);
394     }
395     for (leaf = 0; leaf < numLeafNodes; leaf++)
396     {
397       int index = leafNodes[leaf]->GetIndex();
398       leafNodes[leaf]->SetIndex(index_map.at(index));
399     }
400   }
401 
402   // Fill in the indices in the output image
403   indexPtr = outPtr;
404   rgbPtr = inPtr;
405   for (z = extent[4]; z <= extent[5]; z++)
406   {
407     for (y = extent[2]; !self->AbortExecute && y <= extent[3]; y++)
408     {
409       for (x = extent[0]; x <= extent[1]; x++)
410       {
411         for (c = 0; c < 3; c++)
412         {
413           if (type == VTK_UNSIGNED_CHAR)
414           {
415             rgb[c] = static_cast<int>(*rgbPtr);
416           }
417           else if (type == VTK_UNSIGNED_SHORT)
418           {
419             rgb[c] = (static_cast<unsigned short>(*rgbPtr)) >> 8;
420           }
421           else
422           {
423             rgb[c] = static_cast<int>(*rgbPtr * 255.5);
424           }
425           rgbPtr++;
426         }
427         tmp = root;
428         while (true)
429         {
430           if (tmp->GetIndex() != -1)
431           {
432             *indexPtr = tmp->GetIndex();
433             break;
434           }
435           if (rgb[tmp->GetAxis()] > tmp->GetSplitPoint())
436           {
437             tmp = tmp->GetChild2();
438           }
439           else
440           {
441             tmp = tmp->GetChild1();
442           }
443         }
444         tmp->AddColor(rgb);
445         indexPtr++;
446 
447         rgbPtr += inIncrement[0];
448         indexPtr += outIncrement[0];
449       }
450       rgbPtr += inIncrement[1];
451       indexPtr += outIncrement[1];
452     }
453     rgbPtr += inIncrement[2];
454     indexPtr += outIncrement[2];
455   }
456 
457   self->UpdateProgress(0.90);
458 
459   // Fill in the lookup table
460   lut = self->GetLookupTable();
461   lut->SetNumberOfTableValues(numLeafNodes);
462   lut->SetNumberOfColors(numLeafNodes);
463   lut->SetTableRange(0, numLeafNodes - 1);
464   color[3] = 1.0;
465   for (leaf = 0; leaf < numLeafNodes; leaf++)
466   {
467     leafNodes[leaf]->GetAverageColor(rgb);
468     color[0] = rgb[0] / 255.0;
469     color[1] = rgb[1] / 255.0;
470     color[2] = rgb[2] / 255.0;
471     lut->SetTableValue(leafNodes[leaf]->GetIndex(), color);
472   }
473 
474   timer->StopTimer();
475   self->SetLookupIndexExecuteTime(timer->GetElapsedTime());
476   timer->Delete();
477 
478   delete root;
479 }
480 
ComputeStdDev()481 void vtkColorQuantizeNode::ComputeStdDev()
482 {
483   int i, j;
484   double mean;
485   int count = 0;
486   int medianCount;
487 
488   // Create space for histogram
489   this->Histogram[0] = new int[this->Bounds[1] - this->Bounds[0] + 1];
490   this->Histogram[1] = new int[this->Bounds[3] - this->Bounds[2] + 1];
491   this->Histogram[2] = new int[this->Bounds[5] - this->Bounds[4] + 1];
492 
493   // Create histogram
494   switch (this->ImageType)
495   {
496     vtkTemplateMacro(vtkImageQuantizeRGBToIndexHistogram(static_cast<VTK_TT*>(this->Image),
497       this->ImageExtent, this->ImageIncrement, this->ImageType, this->Bounds, this->Histogram));
498   }
499 
500   // Compute for r, g, and b
501   for (i = 0; i < 3; i++)
502   {
503     // Compute the mean
504     mean = 0;
505     count = 0;
506     for (j = 0; j <= (this->Bounds[i * 2 + 1] - this->Bounds[i * 2]); j++)
507     {
508       count += this->Histogram[i][j];
509       mean += this->Histogram[i][j] * (j + this->Bounds[i * 2]);
510     }
511     if (count > 0)
512     {
513       mean /= static_cast<double>(count);
514     }
515     else
516     {
517       mean = 0;
518     }
519     this->Mean[i] = mean;
520 
521     // Must have some minimum distance to subdivide - if we
522     // are below this distance limit, don't compute a
523     // standard deviation since we don't want to subdivide this
524     // node along this axis. Set the deviation to 0.0 and continue.
525     if (this->Bounds[i * 2 + 1] == this->Bounds[i * 2])
526     {
527       this->StdDev[i] = 0.0;
528       continue;
529     }
530 
531     // Where is the median?
532     medianCount = count / 2;
533 
534     // Initialize the median to unset
535     this->Median[i] = -1;
536 
537     // Compute the standard deviation and the location of the median
538     this->StdDev[i] = 0;
539     count = 0;
540     for (j = 0; j <= (this->Bounds[i * 2 + 1] - this->Bounds[i * 2]); j++)
541     {
542       count += this->Histogram[i][j];
543       this->StdDev[i] += static_cast<double>(this->Histogram[i][j]) *
544         (static_cast<double>(j) + this->Bounds[i * 2] - mean) *
545         (static_cast<double>(j) + this->Bounds[i * 2] - mean);
546       if (this->Median[i] == -1 && count > medianCount)
547       {
548         this->Median[i] = j + this->Bounds[i * 2];
549       }
550     }
551 
552     // If our median is at the upper bound, bump down by one. This will
553     // help in the cases where we have a distance of 2 in this dimension,
554     // and just over half the entries are in the second bucket. We
555     // still want to divide - the division needs to be at the first
556     // bucket.
557     if (this->Median[i] == this->Bounds[i * 2 + 1])
558     {
559       this->Median[i]--;
560     }
561 
562     // Do the final division and square root to get the standard deviation
563     if (count > 0)
564     {
565       this->StdDev[i] /= static_cast<double>(count);
566     }
567     else
568     {
569       this->StdDev[i] = 0;
570     }
571 
572     this->StdDev[i] = sqrt(this->StdDev[i]);
573   }
574 
575   // Should all be the same - just take the last one
576   this->Count = count;
577 }
578 
Divide(int axis,int nextIndex)579 void vtkColorQuantizeNode::Divide(int axis, int nextIndex)
580 {
581   int newBounds[6];
582 
583   this->Child1 = new vtkColorQuantizeNode;
584   this->Child2 = new vtkColorQuantizeNode;
585 
586   memcpy(newBounds, this->Bounds, 6 * sizeof(int));
587 
588   newBounds[axis * 2 + 1] = static_cast<int>(this->Median[axis]);
589   this->Child1->SetBounds(newBounds);
590 
591   newBounds[axis * 2] = static_cast<int>(this->Median[axis] + 1);
592   newBounds[axis * 2 + 1] = static_cast<int>(this->Bounds[axis * 2 + 1]);
593   this->Child2->SetBounds(newBounds);
594 
595   this->SplitPoint = static_cast<int>(this->Median[axis]);
596   this->Axis = axis;
597 
598   this->Child1->SetIndex(this->Index);
599   this->Child2->SetIndex(nextIndex);
600   this->Index = -1;
601 
602   delete[] this->Histogram[0];
603   delete[] this->Histogram[1];
604   delete[] this->Histogram[2];
605 
606   this->Histogram[0] = nullptr;
607   this->Histogram[1] = nullptr;
608   this->Histogram[2] = nullptr;
609 
610   this->Child1->SetImageExtent(this->ImageExtent);
611   this->Child1->SetImageIncrement(this->ImageIncrement);
612   this->Child1->SetImageType(this->ImageType);
613   this->Child1->SetImage(this->Image);
614 
615   this->Child2->SetImageExtent(this->ImageExtent);
616   this->Child2->SetImageIncrement(this->ImageIncrement);
617   this->Child2->SetImageType(this->ImageType);
618   this->Child2->SetImage(this->Image);
619 
620   this->Child1->ComputeStdDev();
621   this->Child2->ComputeStdDev();
622 }
623 
624 // Constructor sets default values
vtkImageQuantizeRGBToIndex()625 vtkImageQuantizeRGBToIndex::vtkImageQuantizeRGBToIndex()
626 {
627   this->LookupTable = vtkLookupTable::New();
628   this->NumberOfColors = 256;
629   this->InputType = VTK_UNSIGNED_SHORT;
630 
631   this->InitializeExecuteTime = 0.0;
632   this->BuildTreeExecuteTime = 0.0;
633   this->LookupIndexExecuteTime = 0.0;
634   this->SamplingRate[0] = 1;
635   this->SamplingRate[1] = 1;
636   this->SamplingRate[2] = 1;
637   this->SortIndexByLuminance = false;
638 }
639 
640 // Destructor deletes used resources
~vtkImageQuantizeRGBToIndex()641 vtkImageQuantizeRGBToIndex::~vtkImageQuantizeRGBToIndex()
642 {
643   if (this->LookupTable)
644   {
645     this->LookupTable->Delete();
646   }
647 }
648 
649 // This method is passed an input and output Data, and executes the filter
650 // algorithm to fill the output from the input.
651 // It just executes a switch statement to call the correct function for
652 // the Datas data types.
RequestData(vtkInformation * vtkNotUsed (request),vtkInformationVector ** inputVector,vtkInformationVector * outputVector)653 int vtkImageQuantizeRGBToIndex::RequestData(vtkInformation* vtkNotUsed(request),
654   vtkInformationVector** inputVector, vtkInformationVector* outputVector)
655 {
656   vtkInformation* inInfo = inputVector[0]->GetInformationObject(0);
657   vtkInformation* outInfo = outputVector->GetInformationObject(0);
658 
659   vtkImageData* inData = vtkImageData::SafeDownCast(inInfo->Get(vtkDataObject::DATA_OBJECT()));
660   vtkImageData* outData = vtkImageData::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT()));
661 
662   outData->SetExtent(outInfo->Get(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT()));
663   outData->AllocateScalars(outInfo);
664 
665   int inExt[6];
666   inData->GetExtent(inExt);
667   if (inExt[1] < inExt[0] || inExt[3] < inExt[2] || inExt[5] < inExt[4])
668   {
669     return 1;
670   }
671 
672   // Input must be 3 components (rgb)
673   if (inData->GetNumberOfScalarComponents() != 3)
674   {
675     vtkErrorMacro("This filter can handles only 3 components");
676     return 1;
677   }
678 
679   // this filter expects that output is type unsigned short.
680   if (outData->GetScalarType() != VTK_UNSIGNED_SHORT)
681   {
682     vtkErrorMacro(<< "Execute: out ScalarType " << outData->GetScalarType()
683                   << " must be unsigned short\n");
684     return 1;
685   }
686 
687   this->InputType = inData->GetScalarType();
688 
689   switch (this->InputType)
690   {
691     vtkTemplateMacro(vtkImageQuantizeRGBToIndexExecute<VTK_TT>(this, inData, outData));
692     default:
693       vtkErrorMacro(<< "Execute: This ScalarType is not handled");
694       return 1;
695   }
696 
697   return 1;
698 }
699 
700 // Change the output type and number of components
RequestInformation(vtkInformation * vtkNotUsed (request),vtkInformationVector ** vtkNotUsed (inputVector),vtkInformationVector * outputVector)701 int vtkImageQuantizeRGBToIndex::RequestInformation(vtkInformation* vtkNotUsed(request),
702   vtkInformationVector** vtkNotUsed(inputVector), vtkInformationVector* outputVector)
703 {
704   // get the info objects
705   vtkInformation* outInfo = outputVector->GetInformationObject(0);
706 
707   vtkDataObject::SetPointDataActiveScalarInfo(outInfo, VTK_UNSIGNED_SHORT, 1);
708   return 1;
709 }
710 
711 // Get ALL of the input.
RequestUpdateExtent(vtkInformation * vtkNotUsed (request),vtkInformationVector ** inputVector,vtkInformationVector * vtkNotUsed (outputVector))712 int vtkImageQuantizeRGBToIndex::RequestUpdateExtent(vtkInformation* vtkNotUsed(request),
713   vtkInformationVector** inputVector, vtkInformationVector* vtkNotUsed(outputVector))
714 {
715   // get the info objects
716   vtkInformation* inInfo = inputVector[0]->GetInformationObject(0);
717 
718   int inExt[6];
719   inInfo->Get(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(), inExt);
720   inInfo->Set(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT(), inExt, 6);
721 
722   return 1;
723 }
724 
PrintSelf(ostream & os,vtkIndent indent)725 void vtkImageQuantizeRGBToIndex::PrintSelf(ostream& os, vtkIndent indent)
726 {
727   this->Superclass::PrintSelf(os, indent);
728 
729   // Input Type is internal so we don't print it
730   // os << indent << "InputType: " << this->InputType << endl;
731 
732   os << indent << "Number Of Colors: " << this->NumberOfColors << endl;
733   os << indent << "Lookup Table: " << endl << *this->LookupTable;
734   os << indent << "Execute Time (in initialize stage): " << this->InitializeExecuteTime << endl;
735   os << indent << "Execute Time (in build tree stage): " << this->BuildTreeExecuteTime << endl;
736   os << indent << "Execute Time (in lookup index stage): " << this->LookupIndexExecuteTime << endl;
737 }
738