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