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