1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkImageRGBToHSI.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 "vtkImageRGBToHSI.h"
16 
17 #include "vtkMath.h"
18 #include "vtkImageData.h"
19 #include "vtkImageProgressIterator.h"
20 #include "vtkObjectFactory.h"
21 
22 #include <math.h>
23 
24 vtkStandardNewMacro(vtkImageRGBToHSI);
25 
26 //----------------------------------------------------------------------------
vtkImageRGBToHSI()27 vtkImageRGBToHSI::vtkImageRGBToHSI()
28 {
29   this->Maximum = 255.0;
30   this->SetNumberOfInputPorts(1);
31   this->SetNumberOfOutputPorts(1);
32 }
33 
34 //----------------------------------------------------------------------------
35 // This templated function executes the filter for any type of data.
36 template <class T>
vtkImageRGBToHSIExecute(vtkImageRGBToHSI * self,vtkImageData * inData,vtkImageData * outData,int outExt[6],int id,T *)37 void vtkImageRGBToHSIExecute(vtkImageRGBToHSI *self,
38                              vtkImageData *inData,
39                              vtkImageData *outData,
40                              int outExt[6], int id, T *)
41 {
42   vtkImageIterator<T> inIt(inData, outExt);
43   vtkImageProgressIterator<T> outIt(outData, outExt, self, id);
44   int idxC, maxC;
45   double R, G, B, H, S, I;
46   double max = self->GetMaximum();
47   double temp;
48 
49   // find the region to loop over
50   maxC = inData->GetNumberOfScalarComponents()-1;
51 
52   // Loop through output pixels
53   while (!outIt.IsAtEnd())
54     {
55     T* inSI = inIt.BeginSpan();
56     T* outSI = outIt.BeginSpan();
57     T* outSIEnd = outIt.EndSpan();
58     while (outSI != outSIEnd)
59       {
60       // Pixel operation
61       R = static_cast<double>(*inSI); inSI++;
62       G = static_cast<double>(*inSI); inSI++;
63       B = static_cast<double>(*inSI); inSI++;
64       // Saturation
65       temp = R;
66       if (G < temp)
67         {
68         temp = G;
69         }
70       if (B < temp)
71         {
72         temp = B;
73         }
74       double sumRGB = R+G+B;
75       if(sumRGB == 0.0)
76         {
77         S = 0.0;
78         }
79       else
80         {
81         S = max * (1.0 - (3.0 * temp / sumRGB));
82         }
83 
84       temp = static_cast<double>(R + G + B);
85       // Intensity is easy
86       I = temp / 3.0;
87 
88       // Hue
89       temp = sqrt((R-G)*(R-G) + (R-B)*(G-B));
90       if(temp != 0.0)
91         {
92         temp = acos((0.5 * ((R-G) + (R-B))) / temp);
93         }
94       if (G >= B)
95         {
96         H = max * (temp / (2.0 * vtkMath::Pi()));
97         }
98       else
99         {
100         H = max * (1.0 - (temp / (2.0 * vtkMath::Pi())));
101         }
102 
103       // assign output.
104       *outSI = static_cast<T>(H); outSI++;
105       *outSI = static_cast<T>(S); outSI++;
106       *outSI = static_cast<T>(I); outSI++;
107 
108       for (idxC = 3; idxC <= maxC; idxC++)
109         {
110         *outSI++ = *inSI++;
111         }
112       }
113     inIt.NextSpan();
114     outIt.NextSpan();
115     }
116 }
117 
118 //----------------------------------------------------------------------------
ThreadedExecute(vtkImageData * inData,vtkImageData * outData,int outExt[6],int id)119 void vtkImageRGBToHSI::ThreadedExecute (vtkImageData *inData,
120                                          vtkImageData *outData,
121                                          int outExt[6], int id)
122 {
123   vtkDebugMacro(<< "Execute: inData = " << inData
124   << ", outData = " << outData);
125 
126   // this filter expects that input is the same type as output.
127   if (inData->GetScalarType() != outData->GetScalarType())
128     {
129     vtkErrorMacro(<< "Execute: input ScalarType, " << inData->GetScalarType()
130     << ", must match out ScalarType " << outData->GetScalarType());
131     return;
132     }
133 
134   // need three components for input and output
135   if (inData->GetNumberOfScalarComponents() < 3)
136     {
137     vtkErrorMacro("Input has too few components");
138     return;
139     }
140   if (outData->GetNumberOfScalarComponents() < 3)
141     {
142     vtkErrorMacro("Output has too few components");
143     return;
144     }
145 
146   switch (inData->GetScalarType())
147     {
148     vtkTemplateMacro(
149       vtkImageRGBToHSIExecute( this, inData,
150                                outData, outExt, id,
151                                static_cast<VTK_TT *>(0)));
152     default:
153       vtkErrorMacro(<< "Execute: Unknown ScalarType");
154       return;
155     }
156 }
157 
PrintSelf(ostream & os,vtkIndent indent)158 void vtkImageRGBToHSI::PrintSelf(ostream& os, vtkIndent indent)
159 {
160   this->Superclass::PrintSelf(os,indent);
161 
162   os << indent << "Maximum: " << this->Maximum << "\n";
163 }
164 
165