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