]> Creatis software - cpPlugins.git/blob - lib/cpExtensions/Visualization/ImageBlender.cxx
Glitch hunted down
[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->m_Colors.begin( );
29   for( ; i != this->m_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( ( const_cast< Self* >( this ) )->GetNumberOfInputConnections( 0 ) );
43 }
44
45 // -------------------------------------------------------------------------
46 const double& cpExtensions::Visualization::ImageBlender::
47 GetMaxWindow( ) const
48 {
49   return( this->m_MaxWindow );
50 }
51
52 // -------------------------------------------------------------------------
53 const double& cpExtensions::Visualization::ImageBlender::
54 GetMaxLevel( ) const
55 {
56   return( this->m_MaxLevel );
57 }
58
59 // -------------------------------------------------------------------------
60 const double& cpExtensions::Visualization::ImageBlender::
61 GetMinWindow( ) const
62 {
63   return( this->m_MinWindow );
64 }
65
66 // -------------------------------------------------------------------------
67 const double& cpExtensions::Visualization::ImageBlender::
68 GetMinLevel( ) const
69 {
70   return( this->m_MinLevel );
71 }
72
73 // -------------------------------------------------------------------------
74 const double& cpExtensions::Visualization::ImageBlender::
75 GetWindow( ) const
76 {
77   return( this->m_Window );
78 }
79
80 // -------------------------------------------------------------------------
81 const double& cpExtensions::Visualization::ImageBlender::
82 GetLevel( ) const
83 {
84   return( this->m_Level );
85 }
86
87 // -------------------------------------------------------------------------
88 void cpExtensions::Visualization::ImageBlender::
89 SetWindow( const double& w )
90 {
91   if( this->m_Window != w )
92   {
93     this->m_Window = w;
94     this->Modified( );
95
96   } // fi
97 }
98
99 // -------------------------------------------------------------------------
100 void cpExtensions::Visualization::ImageBlender::
101 SetLevel( const double& l )
102 {
103   if( this->m_Level != l )
104   {
105     this->m_Level = l;
106     this->Modified( );
107
108   } // fi
109 }
110
111 // -------------------------------------------------------------------------
112 void cpExtensions::Visualization::ImageBlender::
113 SetWindowLevel( const double& w, const double& l )
114 {
115   this->SetWindow( w );
116   this->SetLevel( l );
117 }
118
119 // -------------------------------------------------------------------------
120 void cpExtensions::Visualization::ImageBlender::
121 GetColor(
122   const unsigned int& i,
123   double& r,
124   double& g,
125   double& b
126   ) const
127 {
128   auto c = this->m_Colors.find( i );
129   if( c != this->m_Colors.end( ) )
130   {
131     r = c->second.R;
132     g = c->second.G;
133     b = c->second.B;
134   }
135   else
136   {
137     TColor c;
138     r = c.R;
139     g = c.G;
140     b = c.B;
141
142   } // fi
143 }
144
145 // -------------------------------------------------------------------------
146 void cpExtensions::Visualization::ImageBlender::
147 SetColor(
148   const unsigned int& i,
149   const double& r,
150   const double& g,
151   const double& b
152   )
153 {
154   this->m_Colors[ i ] = TColor( r, g, b );
155   this->Modified( );
156 }
157
158 // -------------------------------------------------------------------------
159 cpExtensions::Visualization::ImageBlender::
160 ImageBlender( )
161   : Superclass( ),
162     m_MaxWindow( double( 0 ) ),
163     m_MaxLevel( double( 0 ) ),
164     m_MinWindow( double( 0 ) ),
165     m_MinLevel( double( 0 ) ),
166     m_Window( double( 0 ) ),
167     m_Level( double( 0 ) )
168 {
169   this->SetNumberOfInputPorts( 1 );
170 }
171
172 // -------------------------------------------------------------------------
173 cpExtensions::Visualization::ImageBlender::
174 ~ImageBlender( )
175 {
176 }
177
178 // -------------------------------------------------------------------------
179 int cpExtensions::Visualization::ImageBlender::
180 RequestInformation(
181   vtkInformation* request,
182   vtkInformationVector** inputVector,
183   vtkInformationVector* outputVector
184   )
185 {
186   // Check number of inputs
187   int numInputs = this->GetNumberOfInputConnections( 0 );
188   if( numInputs == 0 )
189     return( 0 );
190
191   // Get input image
192   vtkInformation* inInfo = inputVector[ 0 ]->GetInformationObject( 0 );
193   if( inInfo == NULL )
194     return( 0 );
195   vtkImageData* inData = vtkImageData::SafeDownCast(
196     inInfo->Get( vtkDataObject::DATA_OBJECT( ) )
197     );
198   if( inData == NULL )
199     return( 0 );
200
201   // Configure buffer extent
202   inData->GetExtent( this->m_Extent );
203   this->m_Extent[ 1 ] -= this->m_Extent[ 0 ];
204   this->m_Extent[ 3 ] -= this->m_Extent[ 2 ];
205   this->m_Extent[ 5 ] -= this->m_Extent[ 4 ];
206   this->m_Extent[ 1 ] += 1;
207   this->m_Extent[ 3 ] += 1;
208   this->m_Extent[ 5 ] += 1;
209
210   // Configure window/level
211   double range[ 2 ];
212   inData->GetScalarRange( range );
213   this->m_MaxWindow = range[ 1 ] - range[ 0 ];
214   this->m_MinWindow = this->m_MaxWindow * double( 1e-2 );
215   this->m_MinLevel = range[ 0 ];
216   this->m_MaxLevel = range[ 1 ];
217   if( this->m_Window < this->m_MinWindow )
218     this->m_Window = this->m_MinWindow;
219   if( this->m_Window > this->m_MaxWindow )
220     this->m_Window = this->m_MaxWindow;
221   if( this->m_Level < this->m_MinLevel )
222     this->m_Level = this->m_MinLevel;
223   if( this->m_Level > this->m_MaxLevel )
224     this->m_Level = this->m_MaxLevel;
225   this->m_WLSlope = double( 1 ) / this->m_Window;
226   this->m_WLOffset = double( 0.5 ) - ( this->m_Level / this->m_Window );
227
228   // Configure output type
229   vtkDataObject::SetPointDataActiveScalarInfo(
230     outputVector->GetInformationObject( 0 ),
231     VTK_UNSIGNED_CHAR, 4
232     );
233   return( 1 );
234 }
235
236 // -------------------------------------------------------------------------
237 void cpExtensions::Visualization::ImageBlender::
238 ThreadedRequestData(
239   vtkInformation* request,
240   vtkInformationVector** inputVector,
241   vtkInformationVector* outputVector,
242   vtkImageData*** inData,
243   vtkImageData** outData,
244   int outExt[ 6 ], int id
245   )
246 {
247   if( inData[ 0 ][ 0 ] == NULL )
248   {
249     vtkErrorMacro( << "Input " << 0 << " must be specified." );
250     return;
251
252   } // fi
253
254   int numInputs = this->GetNumberOfInputConnections( 0 );
255   int numComp = inData[ 0 ][ 0 ]->GetNumberOfScalarComponents( );
256   if( numComp > 1 )
257   {
258     vtkErrorMacro(
259       "ThreadedRequestData: Input has " << numComp
260       << " components, but just 1 is supported"
261       );
262     return;
263
264   } // fi
265
266   for( int i = 1; i < numInputs; ++i )
267   {
268     int otherComp = inData[ 0 ][ i ]->GetNumberOfScalarComponents( );
269     if( otherComp != numComp )
270     {
271       if( id == 0 )
272         vtkErrorMacro(
273           "ThreadedRequestData: Input " << i
274           << " has " << otherComp
275           << " components, but input 0 has " << numComp
276           << " components"
277           );
278       return;
279
280     } // fi
281
282   } // rof
283
284   // Real update
285   this->_GenerateData( inData[ 0 ], numInputs, outData[ 0 ], outExt, id );
286 }
287
288 // -------------------------------------------------------------------------
289 int cpExtensions::Visualization::ImageBlender::
290 FillInputPortInformation( int i, vtkInformation* info )
291 {
292   info->Set( vtkAlgorithm::INPUT_IS_REPEATABLE( ), 1 );
293   return( this->Superclass::FillInputPortInformation( i, info ) );
294 }
295
296
297 // -------------------------------------------------------------------------
298 #define cpExtensions_ImageBlender_Type( O, V, T, B )                    \
299   O V = O( 0 );                                                         \
300   switch( T )                                                           \
301   {                                                                     \
302   case VTK_CHAR:                                                        \
303     V = O( *( reinterpret_cast< char* >( B ) ) );                       \
304     break;                                                              \
305   case VTK_SHORT:                                                       \
306     V = O( *( reinterpret_cast< short* >( B ) ) );                      \
307     break;                                                              \
308   case VTK_INT:                                                         \
309     V = O( *( reinterpret_cast< int* >( B ) ) );                        \
310     break;                                                              \
311   case VTK_LONG:                                                        \
312     V = O( *( reinterpret_cast< long* >( B ) ) );                       \
313     break;                                                              \
314   case VTK_UNSIGNED_CHAR:                                               \
315     V = O( *( reinterpret_cast< unsigned char* >( B ) ) );              \
316     break;                                                              \
317   case VTK_UNSIGNED_SHORT:                                              \
318     V = O( *( reinterpret_cast< unsigned short* >( B ) ) );             \
319     break;                                                              \
320   case VTK_UNSIGNED_INT:                                                \
321     V = O( *( reinterpret_cast< unsigned int* >( B ) ) );               \
322     break;                                                              \
323   case VTK_UNSIGNED_LONG:                                               \
324     V = O( *( reinterpret_cast< unsigned long* >( B ) ) );              \
325     break;                                                              \
326   case VTK_FLOAT:                                                       \
327     V = O( *( reinterpret_cast< float* >( B ) ) );                      \
328     break;                                                              \
329   case VTK_DOUBLE:                                                      \
330     V = O( *( reinterpret_cast< double* >( B ) ) );                     \
331     break;                                                              \
332   }
333
334 // -------------------------------------------------------------------------
335 void cpExtensions::Visualization::ImageBlender::
336 _GenerateData(
337   vtkImageData** inDatas,
338   int numInputs,
339   vtkImageData* outData,
340   int outExt[6],
341   int id
342   )
343 {
344   static const double _0 = double( 0 );
345   static const double _1 = double( 1 );
346   static const double _255 = double( 255 );
347
348   unsigned char* mBuffer =
349     reinterpret_cast< unsigned char* >( inDatas[ 0 ]->GetScalarPointer( ) );
350   unsigned char* oBuffer =
351     reinterpret_cast< unsigned char* >( outData->GetScalarPointer( ) );
352   int mType = inDatas[ 0 ]->GetScalarType( );
353   int mSize = inDatas[ 0 ]->GetScalarSize( );
354
355   double r, g, b, a;
356   int e13 = this->m_Extent[ 1 ] * this->m_Extent[ 3 ];
357   for( int k = outExt[ 4 ]; k <= outExt[ 5 ]; ++k )
358   {
359     int dk = ( k - this->m_Extent[ 4 ] ) * e13;
360     for( int j = outExt[ 2 ]; j <= outExt[ 3 ]; ++j )
361     {
362       int dj = ( ( j - this->m_Extent[ 2 ] ) * this->m_Extent[ 3 ] ) + dk;
363       for( int i = outExt[ 0 ]; i <= outExt[ 1 ]; ++i )
364       {
365         int di = ( i - this->m_Extent[ 0 ] ) + dj;
366
367         // Get main value
368         cpExtensions_ImageBlender_Type(
369           double, v, mType, mBuffer + ( di * mSize )
370           );
371         v *= this->m_WLSlope;
372         v += this->m_WLOffset;
373         if( v < _0 ) v = _0;
374         if( v > _1 ) v = _1;
375
376         // Prepare color
377         r = g = b = v;
378         a = _1;
379
380         // Blend colors
381         for( int i = 1; i < numInputs; ++i )
382         {
383           unsigned char* cBuffer =
384             reinterpret_cast< unsigned char* >(
385               inDatas[ i ]->GetScalarPointer( )
386               );
387           int cType = inDatas[ i ]->GetScalarType( );
388           int cSize = inDatas[ i ]->GetScalarSize( );
389           cpExtensions_ImageBlender_Type(
390             double, c, cType, cBuffer + ( di * cSize )
391             );
392           if( c > double( 0 ) )
393           {
394             TColor rgb = this->m_Colors[ i ];
395             r *= rgb.R * rgb.N;
396             g *= rgb.G * rgb.N;
397             b *= rgb.B * rgb.N;
398             a = _1;
399
400           } // fi
401
402         } // rof
403
404         // Update color
405         int di4 = di << 2;
406         oBuffer[ di4 + 0 ] = static_cast< unsigned char >( r * _255 );
407         oBuffer[ di4 + 1 ] = static_cast< unsigned char >( g * _255 );
408         oBuffer[ di4 + 2 ] = static_cast< unsigned char >( b * _255 );
409         oBuffer[ di4 + 3 ] = static_cast< unsigned char >( a * _255 );
410
411       } // rof
412
413     } // rof
414
415   } // rof
416 }
417
418 // eof - $RCSfile$