]> Creatis software - cpPlugins.git/blob - lib/cpExtensions/Visualization/ImageBlender.cxx
...
[cpPlugins.git] / lib / cpExtensions / Visualization / ImageBlender.cxx
1 #include <cpExtensions/Visualization/ImageBlender.h>
2
3 #include <cstring>
4
5 #include <vtkDataObject.h>
6 #include <vtkImageData.h>
7 #include <vtkImageIterator.h>
8 #include <vtkImageProgressIterator.h>
9 #include <vtkInformation.h>
10 #include <vtkInformationVector.h>
11
12 // -------------------------------------------------------------------------
13 cpExtensions::Visualization::ImageBlender::
14 Self* cpExtensions::Visualization::ImageBlender::
15 New( )
16 {
17   return( new Self( ) );
18 }
19
20 // -------------------------------------------------------------------------
21 void cpExtensions::Visualization::ImageBlender::
22 PrintSelf( std::ostream& os, vtkIndent indent )
23 {
24   this->Superclass::PrintSelf( os, indent );
25
26   // Objects
27   os << indent << "Colors: " << std::endl;
28   auto i = this->Colors.begin( );
29   for( ; i != this->Colors.end( ); ++i )
30     os
31       << indent << indent << i->first << " : ["
32       << i->second.R << ", "
33       << i->second.G << ", "
34       << i->second.B << "]"
35       << std::endl;
36 }
37
38 // -------------------------------------------------------------------------
39 unsigned int cpExtensions::Visualization::ImageBlender::
40 GetNumberOfImages( ) const
41 {
42   return(
43     ( const_cast< Self* >( this ) )->GetNumberOfInputConnections( 0 )
44     );
45 }
46
47 // -------------------------------------------------------------------------
48 void cpExtensions::Visualization::ImageBlender::
49 SetWindowLevel( const double& w, const double& l )
50 {
51   this->SetWindow( w );
52   this->SetLevel( l );
53 }
54
55 // -------------------------------------------------------------------------
56 void cpExtensions::Visualization::ImageBlender::
57 GetColor(
58   const unsigned int& i,
59   double& r,
60   double& g,
61   double& b
62   ) const
63 {
64   auto c = this->Colors.find( i );
65   if( c != this->Colors.end( ) )
66   {
67     r = c->second.R;
68     g = c->second.G;
69     b = c->second.B;
70   }
71   else
72   {
73     TColor c;
74     r = c.R;
75     g = c.G;
76     b = c.B;
77
78   } // fi
79 }
80
81 // -------------------------------------------------------------------------
82 void cpExtensions::Visualization::ImageBlender::
83 SetColor(
84   const unsigned int& i,
85   const double& r,
86   const double& g,
87   const double& b
88   )
89 {
90   this->Colors[ i ] = TColor( r, g, b );
91   this->Modified( );
92 }
93
94 // -------------------------------------------------------------------------
95 cpExtensions::Visualization::ImageBlender::
96 ImageBlender( )
97   : Superclass( ),
98     MaxWindow( double( 1 ) ),
99     MaxLevel( double( 1 ) ),
100     MinWindow( double( 0 ) ),
101     MinLevel( double( 0 ) ),
102     Window( double( 1 ) ),
103     Level( double( 0.5 ) )
104 {
105   this->SetNumberOfInputPorts( 1 );
106 }
107
108 // -------------------------------------------------------------------------
109 cpExtensions::Visualization::ImageBlender::
110 ~ImageBlender( )
111 {
112 }
113
114 // -------------------------------------------------------------------------
115 int cpExtensions::Visualization::ImageBlender::
116 RequestInformation(
117   vtkInformation* request,
118   vtkInformationVector** inputVector,
119   vtkInformationVector* outputVector
120   )
121 {
122   // Check number of inputs
123   int numInputs = this->GetNumberOfInputConnections( 0 );
124   if( numInputs == 0 )
125     return( 0 );
126
127   // Get input image
128   vtkInformation* inInfo = inputVector[ 0 ]->GetInformationObject( 0 );
129   if( inInfo == NULL )
130     return( 0 );
131   vtkImageData* inData = vtkImageData::SafeDownCast(
132     inInfo->Get( vtkDataObject::DATA_OBJECT( ) )
133     );
134   if( inData == NULL )
135     return( 0 );
136
137   // Configure buffer extent
138   inData->GetExtent( this->m_Extent );
139   this->m_Extent[ 1 ] -= this->m_Extent[ 0 ];
140   this->m_Extent[ 3 ] -= this->m_Extent[ 2 ];
141   this->m_Extent[ 5 ] -= this->m_Extent[ 4 ];
142   this->m_Extent[ 1 ] += 1;
143   this->m_Extent[ 3 ] += 1;
144   this->m_Extent[ 5 ] += 1;
145
146   // Configure window/level
147   this->m_WLSlope = double( 1 ) / this->Window;
148   this->m_WLOffset = double( 0.5 ) - ( this->Level / this->Window );
149
150   // Configure output type
151   vtkDataObject::SetPointDataActiveScalarInfo(
152     outputVector->GetInformationObject( 0 ),
153     VTK_UNSIGNED_CHAR, 3
154     );
155   return( 1 );
156 }
157
158 // -------------------------------------------------------------------------
159 void cpExtensions::Visualization::ImageBlender::
160 ThreadedRequestData(
161   vtkInformation* request,
162   vtkInformationVector** inputVector,
163   vtkInformationVector* outputVector,
164   vtkImageData*** inData,
165   vtkImageData** outData,
166   int outExt[ 6 ], int id
167   )
168 {
169   if( inData[ 0 ][ 0 ] == NULL )
170   {
171     vtkErrorMacro( << "Input " << 0 << " must be specified." );
172     return;
173
174   } // fi
175
176   int numInputs = this->GetNumberOfInputConnections( 0 );
177   int numComp = inData[ 0 ][ 0 ]->GetNumberOfScalarComponents( );
178   if( numComp > 1 )
179   {
180     vtkErrorMacro(
181       "ThreadedRequestData: Input has " << numComp
182       << " components, but just 1 is supported"
183       );
184     return;
185
186   } // fi
187
188   for( int i = 1; i < numInputs; ++i )
189   {
190     int otherComp = inData[ 0 ][ i ]->GetNumberOfScalarComponents( );
191     if( otherComp != numComp )
192     {
193       if( id == 0 )
194         vtkErrorMacro(
195           "ThreadedRequestData: Input " << i
196           << " has " << otherComp
197           << " components, but input 0 has " << numComp
198           << " components"
199           );
200       return;
201
202     } // fi
203
204   } // rof
205
206   // Real update
207   this->_GenerateData( inData[ 0 ], numInputs, outData[ 0 ], outExt, id );
208 }
209
210 // -------------------------------------------------------------------------
211 int cpExtensions::Visualization::ImageBlender::
212 FillInputPortInformation( int i, vtkInformation* info )
213 {
214   info->Set( vtkAlgorithm::INPUT_IS_REPEATABLE( ), 1 );
215   return( this->Superclass::FillInputPortInformation( i, info ) );
216 }
217
218
219 // -------------------------------------------------------------------------
220 #define cpExtensions_ImageBlender_Type( O, V, T, B )                    \
221   O V = O( 0 );                                                         \
222   switch( T )                                                           \
223   {                                                                     \
224   case VTK_CHAR:                                                        \
225     V = O( *( reinterpret_cast< char* >( B ) ) );                       \
226     break;                                                              \
227   case VTK_SHORT:                                                       \
228     V = O( *( reinterpret_cast< short* >( B ) ) );                      \
229     break;                                                              \
230   case VTK_INT:                                                         \
231     V = O( *( reinterpret_cast< int* >( B ) ) );                        \
232     break;                                                              \
233   case VTK_LONG:                                                        \
234     V = O( *( reinterpret_cast< long* >( B ) ) );                       \
235     break;                                                              \
236   case VTK_UNSIGNED_CHAR:                                               \
237     V = O( *( reinterpret_cast< unsigned char* >( B ) ) );              \
238     break;                                                              \
239   case VTK_UNSIGNED_SHORT:                                              \
240     V = O( *( reinterpret_cast< unsigned short* >( B ) ) );             \
241     break;                                                              \
242   case VTK_UNSIGNED_INT:                                                \
243     V = O( *( reinterpret_cast< unsigned int* >( B ) ) );               \
244     break;                                                              \
245   case VTK_UNSIGNED_LONG:                                               \
246     V = O( *( reinterpret_cast< unsigned long* >( B ) ) );              \
247     break;                                                              \
248   case VTK_FLOAT:                                                       \
249     V = O( *( reinterpret_cast< float* >( B ) ) );                      \
250     break;                                                              \
251   case VTK_DOUBLE:                                                      \
252     V = O( *( reinterpret_cast< double* >( B ) ) );                     \
253     break;                                                              \
254   }
255
256 // -------------------------------------------------------------------------
257 void cpExtensions::Visualization::ImageBlender::
258 _GenerateData(
259   vtkImageData** inDatas,
260   int numInputs,
261   vtkImageData* outData,
262   int outExt[ 6 ],
263   int id
264   )
265 {
266   static const double _0 = double( 0 );
267   static const double _1 = double( 1 );
268   static const double _255 = double( 255 );
269
270   unsigned char* mBuffer =
271     reinterpret_cast< unsigned char* >( inDatas[ 0 ]->GetScalarPointer( ) );
272   unsigned char* oBuffer =
273     reinterpret_cast< unsigned char* >( outData->GetScalarPointer( ) );
274   int mType = inDatas[ 0 ]->GetScalarType( );
275   int mSize = inDatas[ 0 ]->GetScalarSize( );
276
277   double r, g, b;
278   int e13 = this->m_Extent[ 1 ] * this->m_Extent[ 3 ];
279   for( int k = outExt[ 4 ]; k <= outExt[ 5 ]; ++k )
280   {
281     int dk = ( k - this->m_Extent[ 4 ] ) * e13;
282     for( int j = outExt[ 2 ]; j <= outExt[ 3 ]; ++j )
283     {
284       int dj = ( ( j - this->m_Extent[ 2 ] ) * this->m_Extent[ 3 ] ) + dk;
285       for( int i = outExt[ 0 ]; i <= outExt[ 1 ]; ++i )
286       {
287         int di = ( i - this->m_Extent[ 0 ] ) + dj;
288
289         // Get main value
290         cpExtensions_ImageBlender_Type(
291           double, v, mType, mBuffer + ( di * mSize )
292           );
293         v *= this->m_WLSlope;
294         v += this->m_WLOffset;
295         if( v < _0 ) v = _0;
296         if( v > _1 ) v = _1;
297
298         // Prepare color
299         r = g = b = v;
300
301         // Blend colors
302         for( int i = 1; i < numInputs; ++i )
303         {
304           unsigned char* cBuffer =
305             reinterpret_cast< unsigned char* >(
306               inDatas[ i ]->GetScalarPointer( )
307               );
308           int cType = inDatas[ i ]->GetScalarType( );
309           int cSize = inDatas[ i ]->GetScalarSize( );
310           cpExtensions_ImageBlender_Type(
311             double, c, cType, cBuffer + ( di * cSize )
312             );
313           if( c > double( 0 ) )
314           {
315             TColor rgb = this->Colors[ i ];
316             r *= rgb.R * rgb.N;
317             g *= rgb.G * rgb.N;
318             b *= rgb.B * rgb.N;
319
320           } // fi
321
322         } // rof
323
324         // Update color
325         int di3 = di * 3;
326         oBuffer[ di3 + 0 ] = static_cast< unsigned char >( r * _255 );
327         oBuffer[ di3 + 1 ] = static_cast< unsigned char >( g * _255 );
328         oBuffer[ di3 + 2 ] = static_cast< unsigned char >( b * _255 );
329
330       } // rof
331
332     } // rof
333
334   } // rof
335 }
336
337 // eof - $RCSfile$