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